1 // Copyright (c) 2017-2021, Lawrence Livermore National Security, LLC and
2 // other Axom Project Developers. See the top-level LICENSE file for details.
3 //
4 // SPDX-License-Identifier: (BSD-3-Clause)
5
6 #include <cstdlib> // for free
7 #include <sstream> // for std::ostringstream
8
9 #ifdef WIN32
10 #define NOMINMAX
11 #include <Windows.h>
12 #include <WinBase.h>
13 #include <DbgHelp.h>
14 #else
15 #include <execinfo.h> // for backtrace()
16 #include <ciso646>
17 #if !defined(_LIBCPP_VERSION)
18 #include <cxxabi.h> // for abi::__cxa_demangle
19 #endif
20 #endif
21
22 constexpr int MAX_FRAMES = 25;
23
24 namespace axom
25 {
26 namespace slic
27 {
28 namespace internal
29 {
30 #ifdef WIN32
31
stacktrace()32 std::string stacktrace()
33 {
34 void* stack[MAX_FRAMES];
35 std::ostringstream oss;
36
37 unsigned short frames;
38 SYMBOL_INFO* symbol;
39 HANDLE process;
40
41 process = GetCurrentProcess();
42
43 SymInitialize(process, NULL, TRUE);
44
45 frames = CaptureStackBackTrace(0, MAX_FRAMES, stack, NULL);
46 symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
47 symbol->MaxNameLen = 255;
48 symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
49
50 oss << "\n** StackTrace of " << frames << " frames **\n";
51 for(int i = 0; i < frames; i++)
52 {
53 char outString[512];
54 SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
55
56 sprintf_s(outString,
57 "%i: %s - 0x%0X",
58 frames - i - 1,
59 symbol->Name,
60 symbol->Address);
61 oss << outString << std::endl;
62 }
63
64 free(symbol);
65 oss << "=====\n\n";
66
67 return (oss.str());
68 }
69
70 #else /* #ifdef WIN32 */
71
72 //------------------------------------------------------------------------------
73 std::string demangle(char* backtraceString, int frame)
74 {
75 char* mangledName = nullptr;
76 char* functionOffset = nullptr;
77 char* returnOffset = nullptr;
78
79 #ifdef __APPLE__
80 /* On apple machines the mangled function name always starts at the 58th
81 * character */
82 constexpr int APPLE_OFFSET = 58;
83 mangledName = backtraceString + APPLE_OFFSET;
84 for(char* p = backtraceString; *p; ++p)
85 {
86 if(*p == '+')
87 {
88 functionOffset = p;
89 }
90 returnOffset = p;
91 }
92 #else
93 for(char* p = backtraceString; *p; ++p)
94 {
95 if(*p == '(')
96 {
97 mangledName = p;
98 }
99 else if(*p == '+')
100 {
101 functionOffset = p;
102 }
103 else if(*p == ')')
104 {
105 returnOffset = p;
106 break;
107 }
108 }
109 #endif
110
111 std::ostringstream oss;
112
113 // if the line could be processed, attempt to demangle the symbol
114 if(mangledName && functionOffset && returnOffset && mangledName < functionOffset)
115 {
116 *mangledName = 0;
117 mangledName++;
118 #ifdef __APPLE__
119 *(functionOffset - 1) = 0;
120 #endif
121 *functionOffset = 0;
122 ++functionOffset;
123 *returnOffset = 0;
124 ++returnOffset;
125
126 int status = false;
127 #if !defined(_LIBCPP_VERSION)
128 char* realName = abi::__cxa_demangle(mangledName, nullptr, nullptr, &status);
129 #else
130 char* realName = mangledName;
131 #endif
132
133 // if demangling is successful, output the demangled function name
134 if(status == 0)
135 {
136 oss << "Frame " << frame << ": " << realName << std::endl;
137 }
138 // otherwise, output the mangled function name
139 else
140 {
141 oss << "Frame " << frame << ": " << mangledName << std::endl;
142 }
143
144 #if !defined(_LIBCPP_VERSION)
145 free(realName);
146 #endif
147 }
148 // otherwise, print the whole line
149 else
150 {
151 oss << "Frame " << frame << ": " << backtraceString << std::endl;
152 }
153
154 return (oss.str());
155 }
156
157 std::string stacktrace()
158 {
159 void* array[MAX_FRAMES];
160
161 const int size = backtrace(array, MAX_FRAMES);
162 char** strings = backtrace_symbols(array, size);
163
164 // skip first stack frame (points here)
165 std::ostringstream oss;
166 oss << "\n** StackTrace of " << size - 1 << " frames **\n";
167 for(int i = 1; i < size && strings != nullptr; ++i)
168 {
169 oss << internal::demangle(strings[i], i);
170 }
171
172 oss << "=====\n\n";
173
174 free(strings);
175
176 return (oss.str());
177 }
178
179 #endif /* #ifdef WIN32 */
180
181 } /* namespace internal */
182
183 } /* namespace slic */
184
185 } /* namespace axom */
186