25 SIGILL, // illegal instructions |
25 SIGILL, // illegal instructions |
26 }); |
26 }); |
27 |
27 |
28 // ============================================================================= |
28 // ============================================================================= |
29 // ----------------------------------------------------------------------------- |
29 // ----------------------------------------------------------------------------- |
30 static void handleSignal (int sig) |
30 static void handleCrash (int sig) |
31 { printf ("caught signal %d\n", sig); |
31 { printf ("%s: crashed with signal %d, launching gdb\n", __func__, sig); |
32 |
32 |
33 if (g_crashCatcherActive) |
33 if (g_crashCatcherActive) |
34 { printf ("caught signal while crash catcher is active!\n"); |
34 { printf ("caught signal while crash catcher is active!\n"); |
35 return; |
35 return; |
36 } |
36 } |
37 |
37 |
38 if (g_signalsToCatch.indexOf (sig) != -1) |
38 const pid_t pid = getpid(); |
39 { const pid_t pid = getpid(); |
39 QProcess proc; |
40 QProcess proc; |
40 QTemporaryFile commandsFile; |
41 QTemporaryFile commandsFile; |
|
42 |
41 |
43 g_crashCatcherActive = true; |
42 g_crashCatcherActive = true; |
44 printf ("%s: crashed with signal %d, launching gdb\n", __func__, sig); |
|
45 |
43 |
46 if (commandsFile.open()) |
44 if (commandsFile.open()) |
47 { commandsFile.write (fmt ("attach %1\n", pid).toLocal8Bit()); |
45 { commandsFile.write (fmt ("attach %1\n", pid).toLocal8Bit()); |
48 commandsFile.write (str ("backtrace full\n").toLocal8Bit()); |
46 commandsFile.write (str ("backtrace full\n").toLocal8Bit()); |
49 commandsFile.write (str ("detach\n").toLocal8Bit()); |
47 commandsFile.write (str ("detach\n").toLocal8Bit()); |
50 commandsFile.write (str ("quit").toLocal8Bit()); |
48 commandsFile.write (str ("quit").toLocal8Bit()); |
51 commandsFile.flush(); |
49 commandsFile.flush(); |
52 commandsFile.close(); |
50 commandsFile.close(); |
53 } |
51 } |
54 |
52 |
55 QStringList args ({"-x", commandsFile.fileName()}); |
53 QStringList args ({"-x", commandsFile.fileName()}); |
56 |
54 |
57 proc.start ("gdb", args); |
55 proc.start ("gdb", args); |
58 |
56 |
59 // Linux doesn't allow ptrace to be used on anything but direct child processes |
57 // Linux doesn't allow ptrace to be used on anything but direct child processes |
60 // so we need to use prctl to register an exception to this to allow GDB attach to us. |
58 // so we need to use prctl to register an exception to this to allow GDB attach to us. |
61 // We need to do this now and no earlier because only now we actually know GDB's PID. |
59 // We need to do this now and no earlier because only now we actually know GDB's PID. |
62 prctl (PR_SET_PTRACER, proc.pid(), 0, 0, 0); |
60 prctl (PR_SET_PTRACER, proc.pid(), 0, 0, 0); |
63 |
61 |
64 proc.waitForFinished (5000); |
62 proc.waitForFinished (1000); |
65 str output = QString (proc.readAllStandardOutput()); |
63 str output = QString (proc.readAllStandardOutput()); |
66 str err = QString (proc.readAllStandardError()); |
64 str err = QString (proc.readAllStandardError()); |
67 |
65 |
68 bombBox (fmt ("<h3>Program crashed with signal %1</h3>\n\n" |
66 bombBox (fmt ("<h3>Program crashed with signal %1</h3>\n\n" |
69 "%2" |
67 "%2" |
70 "<p><b>GDB <tt>stdout</tt>:</b></p><pre>%3</pre>\n" |
68 "<p><b>GDB <tt>stdout</tt>:</b></p><pre>%3</pre>\n" |
71 "<p><b>GDB <tt>stderr</tt>:</b></p><pre>%4</pre>", |
69 "<p><b>GDB <tt>stderr</tt>:</b></p><pre>%4</pre>", |
72 sig, (!g_assertionFailure.isEmpty()) ? g_assertionFailure : "", output, err)); |
70 sig, (!g_assertionFailure.isEmpty()) ? g_assertionFailure : "", output, err)); |
73 exit (137); |
|
74 } |
|
75 } |
71 } |
76 |
72 |
77 // ============================================================================= |
73 // ============================================================================= |
78 // ----------------------------------------------------------------------------- |
74 // ----------------------------------------------------------------------------- |
79 void initCrashCatcher() |
75 void initCrashCatcher() |
80 { struct sigaction sighandler; |
76 { struct sigaction sighandler; |
81 sighandler.sa_handler = &handleSignal; |
77 sighandler.sa_handler = &handleCrash; |
82 sighandler.sa_flags = 0; |
78 sighandler.sa_flags = 0; |
83 sigemptyset (&sighandler.sa_mask); |
79 sigemptyset (&sighandler.sa_mask); |
84 |
80 |
85 for (int sig : g_signalsToCatch) |
81 for (int sig : g_signalsToCatch) |
86 sigaction (sig, &sighandler, null); |
82 sigaction (sig, &sighandler, null); |