Bumping manifests a=b2g-bump
[gecko.git] / js / src / jscrashreport.cpp
blob0fa8f68a38f67070780c14704e30d370d327895e
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "jscrashreport.h"
9 #include <time.h>
11 #include "jsapi.h"
12 #include "jscrashformat.h"
13 #include "jsutil.h"
15 using namespace js;
16 using namespace js::crash;
18 #if defined(XP_WIN)
20 static const int stack_snapshot_max_size = 32768;
22 #include <windows.h>
24 static bool
25 GetStack(uint64_t *stack, uint64_t *stack_len, CrashRegisters *regs, char *buffer, size_t size)
27 /* Try to figure out how big the stack is. */
28 char dummy;
29 MEMORY_BASIC_INFORMATION info;
30 if (VirtualQuery(reinterpret_cast<LPCVOID>(&dummy), &info, sizeof(info)) == 0)
31 return false;
32 if (info.State != MEM_COMMIT)
33 return false;
35 /* 256 is a fudge factor to account for the rest of GetStack's frame. */
36 uint64_t p = uint64_t(&dummy) - 256;
37 uint64_t len = stack_snapshot_max_size;
39 if (p + len > uint64_t(info.BaseAddress) + info.RegionSize)
40 len = uint64_t(info.BaseAddress) + info.RegionSize - p;
42 if (len > size)
43 len = size;
45 *stack = p;
46 *stack_len = len;
48 /* Get the register state. */
49 #if defined(_MSC_VER) && defined(_M_IX86)
50 /* ASM version for win2k that doesn't support RtlCaptureContext */
51 uint32_t vip, vsp, vbp;
52 __asm {
53 MyLabel:
54 mov [vbp], ebp;
55 mov [vsp], esp;
56 mov eax, [MyLabel];
57 mov [vip], eax;
59 regs->ip = vip;
60 regs->sp = vsp;
61 regs->bp = vbp;
62 #else
63 CONTEXT context;
64 RtlCaptureContext(&context);
65 #if defined(_M_IX86)
66 regs->ip = context.Eip;
67 regs->sp = context.Esp;
68 regs->bp = context.Ebp;
69 #elif defined(_M_X64)
70 regs->ip = context.Rip;
71 regs->sp = context.Rsp;
72 regs->bp = context.Rbp;
73 #else
74 #error unknown cpu architecture
75 #endif
76 #endif
78 js_memcpy(buffer, (void *)p, len);
80 return true;
83 #elif 0
85 #include <sys/mman.h>
86 #include <ucontext.h>
87 #include <unistd.h>
89 static bool
90 GetStack(uint64_t *stack, uint64_t *stack_len, CrashRegisters *regs, char *buffer, size_t size)
92 /* 256 is a fudge factor to account for the rest of GetStack's frame. */
93 char dummy;
94 uint64_t p = uint64_t(&dummy) - 256;
95 uint64_t pgsz = getpagesize();
96 uint64_t len = stack_snapshot_max_size;
97 p &= ~(pgsz - 1);
99 /* Try to figure out how big the stack is. */
100 while (len > 0) {
101 if (mlock((const void *)p, len) == 0) {
102 munlock((const void *)p, len);
103 break;
105 len -= pgsz;
108 if (len > size)
109 len = size;
111 *stack = p;
112 *stack_len = len;
114 /* Get the register state. */
115 ucontext_t context;
116 if (getcontext(&context) != 0)
117 return false;
119 #if defined(__x86_64__)
120 regs->sp = (uint64_t)context.uc_mcontext.gregs[REG_RSP];
121 regs->bp = (uint64_t)context.uc_mcontext.gregs[REG_RBP];
122 regs->ip = (uint64_t)context.uc_mcontext.gregs[REG_RIP];
123 #elif defined(__i386__)
124 regs->sp = (uint64_t)context.uc_mcontext.gregs[REG_ESP];
125 regs->bp = (uint64_t)context.uc_mcontext.gregs[REG_EBP];
126 regs->ip = (uint64_t)context.uc_mcontext.gregs[REG_EIP];
127 #else
128 #error unknown cpu architecture
129 #endif
131 js_memcpy(buffer, (void *)p, len);
133 return true;
136 #else
138 static bool
139 GetStack(uint64_t *stack, uint64_t *stack_len, CrashRegisters *regs, char *buffer, size_t size)
141 return false;
144 #endif
146 namespace js {
147 namespace crash {
149 class Stack : private CrashStack
151 public:
152 explicit Stack(uint64_t id);
154 bool snapshot();
157 Stack::Stack(uint64_t id)
158 : CrashStack(id)
162 bool
163 Stack::snapshot()
165 snaptime = time(nullptr);
166 return GetStack(&stack_base, &stack_len, &regs, stack, sizeof(stack));
169 class Ring : private CrashRing
171 public:
172 explicit Ring(uint64_t id);
174 void push(uint64_t tag, void *data, size_t size);
176 private:
177 size_t bufferSize() { return crash_buffer_size; }
178 void copyBytes(void *data, size_t size);
181 Ring::Ring(uint64_t id)
182 : CrashRing(id)
186 void
187 Ring::push(uint64_t tag, void *data, size_t size)
189 uint64_t t = time(nullptr);
191 copyBytes(&tag, sizeof(uint64_t));
192 copyBytes(&t, sizeof(uint64_t));
193 copyBytes(data, size);
194 uint64_t mysize = size;
195 copyBytes(&mysize, sizeof(uint64_t));
198 void
199 Ring::copyBytes(void *data, size_t size)
201 if (size >= bufferSize())
202 size = bufferSize();
204 if (offset + size > bufferSize()) {
205 size_t first = bufferSize() - offset;
206 size_t second = size - first;
207 js_memcpy(&buffer[offset], data, first);
208 js_memcpy(buffer, (char *)data + first, second);
209 offset = second;
210 } else {
211 js_memcpy(&buffer[offset], data, size);
212 offset += size;
216 } /* namespace crash */
217 } /* namespace js */
219 #ifdef JS_CRASH_DIAGNOSTICS
220 static bool gInitialized;
222 static Stack gGCStack(JS_CRASH_STACK_GC);
223 static Stack gErrorStack(JS_CRASH_STACK_ERROR);
224 static Ring gRingBuffer(JS_CRASH_RING);
225 #endif
227 void
228 js::crash::SnapshotGCStack()
230 #ifdef JS_CRASH_DIAGNOSTICS
231 if (gInitialized)
232 gGCStack.snapshot();
233 #endif
236 void
237 js::crash::SnapshotErrorStack()
239 #ifdef JS_CRASH_DIAGNOSTICS
240 if (gInitialized)
241 gErrorStack.snapshot();
242 #endif
245 void
246 js::crash::SaveCrashData(uint64_t tag, void *ptr, size_t size)
248 #ifdef JS_CRASH_DIAGNOSTICS
249 if (gInitialized)
250 gRingBuffer.push(tag, ptr, size);
251 #endif
254 JS_PUBLIC_API(void)
255 JS_EnumerateDiagnosticMemoryRegions(JSEnumerateDiagnosticMemoryCallback callback)
257 #ifdef JS_CRASH_DIAGNOSTICS
258 if (!gInitialized) {
259 gInitialized = true;
260 (*callback)(&gGCStack, sizeof(gGCStack));
261 (*callback)(&gErrorStack, sizeof(gErrorStack));
262 (*callback)(&gRingBuffer, sizeof(gRingBuffer));
264 #endif