Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/toolkit/xre/nsSigHandlers.cpp
Line
Count
Source (jump to first uncovered line)
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
// Note: some tests manipulate this value.
41
unsigned int _gdb_sleep_duration = 300;
42
43
#if defined(LINUX) && defined(DEBUG) && \
44
      (defined(__i386) || defined(__x86_64) || defined(PPC))
45
#define CRAWL_STACK_ON_SIGSEGV
46
#endif
47
48
#ifndef PR_SET_PTRACER
49
#define PR_SET_PTRACER 0x59616d61
50
#endif
51
#ifndef PR_SET_PTRACER_ANY
52
#define PR_SET_PTRACER_ANY ((unsigned long)-1)
53
#endif
54
55
#if defined(CRAWL_STACK_ON_SIGSEGV)
56
57
#include <unistd.h>
58
#include "nsISupportsUtils.h"
59
#include "mozilla/StackWalk.h"
60
61
static const char* gProgname = "huh?";
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
static void PrintStackFrame(uint32_t aFrameNumber, void *aPC, void *aSP,
70
                            void *aClosure)
71
{
72
  char buf[1024];
73
  MozCodeAddressDetails details;
74
75
  MozDescribeCodeAddress(aPC, &details);
76
  MozFormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
77
  fprintf(stdout, "%s\n", buf);
78
  fflush(stdout);
79
}
80
81
}
82
83
void
84
ah_crap_handler(int signum)
85
{
86
  printf("\nProgram %s (pid = %d) received signal %d.\n",
87
         gProgname,
88
         getpid(),
89
         signum);
90
91
  printf("Stack:\n");
92
  MozStackWalk(PrintStackFrame, /* skipFrames */ 2, /* maxFrames */ 0, nullptr);
93
94
  printf("Sleeping for %d seconds.\n",_gdb_sleep_duration);
95
  printf("Type 'gdb %s %d' to attach your debugger to this thread.\n",
96
         gProgname,
97
         getpid());
98
99
  // Allow us to be ptraced by gdb on Linux with Yama restrictions enabled.
100
  prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY);
101
102
  sleep(_gdb_sleep_duration);
103
104
  printf("Done sleeping...\n");
105
106
  _exit(signum);
107
}
108
109
void
110
child_ah_crap_handler(int signum)
111
{
112
  if (!getenv("MOZ_DONT_UNBLOCK_PARENT_ON_CHILD_CRASH"))
113
    close(kClientChannelFd);
114
  ah_crap_handler(signum);
115
}
116
117
#endif // CRAWL_STACK_ON_SIGSEGV
118
119
#ifdef MOZ_WIDGET_GTK
120
// Need this include for version test below.
121
#include <glib.h>
122
#endif
123
124
#if defined(MOZ_WIDGET_GTK) && (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6))
125
126
static GLogFunc orig_log_func = nullptr;
127
128
extern "C" {
129
static void
130
my_glib_log_func(const gchar *log_domain, GLogLevelFlags log_level,
131
                 const gchar *message, gpointer user_data);
132
}
133
134
/* static */ void
135
my_glib_log_func(const gchar *log_domain, GLogLevelFlags log_level,
136
                 const gchar *message, gpointer user_data)
137
0
{
138
0
  if (log_level & (G_LOG_LEVEL_ERROR | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION)) {
139
0
    NS_DebugBreak(NS_DEBUG_ASSERTION, message, "glib assertion", __FILE__, __LINE__);
140
0
  } else if (log_level & (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING)) {
141
0
    NS_DebugBreak(NS_DEBUG_WARNING, message, "glib warning", __FILE__, __LINE__);
142
0
  }
143
0
144
0
  orig_log_func(log_domain, log_level, message, nullptr);
145
0
}
146
147
#endif
148
149
#ifdef SA_SIGINFO
150
static void fpehandler(int signum, siginfo_t *si, void *context)
151
0
{
152
0
  /* Integer divide by zero or integer overflow. */
153
0
  /* Note: FPE_INTOVF is ignored on Intel, PowerPC and SPARC systems. */
154
0
  if (si->si_code == FPE_INTDIV || si->si_code == FPE_INTOVF) {
155
0
    NS_DebugBreak(NS_DEBUG_ABORT, "Divide by zero", nullptr, __FILE__, __LINE__);
156
0
  }
157
0
158
#ifdef XP_MACOSX
159
  ucontext_t *uc = (ucontext_t *)context;
160
161
#if defined(__i386__) || defined(__amd64__)
162
  _STRUCT_FP_CONTROL *ctrl = &uc->uc_mcontext->__fs.__fpu_fcw;
163
  ctrl->__invalid = ctrl->__denorm = ctrl->__zdiv = ctrl->__ovrfl = ctrl->__undfl = ctrl->__precis = 1;
164
165
  _STRUCT_FP_STATUS *status = &uc->uc_mcontext->__fs.__fpu_fsw;
166
  status->__invalid = status->__denorm = status->__zdiv = status->__ovrfl = status->__undfl =
167
    status->__precis = status->__stkflt = status->__errsumm = 0;
168
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)
175
0
  ucontext_t *uc = (ucontext_t *)context;
