js/src/jscrashreport.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jscrashreport.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,266 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "jscrashreport.h"
    1.11 +
    1.12 +#include <time.h>
    1.13 +
    1.14 +#include "jsapi.h"
    1.15 +#include "jscrashformat.h"
    1.16 +#include "jsutil.h"
    1.17 +
    1.18 +using namespace js;
    1.19 +using namespace js::crash;
    1.20 +
    1.21 +#if defined(XP_WIN)
    1.22 +
    1.23 +static const int stack_snapshot_max_size = 32768;
    1.24 +
    1.25 +#include <windows.h>
    1.26 +
    1.27 +static bool
    1.28 +GetStack(uint64_t *stack, uint64_t *stack_len, CrashRegisters *regs, char *buffer, size_t size)
    1.29 +{
    1.30 +    /* Try to figure out how big the stack is. */
    1.31 +    char dummy;
    1.32 +    MEMORY_BASIC_INFORMATION info;
    1.33 +    if (VirtualQuery(reinterpret_cast<LPCVOID>(&dummy), &info, sizeof(info)) == 0)
    1.34 +        return false;
    1.35 +    if (info.State != MEM_COMMIT)
    1.36 +        return false;
    1.37 +
    1.38 +    /* 256 is a fudge factor to account for the rest of GetStack's frame. */
    1.39 +    uint64_t p = uint64_t(&dummy) - 256;
    1.40 +    uint64_t len = stack_snapshot_max_size;
    1.41 +
    1.42 +    if (p + len > uint64_t(info.BaseAddress) + info.RegionSize)
    1.43 +        len = uint64_t(info.BaseAddress) + info.RegionSize - p;
    1.44 +
    1.45 +    if (len > size)
    1.46 +        len = size;
    1.47 +
    1.48 +    *stack = p;
    1.49 +    *stack_len = len;
    1.50 +
    1.51 +    /* Get the register state. */
    1.52 +#if defined(_MSC_VER) && defined(_M_IX86)
    1.53 +    /* ASM version for win2k that doesn't support RtlCaptureContext */
    1.54 +    uint32_t vip, vsp, vbp;
    1.55 +    __asm {
    1.56 +    MyLabel:
    1.57 +        mov [vbp], ebp;
    1.58 +        mov [vsp], esp;
    1.59 +        mov eax, [MyLabel];
    1.60 +        mov [vip], eax;
    1.61 +    }
    1.62 +    regs->ip = vip;
    1.63 +    regs->sp = vsp;
    1.64 +    regs->bp = vbp;
    1.65 +#else
    1.66 +    CONTEXT context;
    1.67 +    RtlCaptureContext(&context);
    1.68 +#if defined(_M_IX86)
    1.69 +    regs->ip = context.Eip;
    1.70 +    regs->sp = context.Esp;
    1.71 +    regs->bp = context.Ebp;
    1.72 +#elif defined(_M_X64)
    1.73 +    regs->ip = context.Rip;
    1.74 +    regs->sp = context.Rsp;
    1.75 +    regs->bp = context.Rbp;
    1.76 +#else
    1.77 +#error unknown cpu architecture
    1.78 +#endif
    1.79 +#endif
    1.80 +
    1.81 +    js_memcpy(buffer, (void *)p, len);
    1.82 +
    1.83 +    return true;
    1.84 +}
    1.85 +
    1.86 +#elif 0
    1.87 +
    1.88 +#include <sys/mman.h>
    1.89 +#include <ucontext.h>
    1.90 +#include <unistd.h>
    1.91 +
    1.92 +static bool
    1.93 +GetStack(uint64_t *stack, uint64_t *stack_len, CrashRegisters *regs, char *buffer, size_t size)
    1.94 +{
    1.95 +    /* 256 is a fudge factor to account for the rest of GetStack's frame. */
    1.96 +    char dummy;
    1.97 +    uint64_t p = uint64_t(&dummy) - 256;
    1.98 +    uint64_t pgsz = getpagesize();
    1.99 +    uint64_t len = stack_snapshot_max_size;
   1.100 +    p &= ~(pgsz - 1);
   1.101 +
   1.102 +    /* Try to figure out how big the stack is. */
   1.103 +    while (len > 0) {
   1.104 +	if (mlock((const void *)p, len) == 0) {
   1.105 +	    munlock((const void *)p, len);
   1.106 +	    break;
   1.107 +	}
   1.108 +	len -= pgsz;
   1.109 +    }
   1.110 +
   1.111 +    if (len > size)
   1.112 +        len = size;
   1.113 +
   1.114 +    *stack = p;
   1.115 +    *stack_len = len;
   1.116 +
   1.117 +    /* Get the register state. */
   1.118 +    ucontext_t context;
   1.119 +    if (getcontext(&context) != 0)
   1.120 +	return false;
   1.121 +
   1.122 +#if defined(__x86_64__)
   1.123 +    regs->sp = (uint64_t)context.uc_mcontext.gregs[REG_RSP];
   1.124 +    regs->bp = (uint64_t)context.uc_mcontext.gregs[REG_RBP];
   1.125 +    regs->ip = (uint64_t)context.uc_mcontext.gregs[REG_RIP];
   1.126 +#elif defined(__i386__)
   1.127 +    regs->sp = (uint64_t)context.uc_mcontext.gregs[REG_ESP];
   1.128 +    regs->bp = (uint64_t)context.uc_mcontext.gregs[REG_EBP];
   1.129 +    regs->ip = (uint64_t)context.uc_mcontext.gregs[REG_EIP];
   1.130 +#else
   1.131 +#error unknown cpu architecture
   1.132 +#endif
   1.133 +
   1.134 +    js_memcpy(buffer, (void *)p, len);
   1.135 +
   1.136 +    return true;
   1.137 +}
   1.138 +
   1.139 +#else
   1.140 +
   1.141 +static bool
   1.142 +GetStack(uint64_t *stack, uint64_t *stack_len, CrashRegisters *regs, char *buffer, size_t size)
   1.143 +{
   1.144 +    return false;
   1.145 +}
   1.146 +
   1.147 +#endif
   1.148 +
   1.149 +namespace js {
   1.150 +namespace crash {
   1.151 +
   1.152 +class Stack : private CrashStack
   1.153 +{
   1.154 +public:
   1.155 +    Stack(uint64_t id);
   1.156 +
   1.157 +    bool snapshot();
   1.158 +};
   1.159 +
   1.160 +Stack::Stack(uint64_t id)
   1.161 +  : CrashStack(id)
   1.162 +{
   1.163 +}
   1.164 +
   1.165 +bool
   1.166 +Stack::snapshot()
   1.167 +{
   1.168 +    snaptime = time(nullptr);
   1.169 +    return GetStack(&stack_base, &stack_len, &regs, stack, sizeof(stack));
   1.170 +}
   1.171 +
   1.172 +class Ring : private CrashRing
   1.173 +{
   1.174 +public:
   1.175 +    Ring(uint64_t id);
   1.176 +
   1.177 +    void push(uint64_t tag, void *data, size_t size);
   1.178 +
   1.179 +private:
   1.180 +    size_t bufferSize() { return crash_buffer_size; }
   1.181 +    void copyBytes(void *data, size_t size);
   1.182 +};
   1.183 +
   1.184 +Ring::Ring(uint64_t id)
   1.185 +  : CrashRing(id)
   1.186 +{
   1.187 +}
   1.188 +
   1.189 +void
   1.190 +Ring::push(uint64_t tag, void *data, size_t size)
   1.191 +{
   1.192 +    uint64_t t = time(nullptr);
   1.193 +
   1.194 +    copyBytes(&tag, sizeof(uint64_t));
   1.195 +    copyBytes(&t, sizeof(uint64_t));
   1.196 +    copyBytes(data, size);
   1.197 +    uint64_t mysize = size;
   1.198 +    copyBytes(&mysize, sizeof(uint64_t));
   1.199 +}
   1.200 +
   1.201 +void
   1.202 +Ring::copyBytes(void *data, size_t size)
   1.203 +{
   1.204 +    if (size >= bufferSize())
   1.205 +        size = bufferSize();
   1.206 +
   1.207 +    if (offset + size > bufferSize()) {
   1.208 +        size_t first = bufferSize() - offset;
   1.209 +        size_t second = size - first;
   1.210 +        js_memcpy(&buffer[offset], data, first);
   1.211 +        js_memcpy(buffer, (char *)data + first, second);
   1.212 +        offset = second;
   1.213 +    } else {
   1.214 +        js_memcpy(&buffer[offset], data, size);
   1.215 +        offset += size;
   1.216 +    }
   1.217 +}
   1.218 +
   1.219 +} /* namespace crash */
   1.220 +} /* namespace js */
   1.221 +
   1.222 +#ifdef JS_CRASH_DIAGNOSTICS
   1.223 +static bool gInitialized;
   1.224 +
   1.225 +static Stack gGCStack(JS_CRASH_STACK_GC);
   1.226 +static Stack gErrorStack(JS_CRASH_STACK_ERROR);
   1.227 +static Ring gRingBuffer(JS_CRASH_RING);
   1.228 +#endif
   1.229 +
   1.230 +void
   1.231 +js::crash::SnapshotGCStack()
   1.232 +{
   1.233 +#ifdef JS_CRASH_DIAGNOSTICS
   1.234 +    if (gInitialized)
   1.235 +        gGCStack.snapshot();
   1.236 +#endif
   1.237 +}
   1.238 +
   1.239 +void
   1.240 +js::crash::SnapshotErrorStack()
   1.241 +{
   1.242 +#ifdef JS_CRASH_DIAGNOSTICS
   1.243 +    if (gInitialized)
   1.244 +        gErrorStack.snapshot();
   1.245 +#endif
   1.246 +}
   1.247 +
   1.248 +void
   1.249 +js::crash::SaveCrashData(uint64_t tag, void *ptr, size_t size)
   1.250 +{
   1.251 +#ifdef JS_CRASH_DIAGNOSTICS
   1.252 +    if (gInitialized)
   1.253 +        gRingBuffer.push(tag, ptr, size);
   1.254 +#endif
   1.255 +}
   1.256 +
   1.257 +JS_PUBLIC_API(void)
   1.258 +JS_EnumerateDiagnosticMemoryRegions(JSEnumerateDiagnosticMemoryCallback callback)
   1.259 +{
   1.260 +#ifdef JS_CRASH_DIAGNOSTICS
   1.261 +    if (!gInitialized) {
   1.262 +        gInitialized = true;
   1.263 +        (*callback)(&gGCStack, sizeof(gGCStack));
   1.264 +        (*callback)(&gErrorStack, sizeof(gErrorStack));
   1.265 +        (*callback)(&gRingBuffer, sizeof(gRingBuffer));
   1.266 +    }
   1.267 +#endif
   1.268 +}
   1.269 +

mercurial