]> git.sesse.net Git - casparcg/blob - common/os/linux/stack_trace.cpp
c2369e2c86f239882e868f5a6db03706ab2a97b4
[casparcg] / common / os / linux / stack_trace.cpp
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Helge Norberg, helge.norberg@svt.se
20 */
21
22 #include "../stack_trace.h"
23
24 #include <execinfo.h>
25 #include <cstdio>
26 #include <array>
27 #include <memory>
28 #include <sstream>
29 #include <cxxabi.h>
30
31 namespace caspar {
32
33 std::string demangle(const std::string& mangled)
34 {
35         auto start_of_name = mangled.find_first_of('(');
36
37         if (start_of_name == std::string::npos)
38         return "";
39
40         auto start_of_offset = mangled.find_first_of('+', start_of_name);
41
42         if (start_of_offset == std::string::npos)
43         return "";
44
45         auto end_of_name = mangled.find_first_of(')', start_of_offset);
46
47         if (end_of_name == std::string::npos)
48         return "";
49
50         auto file = mangled.substr(0, start_of_name);
51         auto mangled_symbol_name = mangled.substr(start_of_name + 1, start_of_offset - start_of_name - 1);
52         auto offset = mangled.substr(start_of_offset + 1, end_of_name - start_of_offset - 1);
53
54         int status;
55         auto demangled = abi::__cxa_demangle(mangled_symbol_name.c_str(), nullptr, nullptr, &status);
56         bool demangled_success = status == 0;
57
58         if (demangled_success)
59         {
60                 auto demangled_guard = std::shared_ptr<char>(demangled, free);
61
62                 return file + " : " + demangled + " + " + offset;
63         }
64         else
65         {
66                 return "";
67         }
68 }
69
70 std::wstring get_call_stack()
71 {
72         std::array<void*, 100> stackframes;
73         auto size = backtrace(stackframes.data(), stackframes.size());
74         auto strings = backtrace_symbols(stackframes.data(), size);
75
76         if (strings == nullptr)
77                 return L"Out of memory while generating stack trace";
78
79         try
80         {
81                 auto entries = std::shared_ptr<char*>(strings, free);
82                 std::wostringstream stream;
83                 stream << std::endl;
84
85                 for (int i = 0; i != size; ++i)
86                 {
87                         auto demangled = demangle(strings[i]);
88
89                         if (!demangled.empty() && demangled.find("caspar::get_call_stack") == std::string::npos)
90                                 stream << L"   " << demangled.c_str() << std::endl;
91                 }
92
93                 return stream.str();
94         }
95         catch (const std::bad_alloc&)
96         {
97                 return L"Out of memory while generating stack trace";
98         }
99         catch (...)
100         {
101                 return L"Error while generating stack trace";
102         }
103 }
104
105 }