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 "os.h" // must come before atomic.h, ordering issue
22 : #include "atomic.h"
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 :
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 0 : ::abort();
62 : }
63 :
64 37858218 : 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"<< std::endl
71 : << " Set breakpoint in " << __FILE__ << ':' << __LINE__ + 1
72 : << " to debug" << std::endl << enableFlush;
73 : }
74 : #else
75 : #endif
76 37858218 : }
77 :
78 : namespace
79 : {
80 1 : static void backtrace_( std::ostream& os, const size_t skipFrames )
81 : {
82 : #ifdef _WIN32
83 : // Sym* functions from DbgHelp are not thread-safe...
84 : static Lock lock;
85 : ScopedMutex<> mutex( lock );
86 :
87 : typedef USHORT (WINAPI *CaptureStackBackTraceType)( ULONG, ULONG,
88 : PVOID*,
89 : PULONG );
90 : CaptureStackBackTraceType backtraceFunc = (CaptureStackBackTraceType)
91 : GetProcAddress(LoadLibrary("kernel32.dll"), "RtlCaptureStackBackTrace");
92 : if( !backtraceFunc )
93 : return;
94 :
95 : SymSetOptions( SYMOPT_UNDNAME | SYMOPT_LOAD_LINES );
96 : HANDLE hProcess = GetCurrentProcess();
97 : if( !SymInitialize( hProcess, 0, TRUE ))
98 : return;
99 :
100 : void* stack[ LB_BACKTRACE_DEPTH ];
101 : const size_t frames = (backtraceFunc)( 0, LB_BACKTRACE_DEPTH, stack, 0 );
102 :
103 : SYMBOL_INFO* symbol = (SYMBOL_INFO*)calloc( sizeof(SYMBOL_INFO) +
104 : (LB_SYMBOL_LENGTH+-1)*sizeof(char), 1 );
105 : symbol->MaxNameLen = LB_SYMBOL_LENGTH;
106 : symbol->SizeOfStruct = sizeof( SYMBOL_INFO );
107 :
108 : for( size_t i = skipFrames; i < frames; ++i )
109 : {
110 : os << "\n " << frames-i-1 << ": ";
111 : if ( !SymFromAddr( hProcess, (DWORD64)stack[i], 0, symbol ))
112 : os << "Unknown symbol";
113 : else
114 : {
115 : os << symbol->Name << " - ";
116 : IMAGEHLP_LINE64 line = { sizeof(IMAGEHLP_LINE64) };
117 : DWORD displ;
118 : if( !SymGetLineFromAddr64( hProcess, (DWORD64)stack[i], &displ, &line ))
119 : os << std::hex << "0x" << symbol->Address << std::dec;
120 : else
121 : os << line.FileName << ":" << line.LineNumber;
122 : }
123 : }
124 : os << std::endl;
125 : free( symbol );
126 : SymCleanup( hProcess );
127 : #else
128 : void* callstack[ LB_BACKTRACE_DEPTH ];
129 1 : const int frames = ::backtrace( callstack, LB_BACKTRACE_DEPTH );
130 1 : char** names = ::backtrace_symbols( callstack, frames );
131 5 : for( int i = skipFrames + 1; i < frames; ++i )
132 : {
133 8 : std::string name = names[ i ];
134 : # ifdef __linux__
135 4 : const size_t symbolPos = name.find( "(_" );
136 : # else
137 : const size_t symbolPos = name.find( " _" );
138 : # endif
139 4 : if( symbolPos != std::string::npos )
140 2 : name = name.substr( symbolPos+1, name.length( ));
141 :
142 : # ifdef __linux__
143 4 : const size_t spacePos = name.find( '+' );
144 : # else
145 : const size_t spacePos = name.find( ' ' );
146 : # endif
147 4 : if( spacePos != std::string::npos )
148 3 : name = name.substr( 0, spacePos );
149 :
150 : int status;
151 4 : char* demangled = abi::__cxa_demangle( name.c_str(), 0, 0, &status);
152 :
153 4 : os << "\n " << frames-i-1 << ": ";
154 4 : if( symbolPos == std::string::npos || spacePos == std::string::npos )
155 2 : os << names[ i ];
156 : else
157 : {
158 2 : if( demangled )
159 : {
160 1 : os << demangled;
161 1 : free( demangled );
162 : }
163 : else
164 1 : os << name;
165 : }
166 : }
167 1 : os << "\n";
168 1 : ::free( names );
169 : #endif
170 1 : }
171 : }
172 :
173 1 : std::string backtrace( const size_t skipFrames )
174 : {
175 2 : std::ostringstream os;
176 1 : backtrace_( os, skipFrames + 1/*cut self*/ );
177 2 : return os.str();
178 : }
179 :
180 0 : std::ostream& backtrace( std::ostream& os )
181 : {
182 0 : backtrace_( os, 1 /*cut self*/ );
183 0 : return os;
184 : }
185 :
186 1666 : std::string demangleTypeID( const char* mangled )
187 : {
188 : #ifdef _WIN32
189 : return std::string( mangled );
190 : #else
191 : int status;
192 1666 : char* name = abi::__cxa_demangle( mangled, 0, 0, &status );
193 1666 : if( !name || status != 0 )
194 : {
195 0 : free( name );
196 0 : return mangled;
197 : }
198 :
199 3332 : const std::string result = name;
200 1666 : free( name );
201 1666 : return result;
202 : #endif
203 : }
204 :
205 3 : std::ostream& sysError( std::ostream& os )
206 : {
207 : #ifdef _WIN32
208 : const DWORD error = GetLastError();
209 : char text[512] = "";
210 : FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0, error, 0, text, 511, 0 );
211 : const size_t length = strlen( text );
212 : if( length>2 && text[length-2] == '\r' )
213 : text[length-2] = '\0';
214 :
215 : return os << text << " (" << error << ")";
216 : #else
217 3 : return os << strerror( errno ) << " (" << errno << ")";
218 : #endif
219 : }
220 :
221 0 : std::string sysError()
222 : {
223 0 : std::ostringstream os;
224 0 : os << sysError;
225 0 : return os.str();
226 : }
227 :
228 72 : }
|