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