kernel/qcrashhandler.cpp

Source codeSwitch to Preprocessed file
LineSource CodeCoverage
1/**************************************************************************** -
2** -
3** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -
4** Contact: http://www.qt-project.org/legal -
5** -
6** This file is part of the QtCore module of the Qt Toolkit. -
7** -
8** $QT_BEGIN_LICENSE:LGPL$ -
9** Commercial License Usage -
10** Licensees holding valid commercial Qt licenses may use this file in -
11** accordance with the commercial license agreement provided with the -
12** Software or, alternatively, in accordance with the terms contained in -
13** a written agreement between you and Digia. For licensing terms and -
14** conditions see http://qt.digia.com/licensing. For further information -
15** use the contact form at http://qt.digia.com/contact-us. -
16** -
17** GNU Lesser General Public License Usage -
18** Alternatively, this file may be used under the terms of the GNU Lesser -
19** General Public License version 2.1 as published by the Free Software -
20** Foundation and appearing in the file LICENSE.LGPL included in the -
21** packaging of this file. Please review the following information to -
22** ensure the GNU Lesser General Public License version 2.1 requirements -
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -
24** -
25** In addition, as a special exception, Digia gives you certain additional -
26** rights. These rights are described in the Digia Qt LGPL Exception -
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -
28** -
29** GNU General Public License Usage -
30** Alternatively, this file may be used under the terms of the GNU -
31** General Public License version 3.0 as published by the Free Software -
32** Foundation and appearing in the file LICENSE.GPL included in the -
33** packaging of this file. Please review the following information to -
34** ensure the GNU General Public License version 3.0 requirements will be -
35** met: http://www.gnu.org/copyleft/gpl.html. -
36** -
37** -
38** $QT_END_LICENSE$ -
39** -
40****************************************************************************/ -
41 -
42/************************************************************************* -
43 * -
44 * stacktrace.c 1.2 1998/12/21 -
45 * -
46 * Copyright (c) 1998 by Bjorn Reese <breese@imada.ou.dk> -
47 * -
48 * Permission to use, copy, modify, and distribute this software for any -
49 * purpose with or without fee is hereby granted, provided that the above -
50 * copyright notice and this permission notice appear in all copies. -
51 * -
52 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED -
53 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF -
54 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND -
55 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. -
56 * -
57 ************************************************************************/ -
58 -
59#include "qplatformdefs.h" -
60#include "private/qcrashhandler_p.h" -
61#include "qbytearray.h" // for qvsnprintf() -
62 -
63#ifndef QT_NO_CRASHHANDLER -
64 -
65#include <stdio.h> -
66#include <signal.h> -
67#include <stdlib.h> -
68 -
69QT_BEGIN_NAMESPACE -
70 -
71QtCrashHandler QSegfaultHandler::callback = 0; -
72 -
73#if defined(__GLIBC__) && (__GLIBC__ >= 2) && !defined(__UCLIBC__) && !defined(QT_LINUXBASE) -
74QT_BEGIN_INCLUDE_NAMESPACE -
75# include "qstring.h" -
76# include <execinfo.h> -
77QT_END_INCLUDE_NAMESPACE -
78 -
79static void print_backtrace(FILE *outb) -
80{ -
81 void *stack[128];
never executed (the execution status of this line is deduced): void *stack[128];
-
82 int stack_size = backtrace(stack, sizeof(stack) / sizeof(void *));
never executed (the execution status of this line is deduced): int stack_size = backtrace(stack, sizeof(stack) / sizeof(void *));
-
83 char **stack_symbols = backtrace_symbols(stack, stack_size);
never executed (the execution status of this line is deduced): char **stack_symbols = backtrace_symbols(stack, stack_size);
-
84 fprintf(outb, "Stack [%d]:\n", stack_size);
never executed (the execution status of this line is deduced): fprintf(outb, "Stack [%d]:\n", stack_size);
-
85 if(FILE *cppfilt = popen("c++filt", "rw")) {
never evaluated: FILE *cppfilt = popen("c++filt", "rw")
0
86 dup2(fileno(outb), fileno(cppfilt));
never executed (the execution status of this line is deduced): dup2(fileno(outb), fileno(cppfilt));
-
87 for(int i = stack_size-1; i>=0; --i)
never evaluated: i>=0
0
88 fwrite(stack_symbols[i], 1, strlen(stack_symbols[i]), cppfilt);
never executed: fwrite(stack_symbols[i], 1, strlen(stack_symbols[i]), cppfilt);
0
89 pclose(cppfilt);
never executed (the execution status of this line is deduced): pclose(cppfilt);
-
90 } else {
never executed: }
0
91 for(int i = stack_size-1; i>=0; --i)
never evaluated: i>=0
0
92 fprintf(outb, "#%d %p [%s]\n", i, stack[i], stack_symbols[i]);
never executed: fprintf(outb, "#%d %p [%s]\n", i, stack[i], stack_symbols[i]);
0
93 }
never executed: }
0
94} -
95static void init_backtrace(char **, int) -
96{ -
97} -
98 -
99#else /* Don't use the GLIBC callback */ -
100/* Code sourced from: */ -
101QT_BEGIN_INCLUDE_NAMESPACE -
102#include <stdarg.h> -
103#include <string.h> -
104#include <errno.h> -
105#include <sys/types.h> -
106#include <sys/wait.h> -
107#if defined(Q_OS_IRIX) && defined(USE_LIBEXC) -
108# include <libexc.h> -
109#endif -
110QT_END_INCLUDE_NAMESPACE -
111 -
112 -
113static char *globalProgName = NULL; -
114static bool backtrace_command(FILE *outb, const char *format, ...) -
115{ -
116 -
117 bool ret = false; -
118 char buffer[50]; -
119 -
120 /* -
121 * Please note that vsnprintf() is not ASync safe (ie. cannot safely -
122 * be used from a signal handler.) If this proves to be a problem -
123 * then the cmd string can be built by more basic functions such as -
124 * strcpy, strcat, and a home-made integer-to-ascii function. -
125 */ -
126 va_list args; -
127 char cmd[512]; -
128 va_start(args, format); -
129 qvsnprintf(cmd, 512, format, args); -
130 va_end(args); -
131 -
132 char *foo = cmd; -
133#if 0 -
134 foo = "echo hi"; -
135#endif -
136 if(FILE *inb = popen(foo, "r")) { -
137 while(!feof(inb)) { -
138 int len = fread(buffer, 1, sizeof(buffer), inb); -
139 if(!len) -
140 break; -
141 if(!ret) { -
142 fwrite("Output from ", 1, strlen("Output from "), outb); -
143 strtok(cmd, " "); -
144 fwrite(cmd, 1, strlen(cmd), outb); -
145 fwrite("\n", 1, 1, outb); -
146 ret = true; -
147 } -
148 fwrite(buffer, 1, len, outb); -
149 } -
150 fclose(inb); -
151 } -
152 return ret; -
153} -
154 -
155static void init_backtrace(char **argv, int argc) -
156{ -
157 if(argc >= 1) -
158 globalProgName = argv[0]; -
159} -
160 -
161static void print_backtrace(FILE *outb) -
162{ -
163 /* -
164 * In general dbx seems to do a better job than gdb. -
165 * -
166 * Different dbx implementations require different flags/commands. -
167 */ -
168#if defined(Q_OS_AIX) -
169 if(backtrace_command(outb, "dbx -a %d 2>/dev/null <<EOF\n" -
170 "where\n" -
171 "detach\n" -
172 "EOF\n", -
173 (int)getpid())) -
174 return; -
175 if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" -
176 "set prompt\n" -
177 "where\n" -
178 "detach\n" -
179 "quit\n" -
180 "EOF\n", -
181 globalProgName, (int)getpid())) -
182 return; -
183#elif defined(Q_OS_FREEBSD) -
184 /* -
185 * FreeBSD insists on sending a SIGSTOP to the process we -
186 * attach to, so we let the debugger send a SIGCONT to that -
187 * process after we have detached. -
188 */ -
189 if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" -
190 "set prompt\n" -
191 "where\n" -
192 "detach\n" -
193 "shell kill -CONT %d\n" -
194 "quit\n" -
195 "EOF\n", -
196 globalProgName, (int)getpid(), (int)getpid())) -
197 return; -
198#elif defined(Q_OS_HPUX) -
199 /* -
200 * HP decided to call their debugger xdb. -
201 * -
202 * This does not seem to work properly yet. The debugger says -
203 * "Note: Stack traces may not be possible until you are -
204 * stopped in user code." on HP-UX 09.01 -
205 * -
206 * -L = line-oriented interface. -
207 * "T [depth]" gives a stacktrace with local variables. -
208 * The final "y" is confirmation to the quit command. -
209 */ -
210 if(backtrace_command(outb, "xdb -P %d -L %s 2>&1 <<EOF\n" -
211 "T 50\n" -
212 "q\ny\n" -
213 "EOF\n", -
214 (int)getpid(), globalProgName)) -
215 return; -
216 if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" -
217 "set prompt\n" -
218 "where\n" -
219 "detach\n" -
220 "quit\n" -
221 "EOF\n", -
222 globalProgName, (int)getpid())) -
223 return; -
224#elif defined(Q_OS_IRIX) -
225 /* -
226 * "set $page=0" drops hold mode -
227 * "dump ." displays the contents of the variables -
228 */ -
229 if(backtrace_command(outb, "dbx -p %d 2>/dev/null <<EOF\n" -
230 "set \\$page=0\n" -
231 "where\n" -
232# if !defined(__GNUC__) -
233 /* gcc does not generate this information */ -
234 "dump .\n" -
235# endif -
236 "detach\n" -
237 "EOF\n", -
238 (int)getpid())) -
239 return; -
240 -
241# if defined(USE_LIBEXC) -
242 if(trace_back_stack_and_print()) -
243 return; -
244# endif -
245 if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" -
246 "set prompt\n" -
247 "where\n" -
248 "echo ---\\n\n" -
249 "frame 5\n" /* Skip signal handler frames */ -
250 "set \\$x = 50\n" -
251 "while (\\$x)\n" /* Print local variables for each frame */ -
252 "info locals\n" -
253 "up\n" -
254 "set \\$x--\n" -
255 "end\n" -
256 "echo ---\\n\n" -
257 "detach\n" -
258 "quit\n" -
259 "EOF\n", -
260 globalProgName, (int)getpid())) -
261 return; -
262#elif defined(Q_OS_OSF) -
263 if(backtrace_command(outb, "dbx -pid %d %s 2>/dev/null <<EOF\n" -
264 "where\n" -
265 "detach\n" -
266 "quit\n" -
267 "EOF\n", -
268 (int)getpid(), globalProgName)) -
269 return; -
270 if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" -
271 "set prompt\n" -
272 "where\n" -
273 "detach\n" -
274 "quit\n" -
275 "EOF\n", -
276 globalProgName, (int)getpid())) -
277 return; -
278#elif defined(Q_OS_SCO) -
279 /* -
280 * SCO OpenServer dbx is like a catch-22. The 'detach' command -
281 * depends on whether ptrace(S) support detaching or not. If it -
282 * is supported then 'detach' must be used, otherwise the process -
283 * will be killed upon dbx exit. If it isn't supported then 'detach' -
284 * will cause the process to be killed. We do not want it to be -
285 * killed. -
286 * -
287 * Out of two evils, the omission of 'detach' was chosen because -
288 * it worked on our system. -
289 */ -
290 if(backtrace_command(outb, "dbx %s %d 2>/dev/null <<EOF\n" -
291 "where\n" -
292 "quit\nEOF\n", -
293 globalProgName, (int)getpid())) -
294 return; -
295 if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" -
296 "set prompt\n" -
297 "where\n" -
298 "detach\n" -
299 "quit\n" -
300 "EOF\n", -
301 globalProgName, (int)getpid())) -
302 return; -
303#elif defined(Q_OS_SOLARIS) -
304 if(backtrace_command(outb, "dbx %s %d 2>/dev/null <<EOF\n" -
305 "where\n" -
306 "detach\n" -
307 "EOF\n", -
308 globalProgName, (int)getpid())) -
309 return; -
310 if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" -
311 "set prompt\n" -
312 "where\n" -
313 "echo ---\\n\n" -
314 "frame 5\n" /* Skip signal handler frames */ -
315 "set \\$x = 50\n" -
316 "while (\\$x)\n" /* Print local variables for each frame */ -
317 "info locals\n" -
318 "up\n" -
319 "set \\$x--\n" -
320 "end\n" -
321 "echo ---\\n\n" -
322 "detach\n" -
323 "quit\n" -
324 "EOF\n", -
325 globalProgName, (int)getpid())) -
326 return; -
327 if(backtrace_command(outb, "/usr/proc/bin/pstack %d", -
328 (int)getpid())) -
329 return; -
330 /* -
331 * Other Unices (AIX, HPUX, SCO) also have adb, but -
332 * they seem unable to attach to a running process.) -
333 */ -
334 if(backtrace_command(outb, "adb %s 2>&1 <<EOF\n" -
335 "0t%d:A\n" /* Attach to pid */ -
336 "\\$c\n" /* print stacktrace */ -
337 ":R\n" /* Detach */ -
338 "\\$q\n" /* Quit */ -
339 "EOF\n", -
340 globalProgName, (int)getpid())) -
341 return; -
342#elif defined(Q_OS_INTEGRITY) -
343 /* abort */ -
344 CheckSuccess(Failure); -
345#else /* All other platforms */ -
346 /* -
347 * TODO: SCO/UnixWare 7 must be something like (not tested) -
348 * debug -i c <pid> <<EOF\nstack -f 4\nquit\nEOF\n -
349 */ -
350# if !defined(__GNUC__) -
351 if(backtrace_command(outb, "dbx %s %d 2>/dev/null <<EOF\n" -
352 "where\n" -
353 "detach\n" -
354 "EOF\n", -
355 globalProgName, (int)getpid())) -
356 return; -
357# endif -
358 if(backtrace_command(outb, "gdb -q %s %d 2>/dev/null <<EOF\n" -
359 "set prompt\n" -
360 "where\n" -
361#if 0 -
362 "echo ---\\n\n" -
363 "frame 4\n" -
364 "set \\$x = 50\n" -
365 "while (\\$x)\n" -
366 "info locals\n" -
367 "up\n" -
368 "set \\$x--\n" -
369 "end\n" -
370 "echo ---\\n\n" -
371#endif -
372 "detach\n" -
373 "quit\n" -
374 "EOF\n", -
375 globalProgName, (int)getpid())) -
376 return; -
377#endif -
378 const char debug_err[] = "No debugger found\n"; -
379 fwrite(debug_err, strlen(debug_err), 1, outb); -
380} -
381/* end of copied code */ -
382#endif -
383 -
384 -
385void qt_signal_handler(int sig) -
386{ -
387 signal(sig, SIG_DFL);
never executed (the execution status of this line is deduced): signal(sig, ((__sighandler_t) 0));
-
388 if(QSegfaultHandler::callback) {
never evaluated: QSegfaultHandler::callback
0
389 (*QSegfaultHandler::callback)();
never executed (the execution status of this line is deduced): (*QSegfaultHandler::callback)();
-
390 _exit(1);
never executed (the execution status of this line is deduced): _exit(1);
-
391 }
never executed: }
0
392 FILE *outb = stderr;
never executed (the execution status of this line is deduced): FILE *outb = stderr;
-
393 if(char *crash_loc = ::getenv("QT_CRASH_OUTPUT")) {
never evaluated: char *crash_loc = ::getenv("QT_CRASH_OUTPUT")
0
394 if(FILE *new_outb = fopen(crash_loc, "w")) {
never evaluated: FILE *new_outb = fopen(crash_loc, "w")
0
395 fprintf(stderr, "Crash (backtrace written to %s)!!!\n", crash_loc);
never executed (the execution status of this line is deduced): fprintf(stderr, "Crash (backtrace written to %s)!!!\n", crash_loc);
-
396 outb = new_outb;
never executed (the execution status of this line is deduced): outb = new_outb;
-
397 }
never executed: }
0
398 } else {
never executed: }
0
399 fprintf(outb, "Crash!!!\n");
never executed (the execution status of this line is deduced): fprintf(outb, "Crash!!!\n");
-
400 }
never executed: }
0
401 print_backtrace(outb);
never executed (the execution status of this line is deduced): print_backtrace(outb);
-
402 if(outb != stderr)
never evaluated: outb != stderr
0
403 fclose(outb);
never executed: fclose(outb);
0
404 _exit(1);
never executed (the execution status of this line is deduced): _exit(1);
-
405}
never executed: }
0
406 -
407 -
408void -
409QSegfaultHandler::initialize(char **argv, int argc) -
410{ -
411 init_backtrace(argv, argc);
never executed (the execution status of this line is deduced): init_backtrace(argv, argc);
-
412 -
413 struct sigaction SignalAction;
never executed (the execution status of this line is deduced): struct sigaction SignalAction;
-
414 SignalAction.sa_flags = 0;
never executed (the execution status of this line is deduced): SignalAction.sa_flags = 0;
-
415 SignalAction.sa_handler = qt_signal_handler;
never executed (the execution status of this line is deduced): SignalAction.__sigaction_handler.sa_handler = qt_signal_handler;
-
416 sigemptyset(&SignalAction.sa_mask);
never executed (the execution status of this line is deduced): sigemptyset(&SignalAction.sa_mask);
-
417 sigaction(SIGSEGV, &SignalAction, NULL);
never executed (the execution status of this line is deduced): sigaction(11, &SignalAction, __null);
-
418 sigaction(SIGBUS, &SignalAction, NULL);
never executed (the execution status of this line is deduced): sigaction(7, &SignalAction, __null);
-
419}
never executed: }
0
420 -
421QT_END_NAMESPACE -
422 -
423#endif // QT_NO_CRASHHANDLER -
424 -
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial