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 : #include <mutex>
28 :
29 : #define LB_BACKTRACE_DEPTH 256
30 : #ifdef _WIN32
31 : #include "scopedMutex.h"
32 : #define LB_SYMBOL_LENGTH 256
33 : #include <dbghelp.h>
34 : #pragma comment(lib, "DbgHelp.lib")
35 : #else
36 : #include <cxxabi.h>
37 : #include <execinfo.h>
38 : #include <stdlib.h>
39 : #include <string.h>
40 : #endif
41 :
42 : namespace lunchbox
43 : {
44 0 : void abort(const bool dumpThreads)
45 : {
46 0 : LBERROR << " in: " << backtrace << "\n";
47 0 : if (dumpThreads)
48 : {
49 0 : LBERROR << "\nThreads:" << std::endl;
50 0 : Thread::_dumpAll();
51 0 : sleep(100); // threads need a bit to print
52 : }
53 : else
54 0 : LBERROR << std::endl;
55 :
56 : // if LB_ABORT_WAIT is set, spin forever to allow identifying and debugging
57 : // crashed nodes.
58 0 : if (getenv("LB_ABORT_WAIT"))
59 0 : while (true)
60 : ;
61 :
62 0 : ::abort();
63 : }
64 :
65 36917224 : void checkHeap()
66 : {
67 : #ifdef _MSC_VER
68 : static a_int32_t count(0);
69 : if ((++count % 10000) == 0 && _heapchk() != _HEAPOK)
70 : {
71 : LBERROR << disableFlush << "Abort: heap corruption detected"
72 : << std::endl
73 : << " Set breakpoint in " << __FILE__ << ':' << __LINE__ + 1
74 : << " to debug" << std::endl
75 : << enableFlush;
76 : }
77 : #else
78 : #endif
79 36917224 : }
80 :
81 : namespace
82 : {
83 1 : static void backtrace_(std::ostream& os, const size_t skipFrames)
84 : {
85 : #ifdef _WIN32
86 : // Sym* functions from DbgHelp are not thread-safe...
87 : static std::mutex lock;
88 : ScopedWrite scopedWrite(lock);
89 :
90 : typedef USHORT(WINAPI * CaptureStackBackTraceType)(ULONG, ULONG, PVOID*,
91 : PULONG);
92 : CaptureStackBackTraceType backtraceFunc =
93 : (CaptureStackBackTraceType)GetProcAddress(LoadLibrary("kernel32.dll"),
94 : "RtlCaptureStackBackTrace");
95 : if (!backtraceFunc)
96 : return;
97 :
98 : SymSetOptions(SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
99 : HANDLE hProcess = GetCurrentProcess();
100 : if (!SymInitialize(hProcess, 0, TRUE))
101 : return;
102 :
103 : void* stack[LB_BACKTRACE_DEPTH];
104 : const size_t frames = (backtraceFunc)(0, LB_BACKTRACE_DEPTH, stack, 0);
105 :
106 : SYMBOL_INFO* symbol = (SYMBOL_INFO*)
107 : calloc(sizeof(SYMBOL_INFO) + (LB_SYMBOL_LENGTH + -1) * sizeof(char), 1);
108 : symbol->MaxNameLen = LB_SYMBOL_LENGTH;
109 : symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
110 :
111 : for (size_t i = skipFrames; i < frames; ++i)
112 : {
113 : os << "\n " << frames - i - 1 << ": ";
114 : if (!SymFromAddr(hProcess, (DWORD64)stack[i], 0, symbol))
115 : os << "Unknown symbol";
116 : else
117 : {
118 : os << symbol->Name << " - ";
119 : IMAGEHLP_LINE64 line = {sizeof(IMAGEHLP_LINE64)};
120 : DWORD displ;
121 : if (!SymGetLineFromAddr64(hProcess, (DWORD64)stack[i], &displ,
122 : &line))
123 : os << std::hex << "0x" << symbol->Address << std::dec;
124 : else
125 : os << line.FileName << ":" << line.LineNumber;
126 : }
127 : }
128 : os << std::endl;
129 : free(symbol);
130 : SymCleanup(hProcess);
131 : #else
132 : void* callstack[LB_BACKTRACE_DEPTH];
133 1 : const int frames = ::backtrace(callstack, LB_BACKTRACE_DEPTH);
134 1 : char** names = ::backtrace_symbols(callstack, frames);
135 5 : for (int i = skipFrames + 1; i < frames; ++i)
136 : {
137 8 : std::string name = names[i];
138 : #ifdef __linux__
139 4 : const size_t symbolPos = name.find("(_");
140 : #else
141 : const size_t symbolPos = name.find(" _");
142 : #endif
143 4 : if (symbolPos != std::string::npos)
144 2 : name = name.substr(symbolPos + 1, name.length());
145 :
146 : #ifdef __linux__
147 4 : const size_t spacePos = name.find('+');
148 : #else
149 : const size_t spacePos = name.find(' ');
150 : #endif
151 4 : if (spacePos != std::string::npos)
152 3 : name = name.substr(0, spacePos);
153 :
154 : int status;
155 4 : char* demangled = abi::__cxa_demangle(name.c_str(), 0, 0, &status);
156 :
157 4 : os << "\n " << frames - i - 1 << ": ";
158 4 : if (symbolPos == std::string::npos || spacePos == std::string::npos)
159 2 : os << names[i];
160 : else
161 : {
162 2 : if (demangled)
163 : {
164 1 : os << demangled;
165 1 : free(demangled);
166 : }
167 : else
168 1 : os << name;
169 : }
170 : }
171 1 : os << "\n";
172 1 : ::free(names);
173 : #endif
174 1 : }
175 : }
176 :
177 1 : std::string backtrace(const size_t skipFrames)
178 : {
179 2 : std::ostringstream os;
180 1 : backtrace_(os, skipFrames + 1 /*cut self*/);
181 2 : return os.str();
182 : }
183 :
184 0 : std::ostream& backtrace(std::ostream& os)
185 : {
186 0 : backtrace_(os, 1 /*cut self*/);
187 0 : return os;
188 : }
189 :
190 1665 : std::string demangleTypeID(const char* mangled)
191 : {
192 : #ifdef _WIN32
193 : return std::string(mangled);
194 : #else
195 : int status;
196 1665 : char* name = abi::__cxa_demangle(mangled, 0, 0, &status);
197 1665 : if (!name || status != 0)
198 : {
199 0 : free(name);
200 0 : return mangled;
201 : }
202 :
203 3330 : const std::string result = name;
204 1665 : free(name);
205 1665 : return result;
206 : #endif
207 : }
208 :
209 3 : std::ostream& sysError(std::ostream& os)
210 : {
211 : #ifdef _WIN32
212 : const DWORD error = GetLastError();
213 : char text[512] = "";
214 : FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, error, 0, text, 511, 0);
215 : const size_t length = strlen(text);
216 : if (length > 2 && text[length - 2] == '\r')
217 : text[length - 2] = '\0';
218 :
219 : return os << text << " (" << error << ")";
220 : #else
221 3 : return os << strerror(errno) << " (" << errno << ")";
222 : #endif
223 : }
224 :
225 0 : std::string sysError()
226 : {
227 0 : std::ostringstream os;
228 0 : os << sysError;
229 0 : return os.str();
230 : }
231 75 : }
|