41
41
#include < cstdio>
42
42
#include < stdio.h>
43
43
#include < stdlib.h>
44
+ #include < stdarg.h>
44
45
45
46
#ifdef WIN32
46
47
// Open files in binary mode
@@ -83,6 +84,8 @@ typedef SInt32 SRefCon;
83
84
#include < unistd.h>
84
85
#include < execinfo.h>
85
86
#include < signal.h>
87
+ #include < sys/wait.h>
88
+ #include < errno.h>
86
89
#endif
87
90
88
91
/* * print usage text
@@ -193,38 +196,159 @@ void qgisCrash( int signal )
193
196
{
194
197
qFatal ( " QGIS died on signal %d" , signal );
195
198
}
199
+ #endif
196
200
197
- void dumpBacktrace ( )
201
+ void myPrint ( const char *fmt, ... )
198
202
{
199
- if ( access ( " /usr/bin/c++filt" , X_OK ) )
203
+ va_list ap;
204
+ va_start ( ap, fmt );
205
+ #if defined(Q_OS_WIN)
206
+ char buffer[1024 ];
207
+ vsnprintf ( buffer, sizeof buffer, fmt, ap );
208
+ OutputDebugString ( buffer );
209
+ #else
210
+ vfprintf ( stderr, fmt, ap );
211
+ #endif
212
+ }
213
+
214
+ void dumpBacktrace ( unsigned int depth = 0 )
215
+ {
216
+ if ( depth == 0 )
217
+ depth = 10 ;
218
+
219
+ #if (defined(linux) && !defined(ANDROID)) || defined(__FreeBSD__)
220
+ #if defined(linux) && !defined(ANDROID)
221
+ if ( QgsLogger::debugLevel () >= 4 )
222
+ {
223
+ static int gdbRunning = -1 ;
224
+ static int gdbpipe[2 ];
225
+ static int gdbpid;
226
+
227
+ if ( gdbRunning == -1 )
228
+ {
229
+ gdbRunning = 0 ;
230
+
231
+ myPrint ( " starting gdb\n " );
232
+ if ( access ( " /usr/bin/gdb" , X_OK ) == 0 )
233
+ {
234
+ // take full stacktrace using gdb
235
+ // http://stackoverflow.com/questions/3151779/how-its-better-to-invoke-gdb-from-program-to-print-its-stacktrace
236
+
237
+ char exename[512 ];
238
+ int len = readlink ( " /proc/self/exe" , exename, sizeof ( exename ) - 1 );
239
+ if ( len < 0 )
240
+ {
241
+ myPrint ( " Could not read link.\n " );
242
+ }
243
+ else
244
+ {
245
+ exename[ len ] = 0 ;
246
+
247
+ if ( pipe ( gdbpipe ) == 0 )
248
+ {
249
+ char pidstr[32 ];
250
+ snprintf ( pidstr, sizeof pidstr, " --pid=%d" , getpid () );
251
+
252
+ gdbpid = fork ();
253
+ fprintf ( stderr, " fork returned: %d\n " , gdbpid );
254
+ if ( gdbpid == 0 )
255
+ {
256
+ close ( STDIN_FILENO ); // close stdin
257
+ dup ( gdbpipe[0 ] ); // stdin from pipe
258
+ close ( gdbpipe[1 ] ); // close writing end
259
+
260
+ // attach, backtrace and continue
261
+ char btcmd[32 ];
262
+ snprintf ( btcmd, sizeof btcmd, " bt full %u" , depth );
263
+
264
+ execl ( " /usr/bin/gdb" , " gdb" , " -q" , " -ex" , " set height 0" , " -n" , pidstr, " -ex" , " thread" , " -ex" , btcmd, " -ex" , " cont" , exename, NULL );
265
+ perror ( " could not start gdb" );
266
+ exit ( 0 );
267
+ }
268
+ else if ( gdbpid >= 0 )
269
+ {
270
+ close ( gdbpipe[0 ] ); // close reading end
271
+ gdbRunning = 1 ;
272
+ }
273
+ else
274
+ {
275
+ myPrint ( " Could not start gdb (%d:%s).\n " , errno, strerror ( errno ) );
276
+ }
277
+ }
278
+ else
279
+ {
280
+ myPrint ( " Could not create pipe (%d:%s).\n " , errno, strerror ( errno ) );
281
+ }
282
+ }
283
+ }
284
+ else
285
+ {
286
+ myPrint ( " gdb not available.\n " );
287
+ }
288
+ }
289
+ else if ( gdbRunning == 1 )
290
+ {
291
+ myPrint ( " Stacktrace (using gdb):\n " );
292
+ char btcmd[20 ];
293
+ snprintf ( btcmd, sizeof btcmd, " bt full %u\n cont\n " , depth );
294
+ if ( write ( gdbpipe[1 ], btcmd, strlen ( btcmd ) ) == ( int ) strlen ( btcmd ) && kill ( gdbpid, SIGINT ) == 0 )
295
+ return ;
296
+
297
+ myPrint ( " write error to gdb [%d:%s]\n " , errno, strerror ( errno ) );
298
+ gdbRunning = 0 ;
299
+ }
300
+ }
301
+ #endif
302
+
303
+ if ( access ( " /usr/bin/c++filt" , X_OK ) < 0 )
200
304
{
201
- ( void ) write ( STDERR_FILENO, " Stacktrace (c++filt NOT FOUND):\n " , 32 );
305
+ myPrint ( " Stacktrace (c++filt NOT FOUND):\n " );
202
306
}
203
307
else
204
308
{
205
309
int fd[2 ];
206
310
207
311
if ( pipe ( fd ) == 0 && fork () == 0 )
208
312
{
209
- close ( STDIN_FILENO );
210
- close ( fd[1 ] );
211
- dup ( fd[0 ] );
313
+ close ( STDIN_FILENO ); // close stdin
314
+ dup ( fd[0 ] ); // stdin from pipe
315
+ close ( fd[1 ] ); // close writing end
212
316
execl ( " /usr/bin/c++filt" , " c++filt" , ( char * ) 0 );
317
+ perror ( " could not start c++filt" );
213
318
exit ( 1 );
214
319
}
215
320
216
- ( void ) write ( STDERR_FILENO, " Stacktrace (piped through c++filt):\n " , 36 );
217
-
218
- close ( STDERR_FILENO );
219
- close ( fd[0 ] );
220
- dup ( fd[1 ] );
321
+ myPrint ( " Stacktrace (piped through c++filt):\n " );
322
+ close ( fd[0 ] ); // close reading end
323
+ close ( STDERR_FILENO ); // close stderr
324
+ dup ( fd[1 ] ); // stderr to pipe
221
325
}
222
326
223
- void *buffer[ 256 ];
224
- int nptrs = backtrace ( buffer, sizeof ( buffer ) / sizeof ( *buffer ) );
327
+ void ** buffer = new void *[ depth ];
328
+ int nptrs = backtrace ( buffer, depth );
225
329
backtrace_symbols_fd ( buffer, nptrs, STDERR_FILENO );
226
- }
330
+ delete [] buffer;
331
+ #elif defined(Q_OS_WIN)
332
+ void **buffer = new void *[ depth ];
333
+
334
+ SymSetOptions ( SYMOPT_DEFERRED_LOADS | SYMOPT_INCLUDE_32BIT_MODULES | SYMOPT_UNDNAME );
335
+ SymInitialize ( GetCurrentProcess (), " http://msdl.microsoft.com/download/symbols" , TRUE );
336
+
337
+ unsigned short nFrames = CaptureStackBackTrace ( 1 , depth, buffer, NULL );
338
+ SYMBOL_INFO *symbol = ( SYMBOL_INFO * ) qgsMalloc ( sizeof ( SYMBOL_INFO ) + 256 );
339
+ symbol->MaxNameLen = 255 ;
340
+ symbol->SizeOfStruct = sizeof ( SYMBOL_INFO );
341
+
342
+ for ( int i = 0 ; i < nFrames; i++ )
343
+ {
344
+ SymFromAddr ( GetCurrentProcess (), ( DWORD64 )( buffer[ i ] ), 0 , symbol );
345
+ symbol->Name [ 255 ] = 0 ;
346
+ myPrint ( " %d: %s [%x]\n " , i, symbol->Name , symbol->Address );
347
+ }
348
+
349
+ qgsFree ( symbol );
227
350
#endif
351
+ }
228
352
229
353
/*
230
354
* Hook into the qWarning/qFatal mechanism so that we can channel messages
@@ -242,31 +366,19 @@ void myMessageOutput( QtMsgType type, const char *msg )
242
366
switch ( type )
243
367
{
244
368
case QtDebugMsg:
245
- fprintf ( stderr, " Debug: %s\n " , msg );
246
- #if (defined(linux) && !defined(ANDROID)) || defined(__FreeBSD__)
369
+ myPrint ( " %s\n " , msg );
247
370
if ( strncmp ( msg, " Backtrace" , 9 ) == 0 )
248
- dumpBacktrace ();
249
- #endif
371
+ dumpBacktrace ( atoi ( msg + 9 ) );
250
372
break ;
251
373
case QtCriticalMsg:
252
- fprintf ( stderr, " Critical: %s\n " , msg );
374
+ myPrint ( " Critical: %s\n " , msg );
253
375
break ;
254
376
case QtWarningMsg:
255
- fprintf ( stderr, " Warning: %s\n " , msg );
377
+ myPrint ( " Warning: %s\n " , msg );
256
378
257
379
#ifdef QGISDEBUG
258
- if ( 0 == strncmp ( msg, " Object::" , 8 )
259
- || 0 == strncmp ( msg, " QWidget::" , 9 )
260
- || 0 == strncmp ( msg, " QPainter::" , 10 )
261
- )
262
- {
263
- #if 0
264
- #if (defined(linux) && !defined(ANDROID)) || defined(__FreeBSD__)
265
- dumpBacktrace();
266
- #endif
267
- #endif
268
- QgsMessageLog::logMessage ( msg, " Qt" );
269
- }
380
+ dumpBacktrace ( 20 );
381
+ QgsMessageLog::logMessage ( msg, " Qt" );
270
382
#endif
271
383
272
384
// TODO: Verify this code in action.
@@ -279,11 +391,9 @@ void myMessageOutput( QtMsgType type, const char *msg )
279
391
break ;
280
392
case QtFatalMsg:
281
393
{
282
- fprintf ( stderr, " Fatal: %s\n " , msg );
283
- #if (defined(linux) && !defined(ANDROID)) || defined(__FreeBSD__)
284
- dumpBacktrace ();
285
- #endif
286
- abort (); // deliberately core dump
394
+ myPrint ( " Fatal: %s\n " , msg );
395
+ dumpBacktrace ( 256 );
396
+ abort (); // deliberately dump core
287
397
}
288
398
}
289
399
}
@@ -299,10 +409,10 @@ int main( int argc, char *argv[] )
299
409
#endif // _MSC_VER
300
410
#endif // WIN32
301
411
302
- #if (defined(linux) && !defined(ANDROID)) || defined(__FreeBSD__)
303
412
// Set up the custom qWarning/qDebug custom handler
304
413
qInstallMsgHandler ( myMessageOutput );
305
414
415
+ #if (defined(linux) && !defined(ANDROID)) || defined(__FreeBSD__)
306
416
signal ( SIGQUIT, qgisCrash );
307
417
signal ( SIGILL, qgisCrash );
308
418
signal ( SIGFPE, qgisCrash );
@@ -775,9 +885,6 @@ int main( int argc, char *argv[] )
775
885
}
776
886
}
777
887
778
- #ifdef QGISDEBUG
779
- // QgsDebugMsg(QString("Setting translation to %1/qgis_%2").arg(i18nPath).arg(myTranslationCode));
780
- #endif
781
888
QTranslator qgistor ( 0 );
782
889
if ( qgistor.load ( QString ( " qgis_" ) + myTranslationCode, i18nPath ) )
783
890
{
0 commit comments