Bug 1728955: part 5) Add missing `// static` comment to `nsClipboard::CreateNativeDat...
[gecko.git] / toolkit / xre / nsSigHandlers.cpp
blobf67e1c0e1352058c442c65696c083d4924e67996
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/. */
6 /*
7 * This module is supposed to abstract signal handling away from the other
8 * platforms that do not support it.
9 */
11 #include "nsSigHandlers.h"
13 #ifdef XP_UNIX
15 # include <signal.h>
16 # include <stdio.h>
17 # include <string.h>
18 # include "prthread.h"
19 # include "prenv.h"
20 # include "nsDebug.h"
21 # include "nsXULAppAPI.h"
23 # if defined(LINUX)
24 # include <sys/time.h>
25 # include <sys/resource.h>
26 # include <unistd.h>
27 # include <stdlib.h> // atoi
28 # include <sys/prctl.h>
29 # ifndef ANDROID // no Android impl
30 # include <ucontext.h>
31 # endif
32 # endif
34 # if defined(SOLARIS)
35 # include <sys/resource.h>
36 # include <ucontext.h>
37 # endif
39 // Note: some tests manipulate this value.
40 unsigned int _gdb_sleep_duration = 300;
42 # if defined(LINUX) && !defined(ANDROID) && defined(DEBUG) && \
43 (defined(__i386) || defined(__x86_64) || defined(PPC))
44 # define CRAWL_STACK_ON_SIGSEGV
45 # endif
47 # ifndef PR_SET_PTRACER
48 # define PR_SET_PTRACER 0x59616d61
49 # endif
50 # ifndef PR_SET_PTRACER_ANY
51 # define PR_SET_PTRACER_ANY ((unsigned long)-1)
52 # endif
54 # if defined(CRAWL_STACK_ON_SIGSEGV)
56 # include <unistd.h>
57 # include "nsISupportsUtils.h"
58 # include "mozilla/Attributes.h"
59 # include "mozilla/StackWalk.h"
61 static const char* gProgname = "huh?";
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;
67 extern "C" {
69 static void PrintStackFrame(uint32_t aFrameNumber, void* aPC, void* aSP,
70 void* aClosure) {
71 char buf[1024];
72 MozCodeAddressDetails details;
74 MozDescribeCodeAddress(aPC, &details);
75 MozFormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
76 fprintf(stdout, "%s\n", buf);
77 fflush(stdout);
81 void common_crap_handler(int signum, const void* aFirstFramePC) {
82 printf("\nProgram %s (pid = %d) received signal %d.\n", gProgname, getpid(),
83 signum);
85 printf("Stack:\n");
86 MozStackWalk(PrintStackFrame, aFirstFramePC, /* maxFrames */ 0, nullptr);
88 printf("Sleeping for %d seconds.\n", _gdb_sleep_duration);
89 printf("Type 'gdb %s %d' to attach your debugger to this thread.\n",
90 gProgname, getpid());
92 // Allow us to be ptraced by gdb on Linux with Yama restrictions enabled.
93 prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY);
95 sleep(_gdb_sleep_duration);
97 printf("Done sleeping...\n");
99 _exit(signum);
102 MOZ_NEVER_INLINE void ah_crap_handler(int signum) {
103 common_crap_handler(signum, CallerPC());
106 MOZ_NEVER_INLINE void child_ah_crap_handler(int signum) {
107 if (!getenv("MOZ_DONT_UNBLOCK_PARENT_ON_CHILD_CRASH"))
108 close(kClientChannelFd);
109 common_crap_handler(signum, CallerPC());
112 # endif // CRAWL_STACK_ON_SIGSEGV
114 # ifdef MOZ_WIDGET_GTK
115 // Need this include for version test below.
116 # include <glib.h>
117 # endif
119 # if defined(MOZ_WIDGET_GTK) && \
120 (GLIB_MAJOR_VERSION > 2 || \
121 (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6))
123 static GLogFunc orig_log_func = nullptr;
125 extern "C" {
126 static void my_glib_log_func(const gchar* log_domain, GLogLevelFlags log_level,
127 const gchar* message, gpointer user_data);
130 /* static */ void my_glib_log_func(const gchar* log_domain,
131 GLogLevelFlags log_level,
132 const gchar* message, gpointer user_data) {
133 if (log_level &
134 (G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION)) {
135 NS_DebugBreak(NS_DEBUG_ASSERTION, message, "glib assertion", __FILE__,
136 __LINE__);
137 } else if (log_level & (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING)) {
138 NS_DebugBreak(NS_DEBUG_WARNING, message, "glib warning", __FILE__,
139 __LINE__);
142 orig_log_func(log_domain, log_level, message, nullptr);
145 # endif
147 # ifdef SA_SIGINFO
148 static void fpehandler(int signum, siginfo_t* si, void* context) {
149 /* Integer divide by zero or integer overflow. */
150 /* Note: FPE_INTOVF is ignored on Intel, PowerPC and SPARC systems. */
151 if (si->si_code == FPE_INTDIV || si->si_code == FPE_INTOVF) {
152 NS_DebugBreak(NS_DEBUG_ABORT, "Divide by zero", nullptr, __FILE__,
153 __LINE__);
156 # ifdef XP_MACOSX
157 # if defined(__i386__) || defined(__amd64__)
158 ucontext_t* uc = (ucontext_t*)context;
160 _STRUCT_FP_CONTROL* ctrl = &uc->uc_mcontext->__fs.__fpu_fcw;
161 ctrl->__invalid = ctrl->__denorm = ctrl->__zdiv = ctrl->__ovrfl =
162 ctrl->__undfl = ctrl->__precis = 1;
164 _STRUCT_FP_STATUS* status = &uc->uc_mcontext->__fs.__fpu_fsw;
165 status->__invalid = status->__denorm = status->__zdiv = status->__ovrfl =
166 status->__undfl = status->__precis = status->__stkflt =
167 status->__errsumm = 0;
169 uint32_t* mxcsr = &uc->uc_mcontext->__fs.__fpu_mxcsr;
170 *mxcsr |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
171 *mxcsr &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */
172 # endif
173 # endif
174 # if defined(LINUX) && !defined(ANDROID)
176 # if defined(__i386__)
177 ucontext_t* uc = (ucontext_t*)context;
179 * It seems that we have no access to mxcsr on Linux. libc
180 * seems to be translating cw/sw to mxcsr.
182 unsigned long int* cw = &uc->uc_mcontext.fpregs->cw;
183 *cw |= FPU_EXCEPTION_MASK;
185 unsigned long int* sw = &uc->uc_mcontext.fpregs->sw;
186 *sw &= ~FPU_STATUS_FLAGS;
187 # endif
188 # if defined(__amd64__)
189 ucontext_t* uc = (ucontext_t*)context;
191 uint16_t* cw = &uc->uc_mcontext.fpregs->cwd;
192 *cw |= FPU_EXCEPTION_MASK;
194 uint16_t* sw = &uc->uc_mcontext.fpregs->swd;
195 *sw &= ~FPU_STATUS_FLAGS;
197 uint32_t* mxcsr = &uc->uc_mcontext.fpregs->mxcsr;
198 *mxcsr |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
199 *mxcsr &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */
200 # endif
201 # endif
202 # ifdef SOLARIS
203 ucontext_t* uc = (ucontext_t*)context;
205 # if defined(__i386)
206 uint32_t* cw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0];
207 *cw |= FPU_EXCEPTION_MASK;
209 uint32_t* sw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1];
210 *sw &= ~FPU_STATUS_FLAGS;
212 /* address of the instruction that caused the exception */
213 uint32_t* ip = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[3];
214 uc->uc_mcontext.gregs[REG_PC] = *ip;
215 # endif
216 # if defined(__amd64__)
217 uint16_t* cw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw;
218 *cw |= FPU_EXCEPTION_MASK;
220 uint16_t* sw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw;
221 *sw &= ~FPU_STATUS_FLAGS;
223 uint32_t* mxcsr = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr;
224 *mxcsr |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
225 *mxcsr &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */
226 # endif
227 # endif
229 # endif
231 void InstallSignalHandlers(const char* aProgname) {
232 # if defined(CRAWL_STACK_ON_SIGSEGV)
233 if (aProgname) {
234 const char* tmp = strdup(aProgname);
235 if (tmp) {
236 gProgname = tmp;
239 # endif // CRAWL_STACK_ON_SIGSEGV
241 const char* gdbSleep = PR_GetEnv("MOZ_GDB_SLEEP");
242 if (gdbSleep && *gdbSleep) {
243 unsigned int s;
244 if (1 == sscanf(gdbSleep, "%u", &s)) {
245 _gdb_sleep_duration = s;
249 # if defined(CRAWL_STACK_ON_SIGSEGV)
250 if (!getenv("XRE_NO_WINDOWS_CRASH_DIALOG")) {
251 void (*crap_handler)(int) = GeckoProcessType_Default != XRE_GetProcessType()
252 ? child_ah_crap_handler
253 : ah_crap_handler;
254 signal(SIGSEGV, crap_handler);
255 signal(SIGILL, crap_handler);
256 signal(SIGABRT, crap_handler);
258 # endif // CRAWL_STACK_ON_SIGSEGV
260 # ifdef SA_SIGINFO
261 /* Install a handler for floating point exceptions and disable them if they
262 * occur. */
263 struct sigaction sa, osa;
264 sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
265 sa.sa_sigaction = fpehandler;
266 sigemptyset(&sa.sa_mask);
267 sigaction(SIGFPE, &sa, &osa);
268 # endif
270 if (!XRE_IsParentProcess()) {
272 * If the user is debugging a Gecko parent process in gdb and hits ^C to
273 * suspend, a SIGINT signal will be sent to the child. We ignore this signal
274 * so the child isn't killed.
276 signal(SIGINT, SIG_IGN);
279 # if defined(DEBUG) && defined(LINUX)
280 const char* memLimit = PR_GetEnv("MOZ_MEM_LIMIT");
281 if (memLimit && *memLimit) {
282 long m = atoi(memLimit);
283 m *= (1024 * 1024);
284 struct rlimit r;
285 r.rlim_cur = m;
286 r.rlim_max = m;
287 setrlimit(RLIMIT_AS, &r);
289 # endif
291 # if defined(MOZ_WIDGET_GTK) && \
292 (GLIB_MAJOR_VERSION > 2 || \
293 (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6))
294 const char* assertString = PR_GetEnv("XPCOM_DEBUG_BREAK");
295 if (assertString &&
296 (!strcmp(assertString, "suspend") || !strcmp(assertString, "stack") ||
297 !strcmp(assertString, "abort") || !strcmp(assertString, "trap") ||
298 !strcmp(assertString, "break"))) {
299 // Override the default glib logging function so we get stacks for it too.
300 orig_log_func = g_log_set_default_handler(my_glib_log_func, nullptr);
302 # endif
305 #elif XP_WIN
307 # include <windows.h>
309 # ifdef _M_IX86
311 * WinNT.h prior to SDK7 does not expose the structure of the ExtendedRegisters
312 * for ia86. We known that MxCsr is at offset 0x18 and is a DWORD.
314 # define MXCSR(ctx) (*(DWORD*)(((BYTE*)(ctx)->ExtendedRegisters) + 0x18))
315 # endif
317 # ifdef _M_X64
318 # define MXCSR(ctx) (ctx)->MxCsr
319 # endif
321 # if defined(_M_IX86) || defined(_M_X64)
323 # ifdef _M_X64
324 # define X87CW(ctx) (ctx)->FltSave.ControlWord
325 # define X87SW(ctx) (ctx)->FltSave.StatusWord
326 # else
327 # define X87CW(ctx) (ctx)->FloatSave.ControlWord
328 # define X87SW(ctx) (ctx)->FloatSave.StatusWord
329 # endif
331 static LPTOP_LEVEL_EXCEPTION_FILTER gFPEPreviousFilter;
333 LONG __stdcall FpeHandler(PEXCEPTION_POINTERS pe) {
334 PEXCEPTION_RECORD e = (PEXCEPTION_RECORD)pe->ExceptionRecord;
335 CONTEXT* c = (CONTEXT*)pe->ContextRecord;
337 switch (e->ExceptionCode) {
338 case STATUS_FLOAT_DENORMAL_OPERAND:
339 case STATUS_FLOAT_DIVIDE_BY_ZERO:
340 case STATUS_FLOAT_INEXACT_RESULT:
341 case STATUS_FLOAT_INVALID_OPERATION:
342 case STATUS_FLOAT_OVERFLOW:
343 case STATUS_FLOAT_STACK_CHECK:
344 case STATUS_FLOAT_UNDERFLOW:
345 case STATUS_FLOAT_MULTIPLE_FAULTS:
346 case STATUS_FLOAT_MULTIPLE_TRAPS:
347 X87CW(c) |= FPU_EXCEPTION_MASK; /* disable all FPU exceptions */
348 X87SW(c) &= ~FPU_STATUS_FLAGS; /* clear all pending FPU exceptions */
349 # ifdef _M_IX86
350 if (c->ContextFlags & CONTEXT_EXTENDED_REGISTERS) {
351 # endif
352 MXCSR(c) |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
353 MXCSR(c) &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */
354 # ifdef _M_IX86
356 # endif
357 return EXCEPTION_CONTINUE_EXECUTION;
359 LONG action = EXCEPTION_CONTINUE_SEARCH;
360 if (gFPEPreviousFilter) action = gFPEPreviousFilter(pe);
362 return action;
365 void InstallSignalHandlers(const char* aProgname) {
366 gFPEPreviousFilter = SetUnhandledExceptionFilter(FpeHandler);
369 # else
371 void InstallSignalHandlers(const char* aProgname) {}
373 # endif
375 #else
376 # error No signal handling implementation for this platform.
377 #endif