OpenShot Library | libopenshot 0.3.3
Loading...
Searching...
No Matches
CrashHandler.cpp
Go to the documentation of this file.
1
9// Copyright (c) 2008-2019 OpenShot Studios, LLC
10//
11// SPDX-License-Identifier: LGPL-3.0-or-later
12
13#include "CrashHandler.h"
14
15#include <iostream>
16#include <iomanip>
17#include <sstream>
18
19using namespace std;
20using namespace openshot;
21
22
23// Global reference to logger
24CrashHandler *CrashHandler::m_pInstance = NULL;
25
26// Create or Get an instance of the logger singleton
28{
29 if (!m_pInstance) {
30 // Create the actual instance of crash handler only once
31 m_pInstance = new CrashHandler;
32
33#ifdef __MINGW32__
34 // TODO: Windows exception handling methods
35 signal(SIGSEGV, CrashHandler::abortHandler);
36
37#else
38 struct sigaction sa;
39 sa.sa_flags = SA_SIGINFO;
40 sa.sa_sigaction = CrashHandler::abortHandler;
41 sigemptyset( &sa.sa_mask );
42
43 // Register abortHandler function callback
44 sigaction( SIGABRT, &sa, NULL );
45 sigaction( SIGSEGV, &sa, NULL );
46 sigaction( SIGBUS, &sa, NULL );
47 sigaction( SIGILL, &sa, NULL );
48 sigaction( SIGFPE, &sa, NULL );
49 sigaction( SIGPIPE, &sa, NULL );
50#endif
51 }
52
53 return m_pInstance;
54}
55
56#ifdef __MINGW32__
57// Windows exception handler
58void CrashHandler::abortHandler(int signum)
59{
60 // Associate each signal with a signal name string.
61 const char* name = NULL;
62 switch( signum )
63 {
64 case SIGABRT: name = "SIGABRT"; break;
65 case SIGSEGV: name = "SIGSEGV"; break;
66 case SIGILL: name = "SIGILL"; break;
67 case SIGFPE: name = "SIGFPE"; break;
68 }
69
70 // Notify the user which signal was caught
71 if ( name )
72 fprintf( stderr, "Caught signal %d (%s)\n", signum, name );
73 else
74 fprintf( stderr, "Caught signal %d\n", signum );
75
76 // Dump a stack trace.
77 printStackTrace(stderr, 63);
78
79 // Quit
80 exit( signum );
81}
82#else
83// Linux and Mac Exception Handler
84void CrashHandler::abortHandler( int signum, siginfo_t* si, void* unused )
85{
86 // Associate each signal with a signal name string.
87 const char* name = NULL;
88 switch( signum )
89 {
90 case SIGABRT: name = "SIGABRT"; break;
91 case SIGSEGV: name = "SIGSEGV"; break;
92 case SIGBUS: name = "SIGBUS"; break;
93 case SIGILL: name = "SIGILL"; break;
94 case SIGFPE: name = "SIGFPE"; break;
95 case SIGPIPE: name = "SIGPIPE"; break;
96 }
97
98 // Notify the user which signal was caught
99 if ( name )
100 fprintf( stderr, "Caught signal %d (%s)\n", signum, name );
101 else
102 fprintf( stderr, "Caught signal %d\n", signum );
103
104 // Dump a stack trace.
105 printStackTrace(stderr, 63);
106
107 // Quit
108 exit( signum );
109}
110#endif
111
112void CrashHandler::printStackTrace(FILE *out, unsigned int max_frames)
113{
114 fprintf(out, "---- Unhandled Exception: Stack Trace ----\n");
115 ZmqLogger::Instance()->LogToFile("---- Unhandled Exception: Stack Trace ----\n");
116 stringstream stack_output;
117
118#ifdef __MINGW32__
119 // Windows stack unwinding
120 HANDLE process = GetCurrentProcess();
121 HANDLE thread = GetCurrentThread();
122
123 CONTEXT context;
124 memset(&context, 0, sizeof(CONTEXT));
125 context.ContextFlags = CONTEXT_FULL;
126 RtlCaptureContext(&context);
127
128 SymInitialize(process, NULL, TRUE);
129
130 DWORD image;
131 STACKFRAME64 stackframe;
132 ZeroMemory(&stackframe, sizeof(STACKFRAME64));
133
134#ifdef _M_IX86
135 image = IMAGE_FILE_MACHINE_I386;
136 stackframe.AddrPC.Offset = context.Eip;
137 stackframe.AddrPC.Mode = AddrModeFlat;
138 stackframe.AddrFrame.Offset = context.Ebp;
139 stackframe.AddrFrame.Mode = AddrModeFlat;
140 stackframe.AddrStack.Offset = context.Esp;
141 stackframe.AddrStack.Mode = AddrModeFlat;
142#elif _M_X64
143 image = IMAGE_FILE_MACHINE_AMD64;
144 stackframe.AddrPC.Offset = context.Rip;
145 stackframe.AddrPC.Mode = AddrModeFlat;
146 stackframe.AddrFrame.Offset = context.Rsp;
147 stackframe.AddrFrame.Mode = AddrModeFlat;
148 stackframe.AddrStack.Offset = context.Rsp;
149 stackframe.AddrStack.Mode = AddrModeFlat;
150#elif _M_IA64
151 image = IMAGE_FILE_MACHINE_IA64;
152 stackframe.AddrPC.Offset = context.StIIP;
153 stackframe.AddrPC.Mode = AddrModeFlat;
154 stackframe.AddrFrame.Offset = context.IntSp;
155 stackframe.AddrFrame.Mode = AddrModeFlat;
156 stackframe.AddrBStore.Offset = context.RsBSP;
157 stackframe.AddrBStore.Mode = AddrModeFlat;
158 stackframe.AddrStack.Offset = context.IntSp;
159 stackframe.AddrStack.Mode = AddrModeFlat;
160#endif
161
162 // Loop through the entire stack
163 for (size_t i = 0; i < max_frames; i++) {
164
165 BOOL result = StackWalk64(
166 image, process, thread,
167 &stackframe, &context, NULL,
168 SymFunctionTableAccess64, SymGetModuleBase64, NULL);
169
170 if (i <= 2) { continue; } // Skip the first 3 elements (those relate to these functions)
171 if (!result) { break; }
172
173 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
174 PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
175 symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
176 symbol->MaxNameLen = MAX_SYM_NAME;
177 WINBOOL found_symbol = SymFromAddr(process, stackframe.AddrPC.Offset, NULL, symbol);
178
179 if (found_symbol) {
180 printf("[%i] %s, address 0x%0X\n", i, symbol->Name, symbol->Address);
181 stack_output << left << setw(30) << symbol->Name << " " << setw(40) << std::hex << symbol->Address << std::dec << endl;
182 } else {
183 printf("[%i] ???\n", i);
184 stack_output << left << setw(30) << "???" << endl;
185 }
186 }
187 SymCleanup(process);
188
189#else
190 // Linux and Mac stack unwinding
191 // Storage array for stack trace address data
192 void* addrlist[max_frames+1];
193
194 // Retrieve current stack addresses
195 unsigned int addrlen = backtrace( addrlist, sizeof( addrlist ) / sizeof( void* ));
196
197 if ( addrlen == 0 )
198 {
199 fprintf(out, " No stack trace found (addrlen == 0)\n");
200 ZmqLogger::Instance()->LogToFile(" No stack trace found (addrlen == 0)\n");
201 return;
202 }
203
204 // Resolve addresses into strings containing "filename(function+address)",
205 // Actually it will be ## program address function + offset
206 // this array must be free()-ed
207 char** symbollist = backtrace_symbols( addrlist, addrlen );
208
209 size_t funcnamesize = 1024;
210 char funcname[1024];
211
212 // Iterate over the returned symbol lines. Skip the first 4, it is the
213 // address of this function.
214 for ( unsigned int i = 4; i < addrlen; i++ )
215 {
216 char* begin_name = NULL;
217 char* begin_offset = NULL;
218 char* end_offset = NULL;
219
220 // Find parentheses and +address offset surrounding the mangled name
221#ifdef DARWIN
222 // OSX style stack trace
223 for ( char *p = symbollist[i]; *p; ++p )
224 {
225 if (( *p == '_' ) && ( *(p-1) == ' ' ))
226 begin_name = p-1;
227 else if ( *p == '+' )
228 begin_offset = p-1;
229 }
230
231 if ( begin_name && begin_offset && ( begin_name < begin_offset ))
232 {
233 *begin_name++ = '\0';
234 *begin_offset++ = '\0';
235
236 // Mangled name is now in [begin_name, begin_offset) and caller
237 // offset in [begin_offset, end_offset). now apply
238 // __cxa_demangle():
239 int status;
240 char* ret = abi::__cxa_demangle( begin_name, &funcname[0], &funcnamesize, &status );
241 if ( status == 0 )
242 {
243 funcname = ret; // Use possibly realloc()-ed string
244 fprintf( out, " %-30s %-40s %s\n", symbollist[i], funcname, begin_offset );
245 stack_output << left << " " << setw(30) << symbollist[i] << " " << setw(40) << funcname << " " << begin_offset << endl;
246 } else {
247 // Demangling failed. Output function name as a C function with
248 // no arguments.
249 fprintf( out, " %-30s %-38s() %s\n", symbollist[i], begin_name, begin_offset );
250 stack_output << left << " " << setw(30) << symbollist[i] << " " << setw(38) << begin_name << " " << begin_offset << endl;
251 }
252
253#else // !DARWIN - but is posix
254 // not OSX style
255 // ./module(function+0x15c) [0x8048a6d]
256 for ( char *p = symbollist[i]; *p; ++p )
257 {
258 if ( *p == '(' )
259 begin_name = p;
260 else if ( *p == '+' )
261 begin_offset = p;
262 else if ( *p == ')' && ( begin_offset || begin_name ))
263 end_offset = p;
264 }
265
266 if ( begin_name && end_offset && ( begin_name < end_offset ))
267 {
268 *begin_name++ = '\0';
269 *end_offset++ = '\0';
270 if ( begin_offset )
271 *begin_offset++ = '\0';
272
273 // Mangled name is now in [begin_name, begin_offset) and caller
274 // offset in [begin_offset, end_offset). now apply
275 // __cxa_demangle():
276 int status = 0;
277 char* ret = abi::__cxa_demangle( begin_name, funcname, &funcnamesize, &status );
278 char* fname = begin_name;
279 if ( status == 0 )
280 fname = ret;
281
282 if ( begin_offset )
283 {
284 fprintf( out, " %-30s ( %-40s + %-6s) %s\n", symbollist[i], fname, begin_offset, end_offset );
285 stack_output << left << " " << setw(30) << symbollist[i] << " " << setw(40) << fname << " " << begin_offset << " " << end_offset << endl;
286
287 } else {
288 fprintf( out, " %-30s ( %-40s %-6s) %s\n", symbollist[i], fname, "", end_offset );
289 stack_output << left << " " << setw(30) << symbollist[i] << " " << setw(40) << fname << " " << end_offset << endl;
290
291 }
292#endif // !DARWIN - but is posix
293 } else {
294 // Couldn't parse the line? print the whole line.
295 fprintf(out, " %-40s\n", symbollist[i]);
296 stack_output << left << " " << setw(40) << symbollist[i] << endl;
297 }
298 }
299
300 // Free array
301 free(symbollist);
302#endif
303
304 // Write stacktrace to file (if log path set)
305 ZmqLogger::Instance()->LogToFile(stack_output.str());
306
307 fprintf(out, "---- End of Stack Trace ----\n");
308 ZmqLogger::Instance()->LogToFile("---- End of Stack Trace ----\n");
309}
Header file for CrashHandler class.
This class is designed to catch exceptions thrown by libc (SIGABRT, SIGSEGV, SIGILL,...
static void abortHandler(int signum, siginfo_t *si, void *unused)
Method which handles crashes and logs error.
static void printStackTrace(FILE *out, unsigned int max_frames)
Method which prints a stacktrace.
static CrashHandler * Instance()
void LogToFile(std::string message)
Log message to a file (if path set)
static ZmqLogger * Instance()
Create or get an instance of this logger singleton (invoke the class with this method)
Definition ZmqLogger.cpp:35
This namespace is the default namespace for all code in the openshot library.
Definition Compressor.h:29