176
0
177
#if defined(__i386__)
178
  /*
179
   * It seems that we have no access to mxcsr on Linux. libc
180
   * seems to be translating cw/sw to mxcsr.
181
   */
182
  unsigned long int *cw = &uc->uc_mcontext.fpregs->cw;
183
  *cw |= FPU_EXCEPTION_MASK;
184
185
  unsigned long int *sw = &uc->uc_mcontext.fpregs->sw;
186
  *sw &= ~FPU_STATUS_FLAGS;
187
#endif
188
#if defined(__amd64__)
189
0
  uint16_t *cw = &uc->uc_mcontext.fpregs->cwd;
190
0
  *cw |= FPU_EXCEPTION_MASK;
191
0
192
0
  uint16_t *sw = &uc->uc_mcontext.fpregs->swd;
193
0
  *sw &= ~FPU_STATUS_FLAGS;
194
0
195
0
  uint32_t *mxcsr = &uc->uc_mcontext.fpregs->mxcsr;
196
0
  *mxcsr |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
197
0
  *mxcsr &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */
198
0
#endif
199
0
#endif
200
#ifdef SOLARIS
201
  ucontext_t *uc = (ucontext_t *)context;
202
203
#if defined(__i386)
204
  uint32_t *cw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0];
205
  *cw |= FPU_EXCEPTION_MASK;
206
207
  uint32_t *sw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1];
208
  *sw &= ~FPU_STATUS_FLAGS;
209
210
  /* address of the instruction that caused the exception */
211
  uint32_t *ip = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[3];
212
  uc->uc_mcontext.gregs[REG_PC] = *ip;
213
#endif
214
#if defined(__amd64__)
215
  uint16_t *cw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw;
216
  *cw |= FPU_EXCEPTION_MASK;
217
218
  uint16_t *sw = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw;
219
  *sw &= ~FPU_STATUS_FLAGS;
220
221
  uint32_t *mxcsr = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr;
222
  *mxcsr |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */
223
  *mxcsr &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */
