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

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