1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the core module of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
29
/*************************************************************************
31
* Original copyright notice:
33
* stacktrace.c 1.2 1998/12/21
35
* Copyright (c) 1998 by Bjorn Reese <breese@imada.ou.dk>
37
* Permission to use, copy, modify, and distribute this software for any
38
* purpose with or without fee is hereby granted, provided that the above
39
* copyright notice and this permission notice appear in all copies.
41
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
42
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
43
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
44
* CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
46
************************************************************************/
48
#include "qplatformdefs.h"
49
#include "private/qcrashhandler_p.h"
54
QtCrashHandler QSegfaultHandler::callback = 0;
56
#if defined(__GLIBC__) && (__GLIBC__ >= 2) && !defined(__UCLIBC__)
58
# include <execinfo.h>
59
static void print_backtrace(FILE *outb)
62
int stack_size = backtrace(stack, sizeof(stack) / sizeof(void *));
63
char **stack_symbols = backtrace_symbols(stack, stack_size);
64
fprintf(outb, "Stack [%d]:\n", stack_size);
65
if(FILE *cppfilt = popen("c++filt", "rw")) {
66
dup2(fileno(outb), fileno(cppfilt));
67
for(int i = stack_size-1; i>=0; --i)
68
fwrite(stack_symbols[i], 1, strlen(stack_symbols[i]), cppfilt);
71
for(int i = stack_size-1; i>=0; --i)
72
fprintf(outb, "#%d %p [%s]\n", i, stack[i], stack_symbols[i]);
75
static void init_backtrace(char **, int)
78
#else /* Don't use the GLIBC callback */
79
/* Code sourced from: */
83
#include <sys/types.h>
85
#if defined(Q_OS_IRIX) && defined(USE_LIBEXC)
89
static char *globalProgName = NULL;
90
static bool backtrace_command(FILE *outb, const char *format, ...)
97
* Please note that vsprintf() is not ASync safe (ie. cannot safely
98
* be used from a signal handler.) If this proves to be a problem
99
* then the cmd string can be built by more basic functions such as
100
* strcpy, strcat, and a homemade integer-to-ascii function.
104
va_start(args, format);
105
vsprintf(cmd, format, args);
112
if(FILE *inb = popen(foo, "r")) {
114
int len = fread(buffer, 1, sizeof(buffer), inb);
118
fwrite("Output from ", 1, strlen("Output from "), outb);
120
fwrite(cmd, 1, strlen(cmd), outb);
121
fwrite("\n", 1, 1, outb);
124
fwrite(buffer, 1, len, outb);
131
static void init_backtrace(char **argv, int argc)
134
globalProgName = argv[0];
137
static void print_backtrace(FILE *outb)
140
* In general dbx seems to do a better job than gdb.
142
* Different dbx implementations require different flags/commands.
144
#if defined(Q_OS_AIX)
145
if(backtrace_command(outb, "dbx -a %d 2>/dev/null <<EOF\n"
151
if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n"
157
globalProgName, (int)getpid()))
159
#elif defined(Q_OS_FREEBSD)
161
* FreeBSD insists on sending a SIGSTOP to the process we
162
* attach to, so we let the debugger send a SIGCONT to that
163
* process after we have detached.
165
if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n"
169
"shell kill -CONT %d\n"
172
globalProgName, (int)getpid(), (int)getpid()))
174
#elif defined(Q_OS_HPUX)
176
* HP decided to call their debugger xdb.
178
* This does not seem to work properly yet. The debugger says
179
* "Note: Stack traces may not be possible until you are
180
* stopped in user code." on HP-UX 09.01
182
* -L = line-oriented interface.
183
* "T [depth]" gives a stacktrace with local variables.
184
* The final "y" is confirmation to the quit command.
186
if(backtrace_command(outb, "xdb -P %d -L %s 2>&1 <<EOF\n"
190
(int)getpid(), globalProgName))
192
if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n"
198
globalProgName, (int)getpid()))
200
#elif defined(Q_OS_IRIX)
202
* "set $page=0" drops hold mode
203
* "dump ." displays the contents of the variables
205
if(backtrace_command(outb, "dbx -p %d 2>/dev/null <<EOF\n"
208
# if !defined(__GNUC__)
209
/* gcc does not generate this information */
217
# if defined(USE_LIBEXC)
218
if(trace_back_stack_and_print())
221
if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n"
225
"frame 5\n" /* Skip signal handler frames */
227
"while (\\$x)\n" /* Print local variables for each frame */
236
globalProgName, (int)getpid()))
238
#elif defined(Q_OS_OSF)
239
if(backtrace_command(outb, "dbx -pid %d %s 2>/dev/null <<EOF\n"
244
(int)getpid(), globalProgName))
246
if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n"
252
globalProgName, (int)getpid()))
254
#elif defined(Q_OS_SCO)
256
* SCO OpenServer dbx is like a catch-22. The 'detach' command
257
* depends on whether ptrace(S) support detaching or not. If it
258
* is supported then 'detach' must be used, otherwise the process
259
* will be killed upon dbx exit. If it isn't supported then 'detach'
260
* will cause the process to be killed. We do not want it to be
263
* Out of two evils, the omission of 'detach' was chosen because
264
* it worked on our system.
266
if(backtrace_command(outb, "dbx %s %d 2>/dev/null <<EOF\n"
269
globalProgName, (int)getpid()))
271
if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n"
277
globalProgName, (int)getpid()))
279
#elif defined(Q_OS_SOLARIS)
280
if(backtrace_command(outb, "dbx %s %d 2>/dev/null <<EOF\n"
284
globalProgName, (int)getpid()))
286
if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n"
290
"frame 5\n" /* Skip signal handler frames */
292
"while (\\$x)\n" /* Print local variables for each frame */
301
globalProgName, (int)getpid()))
303
if(backtrace_command(outb, "/usr/proc/bin/pstack %d",
307
* Other Unices (AIX, HPUX, SCO) also have adb, but
308
* they seem unable to attach to a running process.)
310
if(backtrace_command(outb, "adb %s 2>&1 <<EOF\n"
311
"0t%d:A\n" /* Attach to pid */
312
"\\$c\n" /* print stacktrace */
316
globalProgName, (int)getpid()))
318
#else /* All other platforms */
320
* TODO: SCO/UnixWare 7 must be something like (not tested)
321
* debug -i c <pid> <<EOF\nstack -f 4\nquit\nEOF\n
323
# if !defined(__GNUC__)
324
if(backtrace_command(outb, "dbx %s %d 2>/dev/null <<EOF\n"
328
globalProgName, (int)getpid()))
331
if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n"
348
globalProgName, (int)getpid()))
351
const char debug_err[] = "No debugger found\n";
352
fwrite(debug_err, strlen(debug_err), 1, outb);
354
/* end of copied code */
358
void qt_signal_handler(int sig)
360
signal(sig, SIG_DFL);
361
if(QSegfaultHandler::callback) {
362
(*QSegfaultHandler::callback)();
366
if(char *crash_loc = ::getenv("QT_CRASH_OUTPUT")) {
367
if(FILE *new_outb = fopen(crash_loc, "w")) {
368
fprintf(stderr, "Crash (backtrace written to %s)!!!\n", crash_loc);
372
fprintf(outb, "Crash!!!\n");
374
print_backtrace(outb);
382
QSegfaultHandler::initialize(char **argv, int argc)
384
init_backtrace(argv, argc);
386
struct sigaction SignalAction;
387
SignalAction.sa_flags = 0;
388
SignalAction.sa_handler = qt_signal_handler;
389
sigemptyset(&SignalAction.sa_mask);
390
sigaction(SIGSEGV, &SignalAction, NULL);
391
sigaction(SIGBUS, &SignalAction, NULL);