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