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, ®s, 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 +