src/crashCatcher.cc

changeset 848
68410477c8bb
parent 844
11587d419d2f
child 855
e16f1587ef44
equal deleted inserted replaced
847:274a7fac44fc 848:68410477c8bb
27 #ifdef Q_OS_LINUX 27 #ifdef Q_OS_LINUX
28 # include <sys/prctl.h> 28 # include <sys/prctl.h>
29 #endif 29 #endif
30 30
31 // Is the crash catcher active now? 31 // Is the crash catcher active now?
32 static bool g_crashCatcherActive = false; 32 static bool IsCrashCatcherActive = false;
33 33
34 // If an assertion failed, what was it? 34 // If an assertion failed, what was it?
35 static QString g_assertionFailure; 35 static QString AssertionFailureText;
36 36
37 // List of signals to catch and crash on 37 // List of signals to catch and crash on
38 static QList<int> g_signalsToCatch ({ 38 static QList<int> SignalsToCatch ({
39 SIGSEGV, // segmentation fault 39 SIGSEGV, // segmentation fault
40 SIGABRT, // abort() calls 40 SIGABRT, // abort() calls
41 SIGFPE, // floating point exceptions (e.g. division by zero) 41 SIGFPE, // floating point exceptions (e.g. division by zero)
42 SIGILL, // illegal instructions 42 SIGILL, // illegal instructions
43 }); 43 });
44 44
45 // -------------------------------------------------------------------------------------------------
45 // 46 //
46 // Removes the signal handler from SIGABRT and then aborts. 47 // Removes the signal handler from SIGABRT and then aborts.
47 // 48 //
48 static void finalAbort() 49 static void FinalAbort()
49 { 50 {
50 struct sigaction sighandler; 51 struct sigaction sighandler;
51 sighandler.sa_handler = SIG_DFL; 52 sighandler.sa_handler = SIG_DFL;
52 sighandler.sa_flags = 0; 53 sighandler.sa_flags = 0;
53 sigaction (SIGABRT, &sighandler, 0); 54 sigaction (SIGABRT, &sighandler, 0);
54 abort(); 55 abort();
55 } 56 }
56 57
57 // ============================================================================= 58 // -------------------------------------------------------------------------------------------------
58 // 59 //
59 static void handleCrash (int sig) 60 static void HandleCrash (int sig)
60 { 61 {
61 printf ("!! Caught signal %d, launching gdb\n", sig); 62 printf ("!! Caught signal %d, launching gdb\n", sig);
62 63
63 if (g_crashCatcherActive) 64 if (IsCrashCatcherActive)
64 { 65 {
65 printf ("Caught signal while crash catcher is active! Execution cannot continue.\n"); 66 printf ("Caught signal while crash catcher is active! Execution cannot continue.\n");
66 finalAbort(); 67 FinalAbort();
67 } 68 }
68 69
69 const pid_t pid = getpid(); 70 pid_t const pid (getpid());
70 QProcess proc; 71 QProcess proc;
71 QTemporaryFile commandsFile; 72 QTemporaryFile commandsFile;
72 73
73 g_crashCatcherActive = true; 74 IsCrashCatcherActive = true;
74 75
75 if (commandsFile.open()) 76 if (commandsFile.open())
76 { 77 {
77 commandsFile.write (format ("attach %1\n", pid).toLocal8Bit()); 78 commandsFile.write (format ("attach %1\n", pid).toLocal8Bit());
78 commandsFile.write (QString ("backtrace full\n").toLocal8Bit()); 79 commandsFile.write (QString ("backtrace full\n").toLocal8Bit());
89 #ifdef Q_OS_LINUX 90 #ifdef Q_OS_LINUX
90 prctl (PR_SET_PTRACER, proc.pid(), 0, 0, 0); 91 prctl (PR_SET_PTRACER, proc.pid(), 0, 0, 0);
91 #endif 92 #endif
92 93
93 proc.waitForFinished (1000); 94 proc.waitForFinished (1000);
94 QString output = QString (proc.readAllStandardOutput()); 95 QString output (proc.readAllStandardOutput());
95 QString err = QString (proc.readAllStandardError()); 96 QString err (proc.readAllStandardError());
96 QFile f (UNIXNAME "-crash.log"); 97 QFile f (UNIXNAME "-crash.log");
97 98
98 if (f.open (QIODevice::WriteOnly)) 99 if (f.open (QIODevice::WriteOnly))
99 { 100 {
100 fprint (f, format ("=== Program crashed with signal %1 ===\n\n%2" 101 fprint (f, format ("=== Program crashed with signal %1 ===\n\n%2"
101 "GDB stdout:\n%3\n" 102 "GDB stdout:\n%3\nGDB stderr:\n%4\n", sig,
102 "GDB stderr:\n%4\n", 103 (not AssertionFailureText.isEmpty()) ? AssertionFailureText + "\n\n" : "",
103 sig, (not g_assertionFailure.isEmpty()) ? g_assertionFailure + "\n\n" : "", output, err)); 104 output, err));
104 f.close(); 105 f.close();
105 } 106 }
106 107
107 if (g_assertionFailure.isEmpty()) 108 if (not AssertionFailureText.isEmpty())
108 { 109 printf ("Assertion failed: \"%s\".\n", qPrintable (AssertionFailureText));
109 printf ("Crashlog written to " UNIXNAME "-crash.log. Aborting.\n");
110 }
111 else
112 {
113 printf ("Assertion failed: \"%s\". Backtrace written to " UNIXNAME "-crash.log.\n",
114 qPrintable (g_assertionFailure));
115 }
116 110
117 finalAbort(); 111 printf ("Backtrace written to " UNIXNAME "-crash.log. Aborting.\n");
112 FinalAbort();
118 } 113 }
119 114
115 // -------------------------------------------------------------------------------------------------
120 // 116 //
121 // Initializes the crash catcher. 117 // Initializes the crash catcher.
122 // 118 //
123 void initCrashCatcher() 119 void InitCrashCatcher()
124 { 120 {
125 struct sigaction sighandler; 121 struct sigaction sighandler;
126 sighandler.sa_handler = &handleCrash; 122 sighandler.sa_handler = &HandleCrash;
127 sighandler.sa_flags = 0; 123 sighandler.sa_flags = 0;
128 sigemptyset (&sighandler.sa_mask); 124 sigemptyset (&sighandler.sa_mask);
129 125
130 for (int sig : g_signalsToCatch) 126 for (int sig : SignalsToCatch)
131 { 127 {
132 if (sigaction (sig, &sighandler, null) == -1) 128 if (sigaction (sig, &sighandler, null) == -1)
133 { 129 {
134 fprint (stderr, "Couldn't set signal handler %1: %2", sig, strerror (errno)); 130 fprint (stderr, "Couldn't set signal handler %1: %2", sig, strerror (errno));
135 g_signalsToCatch.removeOne (sig); 131 SignalsToCatch.removeOne (sig);
136 } 132 }
137 } 133 }
138 134
139 print ("Crash catcher hooked to signals: %1\n", g_signalsToCatch); 135 print ("Crash catcher hooked to signals: %1\n", SignalsToCatch);
140 } 136 }
141 137
142 #endif // #ifdef __unix__ 138 #endif // #ifdef __unix__
143 139
144 // ============================================================================= 140 // -------------------------------------------------------------------------------------------------
145 // 141 //
146 // This function must be readily available in both Windows and Linux. We display 142 // This function catches an assertion failure. It must be readily available in both Windows and
147 // the bomb box straight in Windows while in Linux we let abort() trigger the 143 // Linux. We display the bomb box straight in Windows while in Linux we let abort() trigger
148 // signal handler, which will cause the usual bomb box with GDB diagnostics. 144 // the signal handler, which will cause the usual bomb box with GDB diagnostics. Said prompt will
149 // Said prompt will embed the assertion failure information. 145 // embed the assertion failure information.
150 // 146 //
151 void assertionFailure (const char* file, int line, const char* funcname, const char* expr) 147 void assertionFailure (const char* file, int line, const char* funcname, const char* expr)
152 { 148 {
153 #ifdef __unix__ 149 #ifdef __unix__
154 g_assertionFailure = format ("%1:%2: %3: %4", file, line, funcname, expr); 150 AssertionFailureText = format ("%1:%2: %3: %4", file, line, funcname, expr);
155 #else 151 #else
156 bombBox (format ( 152 bombBox (format (
157 "<p><b>File</b>: <tt>%1</tt><br />" 153 "<p><b>File</b>: <tt>%1</tt><br />"
158 "<b>Line</b>: <tt>%2</tt><br />" 154 "<b>Line</b>: <tt>%2</tt><br />"
159 "<b>Function:</b> <tt>%3</tt></p>" 155 "<b>Function:</b> <tt>%3</tt></p>"

mercurial