Line data Source code
1 :
2 : /* Copyright (c) 2007-2015, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : *
5 : * This library is free software; you can redistribute it and/or modify it under
6 : * the terms of the GNU Lesser General Public License version 2.1 as published
7 : * by the Free Software Foundation.
8 : *
9 : * This library is distributed in the hope that it will be useful, but WITHOUT
10 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 : * details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public License
15 : * along with this library; if not, write to the Free Software Foundation, Inc.,
16 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 : */
18 :
19 : #include "debug.h"
20 :
21 : #include "atomic.h"
22 : #include "os.h" // must come before atomic.h, ordering issue
23 : #include "sleep.h"
24 : #include "thread.h"
25 :
26 : #include <errno.h>
27 :
28 : #define LB_BACKTRACE_DEPTH 256
29 : #ifdef _WIN32
30 : #include "scopedMutex.h"
31 : #define LB_SYMBOL_LENGTH 256
32 : #include <dbghelp.h>
33 : #pragma comment(lib, "DbgHelp.lib")
34 : #else
35 : #include <cxxabi.h>
36 : #include <execinfo.h>
37 : #include <stdlib.h>
38 : #include <string.h>
39 : #endif
40 :
41 : namespace lunchbox
42 : {
43 0 : void abort(const bool dumpThreads)
44 : {
45 0 : LBERROR << " in: " << backtrace << "\n";
46 0 : if (dumpThreads)
47 : {
48 0 : LBERROR << "\nThreads:" << std::endl;
49 0 : Thread::_dumpAll();
50 0 : sleep(100); // threads need a bit to print
51 : }
52 : else
53 0 : LBERROR << std::endl;
54 :
55 : // if LB_ABORT_WAIT is set, spin forever to allow identifying and debugging
56 : // crashed nodes.
57 0 : if (getenv("LB_ABORT_WAIT"))
58 0 : while (true)
59 : ;
60 :
61 0 : ::abort();
62 : }
63 :
64 36575284 : void checkHeap()
65 : {
66 : #ifdef _MSC_VER
67 : static a_int32_t count(0);
68 : if ((++count % 10000) == 0 && _heapchk() != _HEAPOK)
69 : {
70 : LBERROR << disableFlush << "Abort: heap corruption detected"
71 : << std::endl
72 : << " Set breakpoint in " << __FILE__ << ':' << __LINE__ + 1
73 : << " to debug" << std::endl
74 : << enableFlush;
75 : }
76 : #else
77 : #endif
78 36575284 : }
79 :
80 : namespace
81 : {
82 1 : static void backtrace_(std::ostream& os, const size_t skipFrames)
83 : {
84 : #ifdef _WIN32
85 : // Sym* functions from DbgHelp are not thread-safe...
86 : static Lock lock;
87 : ScopedMutex<> mutex(lock);
88 :
89 : typedef USHORT(WINAPI * CaptureStackBackTraceType)(ULONG, ULONG, PVOID*,
90 : PULONG);
91 : CaptureStackBackTraceType backtraceFunc =
92 : (CaptureStackBackTraceType)GetProcAddress(LoadLibrary("kernel32.dll"),
93 : "RtlCaptureStackBackTrace");
94 : if (!backtraceFunc)
95 : return;
96 :
97 : SymSetOptions(SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
98 : HANDLE hProcess = GetCurrentProcess();
99 : if (!SymInitialize(hProcess, 0, TRUE))
100 : return;
101 :
102 : void* stack[LB_BACKTRACE_DEPTH];
103 : const size_t frames = (backtraceFunc)(0, LB_BACKTRACE_DEPTH, stack, 0);
104 :
105 : SYMBOL_INFO* symbol = (SYMBOL_INFO*)
106 : calloc(sizeof(SYMBOL_INFO) + (LB_SYMBOL_LENGTH + -1) * sizeof(char), 1);
107 : symbol->MaxNameLen = LB_SYMBOL_LENGTH;
108 : symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
109 :
110 : for (size_t i = skipFrames; i < frames; ++i)
111 : {
112 : os << "\n " << frames - i - 1 << ": ";
113 : if (!SymFromAddr(hProcess, (DWORD64)stack[i], 0, symbol))
114 : os << "Unknown symbol";
115 : else
116 : {
117 : os << symbol->Name << " - ";
118 : IMAGEHLP_LINE64 line = {sizeof(IMAGEHLP_LINE64)};
119 : DWORD displ;
120 : if (!SymGetLineFromAddr64(hProcess, (DWORD64)stack[i], &displ,
121 : &line))
122 : os << std::hex << "0x" << symbol->Address << std::dec;
123 : else
124 : os << line.FileName << ":" << line.LineNumber;
125 : }
126 : }
127 : os << std::endl;
128 : free(symbol);
129 : SymCleanup(hProcess);
130 : #else
131 : void* callstack[LB_BACKTRACE_DEPTH];
132 1 : const int frames = ::backtrace(callstack, LB_BACKTRACE_DEPTH);
133 1 : char** names = ::backtrace_symbols(callstack, frames);
134 5 : for (int i = skipFrames + 1; i < frames; ++i)
135 : {
136 8 : std::string name = names[i];
137 : #ifdef __linux__
138 4 : const size_t symbolPos = name.find("(_");
139 : #else
140 : const size_t symbolPos = name.find(" _");
141 : #endif
142 4 : if (symbolPos != std::string::npos)
143 2 : name = name.substr(symbolPos + 1, name.length());
144 :
145 : #ifdef __linux__
146 4 : const size_t spacePos = name.find('+');
147 : #else
148 : const size_t spacePos = name.find(' ');
149 : #endif
150 4 : if (spacePos != std::string::npos)
151 3 : name = name.substr(0, spacePos);
152 :
153 : int status;
154 4 : char* demangled = abi::__cxa_demangle(name.c_str(), 0, 0, &status);
155 :
156 4 : os << "\n " << frames - i - 1 << ": ";
157 4 : if (symbolPos == std::string::npos || spacePos == std::string::npos)
158 2 : os << names[i];
159 : else
160 : {
161 2 : if (demangled)
162 : {
163 1 : os << demangled;
164 1 : free(demangled);
165 : }
166 : else
167 1 : os << name;
168 : }
169 : }
170 1 : os << "\n";
171 1 : ::free(names);
172 : #endif
173 1 : }
174 : }
175 :
176 1 : std::string backtrace(const size_t skipFrames)
177 : {
178 2 : std::ostringstream os;
179 1 : backtrace_(os, skipFrames + 1 /*cut self*/);
180 2 : return os.str();
181 : }
182 :
183 0 : std::ostream& backtrace(std::ostream& os)
184 : {
185 0 : backtrace_(os, 1 /*cut self*/);
186 0 : return os;
187 : }
188 :
189 1665 : std::string demangleTypeID(const char* mangled)
190 : {
191 : #ifdef _WIN32
192 : return std::string(mangled);
193 : #else
194 : int status;
195 1665 : char* name = abi::__cxa_demangle(mangled, 0, 0, &status);
196 1665 : if (!name || status != 0)
197 : {
198 0 : free(name);
199 0 : return mangled;
200 : }
201 :
202 3330 : const std::string result = name;
203 1665 : free(name);
204 1665 : return result;
205 : #endif
206 : }
207 :
208 3 : std::ostream& sysError(std::ostream& os)
209 : {
210 : #ifdef _WIN32
211 : const DWORD error = GetLastError();
212 : char text[512] = "";
213 : FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, error, 0, text, 511, 0);
214 : const size_t length = strlen(text);
215 : if (length > 2 && text[length - 2] == '\r')
216 : text[length - 2] = '\0';
217 :
218 : return os << text << " (" << error << ")";
219 : #else
220 3 : return os << strerror(errno) << " (" << errno << ")";
221 : #endif
222 : }
223 :
224 0 : std::string sysError()
225 : {
226 0 : std::ostringstream os;
227 0 : os << sysError;
228 0 : return os.str();
229 : }
230 75 : }
|