toolkit/xre/nsSigHandlers.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 "plstr.h"
    20 #include "prenv.h"
    21 #include "nsDebug.h"
    22 #include "nsXULAppAPI.h"
    24 #if defined(LINUX)
    25 #include <sys/time.h>
    26 #include <sys/resource.h>
    27 #include <unistd.h>
    28 #include <stdlib.h> // atoi
    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 static char _progname[1024] = "huh?";
    40 static unsigned int _gdb_sleep_duration = 300;
    42 // NB: keep me up to date with the same variable in
    43 // ipc/chromium/chrome/common/ipc_channel_posix.cc
    44 static const int kClientChannelFd = 3;
    46 #if defined(LINUX) && defined(DEBUG) && \
    47       (defined(__i386) || defined(__x86_64) || defined(PPC))
    48 #define CRAWL_STACK_ON_SIGSEGV
    49 #endif
    51 #if defined(CRAWL_STACK_ON_SIGSEGV)
    53 #include <unistd.h>
    54 #include "nsISupportsUtils.h"
    55 #include "nsStackWalk.h"
    57 extern "C" {
    59 static void PrintStackFrame(void *aPC, void *aSP, void *aClosure)
    60 {
    61   char buf[1024];
    62   nsCodeAddressDetails details;
    64   NS_DescribeCodeAddress(aPC, &details);
    65   NS_FormatCodeAddressDetails(aPC, &details, buf, sizeof(buf));
    66   fputs(buf, stdout);
    67 }
    69 }
    71 void
    72 ah_crap_handler(int signum)
    73 {
    74   printf("\nProgram %s (pid = %d) received signal %d.\n",
    75          _progname,
    76          getpid(),
    77          signum);
    79   printf("Stack:\n");
    80   NS_StackWalk(PrintStackFrame, /* skipFrames */ 2, /* maxFrames */ 0,
    81                nullptr, 0, nullptr);
    83   printf("Sleeping for %d seconds.\n",_gdb_sleep_duration);
    84   printf("Type 'gdb %s %d' to attach your debugger to this thread.\n",
    85          _progname,
    86          getpid());
    88   sleep(_gdb_sleep_duration);
    90   printf("Done sleeping...\n");
    92   _exit(signum);
    93 }
    95 void
    96 child_ah_crap_handler(int signum)
    97 {
    98   if (!getenv("MOZ_DONT_UNBLOCK_PARENT_ON_CHILD_CRASH"))
    99     close(kClientChannelFd);
   100   ah_crap_handler(signum);
   101 }
   103 #endif // CRAWL_STACK_ON_SIGSEGV
   105 #ifdef MOZ_WIDGET_GTK
   106 // Need this include for version test below.
   107 #include <glib.h>
   108 #endif
   110 #if defined(MOZ_WIDGET_GTK) && (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6))
   112 static GLogFunc orig_log_func = nullptr;
   114 extern "C" {
   115 static void
   116 my_glib_log_func(const gchar *log_domain, GLogLevelFlags log_level,
   117                  const gchar *message, gpointer user_data);
   118 }
   120 /* static */ void
   121 my_glib_log_func(const gchar *log_domain, GLogLevelFlags log_level,
   122                  const gchar *message, gpointer user_data)
   123 {
   124   if (log_level & (G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION)) {
   125     NS_DebugBreak(NS_DEBUG_ASSERTION, message, "glib assertion", __FILE__, __LINE__);
   126   } else if (log_level & (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING)) {
   127     NS_DebugBreak(NS_DEBUG_WARNING, message, "glib warning", __FILE__, __LINE__);
   128   }
   130   orig_log_func(log_domain, log_level, message, nullptr);
   131 }
   133 #endif
   135 #ifdef SA_SIGINFO
   136 static void fpehandler(int signum, siginfo_t *si, void *context)
   137 {
   138   /* Integer divide by zero or integer overflow. */
   139   /* Note: FPE_INTOVF is ignored on Intel, PowerPC and SPARC systems. */
   140   if (si->si_code == FPE_INTDIV || si->si_code == FPE_INTOVF) {
   141     NS_DebugBreak(NS_DEBUG_ABORT, "Divide by zero", nullptr, __FILE__, __LINE__);
   142   }
   144 #ifdef XP_MACOSX
   145   ucontext_t *uc = (ucontext_t *)context;
   147 #if defined(__i386__) || defined(__amd64__)
   148   _STRUCT_FP_CONTROL *ctrl = &uc->uc_mcontext->__fs.__fpu_fcw;
   149   ctrl->__invalid = ctrl->__denorm = ctrl->__zdiv = ctrl->__ovrfl = ctrl->__undfl = ctrl->__precis = 1;
   151   _STRUCT_FP_STATUS *status = &uc->uc_mcontext->__fs.__fpu_fsw;
   152   status->__invalid = status->__denorm = status->__zdiv = status->__ovrfl = status->__undfl =
   153     status->__precis = status->__stkflt = status->__errsumm = 0;
   155   __uint32_t *mxcsr = &uc->uc_mcontext->__fs.__fpu_mxcsr;
   156   *mxcsr |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
   157   *mxcsr &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */
   158 #endif
   159 #endif
   160 #if defined(LINUX) && !defined(ANDROID)
   161   ucontext_t *uc = (ucontext_t *)context;
   163 #if defined(__i386__)
   164   /*
   165    * It seems that we have no access to mxcsr on Linux. libc
   166    * seems to be translating cw/sw to mxcsr.
   167    */
   168   unsigned long int *cw = &uc->uc_mcontext.fpregs->cw;
   169   *cw |= FPU_EXCEPTION_MASK;
   171   unsigned long int *sw = &uc->uc_mcontext.fpregs->sw;
   172   *sw &= ~FPU_STATUS_FLAGS;
   173 #endif
   174 #if defined(__amd64__)
   175   __uint16_t *cw = &uc->uc_mcontext.fpregs->cwd;
   176   *cw |= FPU_EXCEPTION_MASK;
   178   __uint16_t *sw = &uc->uc_mcontext.fpregs->swd;
   179   *sw &= ~FPU_STATUS_FLAGS;
   181   __uint32_t *mxcsr = &uc->uc_mcontext.fpregs->mxcsr;
   182   *mxcsr |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
   183   *mxcsr &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */
   184 #endif
   185 #endif
   186 #ifdef SOLARIS
   187   ucontext_t *uc = (ucontext_t *)context;
   189 #if defined(__i386)
   190   uint32_t *cw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0];
   191   *cw |= FPU_EXCEPTION_MASK;
   193   uint32_t *sw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1];
   194   *sw &= ~FPU_STATUS_FLAGS;
   196   /* address of the instruction that caused the exception */
   197   uint32_t *ip = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[3];
   198   uc->uc_mcontext.gregs[REG_PC] = *ip;
   199 #endif
   200 #if defined(__amd64__)
   201   uint16_t *cw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw;
   202   *cw |= FPU_EXCEPTION_MASK;
   204   uint16_t *sw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw;
   205   *sw &= ~FPU_STATUS_FLAGS;
   207   uint32_t *mxcsr = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr;
   208   *mxcsr |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
   209   *mxcsr &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */
   210 #endif
   211 #endif
   212 }
   213 #endif
   215 void InstallSignalHandlers(const char *ProgramName)
   216 {
   217   PL_strncpy(_progname,ProgramName, (sizeof(_progname)-1) );
   219   const char *gdbSleep = PR_GetEnv("MOZ_GDB_SLEEP");
   220   if (gdbSleep && *gdbSleep)
   221   {
   222     unsigned int s;
   223     if (1 == sscanf(gdbSleep, "%u", &s)) {
   224       _gdb_sleep_duration = s;
   225     }
   226   }
   228 #if defined(CRAWL_STACK_ON_SIGSEGV)
   229   if (!getenv("XRE_NO_WINDOWS_CRASH_DIALOG")) {
   230     void (*crap_handler)(int) =
   231       GeckoProcessType_Default != XRE_GetProcessType() ?
   232           child_ah_crap_handler :
   233           ah_crap_handler;
   234     signal(SIGSEGV, crap_handler);
   235     signal(SIGILL, crap_handler);
   236     signal(SIGABRT, crap_handler);
   237   }
   238 #endif // CRAWL_STACK_ON_SIGSEGV
   240 #ifdef SA_SIGINFO
   241   /* Install a handler for floating point exceptions and disable them if they occur. */
   242   struct sigaction sa, osa;
   243   sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
   244   sa.sa_sigaction = fpehandler;
   245   sigemptyset(&sa.sa_mask);
   246   sigaction(SIGFPE, &sa, &osa);
   247 #endif
   249   if (XRE_GetProcessType() == GeckoProcessType_Content) {
   250     /*
   251      * If the user is debugging a Gecko parent process in gdb and hits ^C to
   252      * suspend, a SIGINT signal will be sent to the child. We ignore this signal
   253      * so the child isn't killed.
   254      */
   255     signal(SIGINT, SIG_IGN);
   256   }
   258 #if defined(DEBUG) && defined(LINUX)
   259   const char *memLimit = PR_GetEnv("MOZ_MEM_LIMIT");
   260   if (memLimit && *memLimit)
   261   {
   262     long m = atoi(memLimit);
   263     m *= (1024*1024);
   264     struct rlimit r;
   265     r.rlim_cur = m;
   266     r.rlim_max = m;
   267     setrlimit(RLIMIT_AS, &r);
   268   }
   269 #endif
   271 #if defined(SOLARIS)
   272 #define NOFILES 512
   274     // Boost Solaris file descriptors
   275     {
   276 	struct rlimit rl;
   278 	if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
   280 	    if (rl.rlim_cur < NOFILES) {
   281 		rl.rlim_cur = NOFILES;
   283 		if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
   284 		    perror("setrlimit(RLIMIT_NOFILE)");
   285 		    fprintf(stderr, "Cannot exceed hard limit for open files");
   286 		}
   287 #if defined(DEBUG)
   288 	    	if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
   289 		    printf("File descriptors set to %d\n", rl.rlim_cur);
   290 #endif //DEBUG
   291 	    }
   292     }
   293 #endif //SOLARIS
   295 #if defined(MOZ_WIDGET_GTK) && (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6))
   296   const char *assertString = PR_GetEnv("XPCOM_DEBUG_BREAK");
   297   if (assertString &&
   298       (!strcmp(assertString, "suspend") ||
   299        !strcmp(assertString, "stack") ||
   300        !strcmp(assertString, "abort") ||
   301        !strcmp(assertString, "trap") ||
   302        !strcmp(assertString, "break"))) {
   303     // Override the default glib logging function so we get stacks for it too.
   304     orig_log_func = g_log_set_default_handler(my_glib_log_func, nullptr);
   305   }
   306 #endif
   307 }
   309 #elif XP_WIN
   311 #include <windows.h>
   313 #ifdef _M_IX86
   314 /*
   315  * WinNT.h prior to SDK7 does not expose the structure of the ExtendedRegisters for ia86.
   316  * We known that MxCsr is at offset 0x18 and is a DWORD.
   317  */
   318 #define MXCSR(ctx) (*(DWORD *)(((BYTE *)(ctx)->ExtendedRegisters) + 0x18))
   319 #endif
   321 #ifdef _M_X64
   322 #define MXCSR(ctx) (ctx)->MxCsr
   323 #endif
   325 #if defined(_M_IX86) || defined(_M_X64)
   327 #ifdef _M_X64
   328 #define X87CW(ctx) (ctx)->FltSave.ControlWord
   329 #define X87SW(ctx) (ctx)->FltSave.StatusWord
   330 #else
   331 #define X87CW(ctx) (ctx)->FloatSave.ControlWord
   332 #define X87SW(ctx) (ctx)->FloatSave.StatusWord
   333 #endif
   335 /*
   336  * SSE traps raise these exception codes, which are defined in internal NT headers
   337  * but not winbase.h
   338  */
   339 #define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4
   340 #define STATUS_FLOAT_MULTIPLE_TRAPS  0xC00002B5
   342 static LPTOP_LEVEL_EXCEPTION_FILTER gFPEPreviousFilter;
   344 LONG __stdcall FpeHandler(PEXCEPTION_POINTERS pe)
   345 {
   346   PEXCEPTION_RECORD e = (PEXCEPTION_RECORD)pe->ExceptionRecord;
   347   CONTEXT *c = (CONTEXT*)pe->ContextRecord;
   349   switch (e->ExceptionCode) {
   350     case STATUS_FLOAT_DENORMAL_OPERAND:
   351     case STATUS_FLOAT_DIVIDE_BY_ZERO:
   352     case STATUS_FLOAT_INEXACT_RESULT:
   353     case STATUS_FLOAT_INVALID_OPERATION:
   354     case STATUS_FLOAT_OVERFLOW:
   355     case STATUS_FLOAT_STACK_CHECK:
   356     case STATUS_FLOAT_UNDERFLOW:
   357     case STATUS_FLOAT_MULTIPLE_FAULTS:
   358     case STATUS_FLOAT_MULTIPLE_TRAPS:
   359       X87CW(c) |= FPU_EXCEPTION_MASK; /* disable all FPU exceptions */
   360       X87SW(c) &= ~FPU_STATUS_FLAGS;  /* clear all pending FPU exceptions */
   361 #ifdef _M_IX86
   362       if (c->ContextFlags & CONTEXT_EXTENDED_REGISTERS) {
   363 #endif
   364         MXCSR(c) |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
   365         MXCSR(c) &= ~SSE_STATUS_FLAGS;  /* clear all pending SSE exceptions */
   366 #ifdef _M_IX86
   367       }
   368 #endif
   369       return EXCEPTION_CONTINUE_EXECUTION;
   370   }
   371   LONG action = EXCEPTION_CONTINUE_SEARCH;
   372   if (gFPEPreviousFilter)
   373     action = gFPEPreviousFilter(pe);
   375   return action;
   376 }
   378 void InstallSignalHandlers(const char *ProgramName)
   379 {
   380   gFPEPreviousFilter = SetUnhandledExceptionFilter(FpeHandler);
   381 }
   383 #else
   385 void InstallSignalHandlers(const char *ProgramName)
   386 {
   387 }
   389 #endif
   391 #else
   392 #error No signal handling implementation for this platform.
   393 #endif

mercurial