qcrashhandler.cpp

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

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9