224
#endif
225
#endif
226
}
227
#endif
228
229
void InstallSignalHandlers(const char *aProgname)
230
3
{
231
#if defined(CRAWL_STACK_ON_SIGSEGV)
232
  const char* tmp = PL_strdup(aProgname);
233
  if (tmp) {
234
    gProgname = tmp;
235
  }
236
#endif // CRAWL_STACK_ON_SIGSEGV
237
238
3
  const char *gdbSleep = PR_GetEnv("MOZ_GDB_SLEEP");
239
3
  if (gdbSleep && *gdbSleep)
240
0
  {
241
0
    unsigned int s;
242
0
    if (1 == sscanf(gdbSleep, "%u", &s)) {
243
0
      _gdb_sleep_duration = s;
244
0
    }
245
0
  }
246
3
247
#if defined(CRAWL_STACK_ON_SIGSEGV)
248
  if (!getenv("XRE_NO_WINDOWS_CRASH_DIALOG")) {
249
    void (*crap_handler)(int) =
250
      GeckoProcessType_Default != XRE_GetProcessType() ?
251
          child_ah_crap_handler :
252
          ah_crap_handler;
253
    signal(SIGSEGV, crap_handler);
254
    signal(SIGILL, crap_handler);
255
    signal(SIGABRT, crap_handler);
256
  }
257
#endif // CRAWL_STACK_ON_SIGSEGV
258
259
3
#ifdef SA_SIGINFO
260
3
  /* Install a handler for floating point exceptions and disable them if they occur. */
261
3
  struct sigaction sa, osa;
262
3
  sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
263
3
  sa.sa_sigaction = fpehandler;
264
3
  sigemptyset(&sa.sa_mask);
265
3
  sigaction(SIGFPE, &sa, &osa);
266
3
#endif
267
3
268
3
  if (!XRE_IsParentProcess()) {
269
0
    /*
270
0
     * If the user is debugging a Gecko parent process in gdb and hits ^C to
271
0
     * suspend, a SIGINT signal will be sent to the child. We ignore this signal
272
0
     * so the child isn't killed.
273
0
     */
274
0
    signal(SIGINT, SIG_IGN);
275
0
  }
276
3
277
#if defined(DEBUG) && defined(LINUX)
278
  const char *memLimit = PR_GetEnv("MOZ_MEM_LIMIT");
279
  if (memLimit && *memLimit)
280
  {
281
    long m = atoi(memLimit);
282
    m *= (1024*1024);
283
    struct rlimit r;
284
    r.rlim_cur = m;
285
    r.rlim_max = m;
286
    setrlimit(RLIMIT_AS, &r);
287
  }
288
#endif
289
290
3
#if defined(MOZ_WIDGET_GTK) && (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6))
291
3
  const char *assertString = PR_GetEnv("XPCOM_DEBUG_BREAK");
292
3
  if (assertString &&
293
3
      (!strcmp(assertString, "suspend") ||
294
0
       !strcmp(assertString, "stack") ||
295
0
       !strcmp(assertString, "abort") ||
296
0
       !strcmp(assertString, "trap") ||
297
0
       !strcmp(assertString, "break"))) {
298
0
    // Override the default glib logging function so we get stacks for it too.
299
0
    orig_log_func = g_log_set_default_handler(my_glib_log_func, nullptr);
300
0
  }
301
3
#endif
302
3
}
303
304
#elif XP_WIN
305
306
#include <windows.h>
307
308
#ifdef _M_IX86
309
/*
310
 * WinNT.h prior to SDK7 does not expose the structure of the ExtendedRegisters for ia86.
311
 * We known that MxCsr is at offset 0x18 and is a DWORD.
312
 */
313
#define MXCSR(ctx) (*(DWORD *)(((BYTE *)(ctx)->ExtendedRegisters) + 0x18))
314
#endif
315
316
#ifdef _M_X64
317
#define MXCSR(ctx) (ctx)->MxCsr
318
#endif
319
320
#if defined(_M_IX86) || defined(_M_X64)
321
322
#ifdef _M_X64
323
#define X87CW(ctx) (ctx)->FltSave.ControlWord
324
#define X87SW(ctx) (ctx)->FltSave.StatusWord
325
#else
326
#define X87CW(ctx) (ctx)->FloatSave.ControlWord
327
#define X87SW(ctx) (ctx)->FloatSave.StatusWord
328
#endif
329
330
static LPTOP_LEVEL_EXCEPTION_FILTER gFPEPreviousFilter;
331
332
LONG __stdcall FpeHandler(PEXCEPTION_POINTERS pe)
333
{
334
  PEXCEPTION_RECORD e = (PEXCEPTION_RECORD)pe->ExceptionRecord;
335
  CONTEXT *c = (CONTEXT*)pe->ContextRecord;
336
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
355
      }
356
#endif
357
      return EXCEPTION_CONTINUE_EXECUTION;
358
  }
359
  LONG action = EXCEPTION_CONTINUE_SEARCH;
360
  if (gFPEPreviousFilter)
361
    action = gFPEPreviousFilter(pe);
362
363
  return action;
364
}
365
366
void InstallSignalHandlers(const char *aProgname)
367
{
368
  gFPEPreviousFilter = SetUnhandledExceptionFilter(FpeHandler);
369
}
370
371
#else
372
373
void InstallSignalHandlers(const char *aProgname)
374
{
375
}
376
377
#endif
378
379
#else
380
#error No signal handling implementation for this platform.
381
#endif