Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /*
7 : * This module is supposed to abstract signal handling away from the other
8 : * platforms that do not support it.
9 : */
10 :
11 : #include "nsSigHandlers.h"
12 :
13 : #ifdef XP_UNIX
14 :
15 : #include <signal.h>
16 : #include <stdio.h>
17 : #include <string.h>
18 : #include "prthread.h"
19 : #include "plstr.h"
20 : #include "prenv.h"
21 : #include "nsDebug.h"
22 : #include "nsXULAppAPI.h"
23 :
24 : #if defined(LINUX)
25 : #include <sys/time.h>
26 : #include <sys/resource.h>
27 : #include <unistd.h>
28 : #include <stdlib.h> // atoi
29 : #include <sys/prctl.h>
30 : #ifndef ANDROID // no Android impl
31 : # include <ucontext.h>
32 : #endif
33 : #endif
34 :
35 : #if defined(SOLARIS)
36 : #include <sys/resource.h>
37 : #include <ucontext.h>
38 : #endif
39 :
40 : static const char* gProgname = "huh?";
41 :
42 : // Note: some tests manipulate this value.
43 : unsigned int _gdb_sleep_duration = 300;
44 :
45 : #if defined(LINUX) && defined(DEBUG) && \
46 : (defined(__i386) || defined(__x86_64) || defined(PPC))
47 : #define CRAWL_STACK_ON_SIGSEGV
48 : #endif
49 :
50 : #ifndef PR_SET_PTRACER
51 : #define PR_SET_PTRACER 0x59616d61
52 : #endif
53 : #ifndef PR_SET_PTRACER_ANY
54 : #define PR_SET_PTRACER_ANY ((unsigned long)-1)
55 : #endif
56 :
57 : #if defined(CRAWL_STACK_ON_SIGSEGV)
58 :
59 : #include <unistd.h>
60 : #include "nsISupportsUtils.h"
61 : #include "mozilla/StackWalk.h"
62 :
63 : // NB: keep me up to date with the same variable in
64 : // ipc/chromium/chrome/common/ipc_channel_posix.cc
65 : static const int kClientChannelFd = 3;
66 :
67 : extern "C" {
68 :
69 0 : static void PrintStackFrame(uint32_t aFrameNumber, void *aPC, void *aSP,
70 : void *aClosure)
71 : {
72 : char buf[1024];
73 : MozCodeAddressDetails details;
74 :
75 0 : MozDescribeCodeAddress(aPC, &details);
76 0 : MozFormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
77 0 : fprintf(stdout, "%s\n", buf);
78 0 : fflush(stdout);
79 0 : }
80 :
81 : }
82 :
83 : void
84 0 : ah_crap_handler(int signum)
85 : {
86 0 : printf("\nProgram %s (pid = %d) received signal %d.\n",
87 : gProgname,
88 : getpid(),
89 0 : signum);
90 :
91 0 : printf("Stack:\n");
92 : MozStackWalk(PrintStackFrame, /* skipFrames */ 2, /* maxFrames */ 0,
93 0 : nullptr, 0, nullptr);
94 :
95 0 : printf("Sleeping for %d seconds.\n",_gdb_sleep_duration);
96 0 : printf("Type 'gdb %s %d' to attach your debugger to this thread.\n",
97 : gProgname,
98 0 : getpid());
99 :
100 : // Allow us to be ptraced by gdb on Linux with Yama restrictions enabled.
101 0 : prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY);
102 :
103 0 : sleep(_gdb_sleep_duration);
104 :
105 0 : printf("Done sleeping...\n");
106 :
107 0 : _exit(signum);
108 : }
109 :
110 : void
111 0 : child_ah_crap_handler(int signum)
112 : {
113 0 : if (!getenv("MOZ_DONT_UNBLOCK_PARENT_ON_CHILD_CRASH"))
114 0 : close(kClientChannelFd);
115 0 : ah_crap_handler(signum);
116 0 : }
117 :
118 : #endif // CRAWL_STACK_ON_SIGSEGV
119 :
120 : #ifdef MOZ_WIDGET_GTK
121 : // Need this include for version test below.
122 : #include <glib.h>
123 : #endif
124 :
125 : #if defined(MOZ_WIDGET_GTK) && (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6))
126 :
127 : static GLogFunc orig_log_func = nullptr;
128 :
129 : extern "C" {
130 : static void
131 : my_glib_log_func(const gchar *log_domain, GLogLevelFlags log_level,
132 : const gchar *message, gpointer user_data);
133 : }
134 :
135 : /* static */ void
136 0 : my_glib_log_func(const gchar *log_domain, GLogLevelFlags log_level,
137 : const gchar *message, gpointer user_data)
138 : {
139 0 : if (log_level & (G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION)) {
140 0 : NS_DebugBreak(NS_DEBUG_ASSERTION, message, "glib assertion", __FILE__, __LINE__);
141 0 : } else if (log_level & (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING)) {
142 0 : NS_DebugBreak(NS_DEBUG_WARNING, message, "glib warning", __FILE__, __LINE__);
143 : }
144 :
145 0 : orig_log_func(log_domain, log_level, message, nullptr);
146 0 : }
147 :
148 : #endif
149 :
150 : #ifdef SA_SIGINFO
151 0 : static void fpehandler(int signum, siginfo_t *si, void *context)
152 : {
153 : /* Integer divide by zero or integer overflow. */
154 : /* Note: FPE_INTOVF is ignored on Intel, PowerPC and SPARC systems. */
155 0 : if (si->si_code == FPE_INTDIV || si->si_code == FPE_INTOVF) {
156 0 : NS_DebugBreak(NS_DEBUG_ABORT, "Divide by zero", nullptr, __FILE__, __LINE__);
157 : }
158 :
159 : #ifdef XP_MACOSX
160 : ucontext_t *uc = (ucontext_t *)context;
161 :
162 : #if defined(__i386__) || defined(__amd64__)
163 : _STRUCT_FP_CONTROL *ctrl = &uc->uc_mcontext->__fs.__fpu_fcw;
164 : ctrl->__invalid = ctrl->__denorm = ctrl->__zdiv = ctrl->__ovrfl = ctrl->__undfl = ctrl->__precis = 1;
165 :
166 : _STRUCT_FP_STATUS *status = &uc->uc_mcontext->__fs.__fpu_fsw;
167 : status->__invalid = status->__denorm = status->__zdiv = status->__ovrfl = status->__undfl =
168 : status->__precis = status->__stkflt = status->__errsumm = 0;
169 :
170 : uint32_t *mxcsr = &uc->uc_mcontext->__fs.__fpu_mxcsr;
171 : *mxcsr |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
172 : *mxcsr &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */
173 : #endif
174 : #endif
175 : #if defined(LINUX) && !defined(ANDROID)
176 0 : ucontext_t *uc = (ucontext_t *)context;
177 :
178 : #if defined(__i386__)
179 : /*
180 : * It seems that we have no access to mxcsr on Linux. libc
181 : * seems to be translating cw/sw to mxcsr.
182 : */
183 : unsigned long int *cw = &uc->uc_mcontext.fpregs->cw;
184 : *cw |= FPU_EXCEPTION_MASK;
185 :
186 : unsigned long int *sw = &uc->uc_mcontext.fpregs->sw;
187 : *sw &= ~FPU_STATUS_FLAGS;
188 : #endif
189 : #if defined(__amd64__)
190 0 : uint16_t *cw = &uc->uc_mcontext.fpregs->cwd;
191 0 : *cw |= FPU_EXCEPTION_MASK;
192 :
193 0 : uint16_t *sw = &uc->uc_mcontext.fpregs->swd;
194 0 : *sw &= ~FPU_STATUS_FLAGS;
195 :
196 0 : uint32_t *mxcsr = &uc->uc_mcontext.fpregs->mxcsr;
197 0 : *mxcsr |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
198 0 : *mxcsr &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */
199 : #endif
200 : #endif
201 : #ifdef SOLARIS
202 : ucontext_t *uc = (ucontext_t *)context;
203 :
204 : #if defined(__i386)
205 : uint32_t *cw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0];
206 : *cw |= FPU_EXCEPTION_MASK;
207 :
208 : uint32_t *sw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1];
209 : *sw &= ~FPU_STATUS_FLAGS;
210 :
211 : /* address of the instruction that caused the exception */
212 : uint32_t *ip = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[3];
213 : uc->uc_mcontext.gregs[REG_PC] = *ip;
214 : #endif
215 : #if defined(__amd64__)
216 : uint16_t *cw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw;
217 : *cw |= FPU_EXCEPTION_MASK;
218 :
219 : uint16_t *sw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw;
220 : *sw &= ~FPU_STATUS_FLAGS;
221 :
222 : uint32_t *mxcsr = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr;
223 : *mxcsr |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
224 : *mxcsr &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */
225 : #endif
226 : #endif
227 0 : }
228 : #endif
229 :
230 3 : void InstallSignalHandlers(const char *aProgname)
231 : {
232 3 : const char* tmp = PL_strdup(aProgname);
233 3 : if (tmp) {
234 3 : gProgname = tmp;
235 : }
236 :
237 3 : const char *gdbSleep = PR_GetEnv("MOZ_GDB_SLEEP");
238 3 : if (gdbSleep && *gdbSleep)
239 : {
240 : unsigned int s;
241 0 : if (1 == sscanf(gdbSleep, "%u", &s)) {
242 0 : _gdb_sleep_duration = s;
243 : }
244 : }
245 :
246 : #if defined(CRAWL_STACK_ON_SIGSEGV)
247 3 : if (!getenv("XRE_NO_WINDOWS_CRASH_DIALOG")) {
248 : void (*crap_handler)(int) =
249 3 : GeckoProcessType_Default != XRE_GetProcessType() ?
250 : child_ah_crap_handler :
251 3 : ah_crap_handler;
252 3 : signal(SIGSEGV, crap_handler);
253 3 : signal(SIGILL, crap_handler);
254 3 : signal(SIGABRT, crap_handler);
255 : }
256 : #endif // CRAWL_STACK_ON_SIGSEGV
257 :
258 : #ifdef SA_SIGINFO
259 : /* Install a handler for floating point exceptions and disable them if they occur. */
260 : struct sigaction sa, osa;
261 3 : sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
262 3 : sa.sa_sigaction = fpehandler;
263 3 : sigemptyset(&sa.sa_mask);
264 3 : sigaction(SIGFPE, &sa, &osa);
265 : #endif
266 :
267 3 : if (!XRE_IsParentProcess()) {
268 : /*
269 : * If the user is debugging a Gecko parent process in gdb and hits ^C to
270 : * suspend, a SIGINT signal will be sent to the child. We ignore this signal
271 : * so the child isn't killed.
272 : */
273 2 : signal(SIGINT, SIG_IGN);
274 : }
275 :
276 : #if defined(DEBUG) && defined(LINUX)
277 3 : const char *memLimit = PR_GetEnv("MOZ_MEM_LIMIT");
278 3 : if (memLimit && *memLimit)
279 : {
280 0 : long m = atoi(memLimit);
281 0 : m *= (1024*1024);
282 : struct rlimit r;
283 0 : r.rlim_cur = m;
284 0 : r.rlim_max = m;
285 0 : setrlimit(RLIMIT_AS, &r);
286 : }
287 : #endif
288 :
289 : #if defined(SOLARIS)
290 : #define NOFILES 512
291 :
292 : // Boost Solaris file descriptors
293 : {
294 : struct rlimit rl;
295 :
296 : if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
297 :
298 : if (rl.rlim_cur < NOFILES) {
299 : rl.rlim_cur = NOFILES;
300 :
301 : if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
302 : perror("setrlimit(RLIMIT_NOFILE)");
303 : fprintf(stderr, "Cannot exceed hard limit for open files");
304 : }
305 : #if defined(DEBUG)
306 : if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
307 : printf("File descriptors set to %d\n", rl.rlim_cur);
308 : #endif //DEBUG
309 : }
310 : }
311 : #endif //SOLARIS
312 :
313 : #if defined(MOZ_WIDGET_GTK) && (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6))
314 3 : const char *assertString = PR_GetEnv("XPCOM_DEBUG_BREAK");
315 3 : if (assertString &&
316 0 : (!strcmp(assertString, "suspend") ||
317 0 : !strcmp(assertString, "stack") ||
318 0 : !strcmp(assertString, "abort") ||
319 0 : !strcmp(assertString, "trap") ||
320 0 : !strcmp(assertString, "break"))) {
321 : // Override the default glib logging function so we get stacks for it too.
322 0 : orig_log_func = g_log_set_default_handler(my_glib_log_func, nullptr);
323 : }
324 : #endif
325 3 : }
326 :
327 : #elif XP_WIN
328 :
329 : #include <windows.h>
330 :
331 : #ifdef _M_IX86
332 : /*
333 : * WinNT.h prior to SDK7 does not expose the structure of the ExtendedRegisters for ia86.
334 : * We known that MxCsr is at offset 0x18 and is a DWORD.
335 : */
336 : #define MXCSR(ctx) (*(DWORD *)(((BYTE *)(ctx)->ExtendedRegisters) + 0x18))
337 : #endif
338 :
339 : #ifdef _M_X64
340 : #define MXCSR(ctx) (ctx)->MxCsr
341 : #endif
342 :
343 : #if defined(_M_IX86) || defined(_M_X64)
344 :
345 : #ifdef _M_X64
346 : #define X87CW(ctx) (ctx)->FltSave.ControlWord
347 : #define X87SW(ctx) (ctx)->FltSave.StatusWord
348 : #else
349 : #define X87CW(ctx) (ctx)->FloatSave.ControlWord
350 : #define X87SW(ctx) (ctx)->FloatSave.StatusWord
351 : #endif
352 :
353 : static LPTOP_LEVEL_EXCEPTION_FILTER gFPEPreviousFilter;
354 :
355 : LONG __stdcall FpeHandler(PEXCEPTION_POINTERS pe)
356 : {
357 : PEXCEPTION_RECORD e = (PEXCEPTION_RECORD)pe->ExceptionRecord;
358 : CONTEXT *c = (CONTEXT*)pe->ContextRecord;
359 :
360 : switch (e->ExceptionCode) {
361 : case STATUS_FLOAT_DENORMAL_OPERAND:
362 : case STATUS_FLOAT_DIVIDE_BY_ZERO:
363 : case STATUS_FLOAT_INEXACT_RESULT:
364 : case STATUS_FLOAT_INVALID_OPERATION:
365 : case STATUS_FLOAT_OVERFLOW:
366 : case STATUS_FLOAT_STACK_CHECK:
367 : case STATUS_FLOAT_UNDERFLOW:
368 : case STATUS_FLOAT_MULTIPLE_FAULTS:
369 : case STATUS_FLOAT_MULTIPLE_TRAPS:
370 : X87CW(c) |= FPU_EXCEPTION_MASK; /* disable all FPU exceptions */
371 : X87SW(c) &= ~FPU_STATUS_FLAGS; /* clear all pending FPU exceptions */
372 : #ifdef _M_IX86
373 : if (c->ContextFlags & CONTEXT_EXTENDED_REGISTERS) {
374 : #endif
375 : MXCSR(c) |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
376 : MXCSR(c) &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */
377 : #ifdef _M_IX86
378 : }
379 : #endif
380 : return EXCEPTION_CONTINUE_EXECUTION;
381 : }
382 : LONG action = EXCEPTION_CONTINUE_SEARCH;
383 : if (gFPEPreviousFilter)
384 : action = gFPEPreviousFilter(pe);
385 :
386 : return action;
387 : }
388 :
389 : void InstallSignalHandlers(const char *aProgname)
390 : {
391 : gFPEPreviousFilter = SetUnhandledExceptionFilter(FpeHandler);
392 : }
393 :
394 : #else
395 :
396 : void InstallSignalHandlers(const char *aProgname)
397 : {
398 : }
399 :
400 : #endif
401 :
402 : #else
403 : #error No signal handling implementation for this platform.
404 : #endif
|