LCOV - code coverage report
Current view: top level - toolkit/xre - nsSigHandlers.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 23 78 29.5 %
Date: 2017-07-14 16:53:18 Functions: 1 6 16.7 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.13