js/src/jscrashreport.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:8b2c9f098f2f
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/. */
6
7 #include "jscrashreport.h"
8
9 #include <time.h>
10
11 #include "jsapi.h"
12 #include "jscrashformat.h"
13 #include "jsutil.h"
14
15 using namespace js;
16 using namespace js::crash;
17
18 #if defined(XP_WIN)
19
20 static const int stack_snapshot_max_size = 32768;
21
22 #include <windows.h>
23
24 static bool
25 GetStack(uint64_t *stack, uint64_t *stack_len, CrashRegisters *regs, char *buffer, size_t size)
26 {
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;
34
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;
38
39 if (p + len > uint64_t(info.BaseAddress) + info.RegionSize)
40 len = uint64_t(info.BaseAddress) + info.RegionSize - p;
41
42 if (len > size)
43 len = size;
44
45 *stack = p;
46 *stack_len = len;
47
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;
58 }
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
77
78 js_memcpy(buffer, (void *)p, len);
79
80 return true;
81 }
82
83 #elif 0
84
85 #include <sys/mman.h>
86 #include <ucontext.h>
87 #include <unistd.h>
88
89 static bool
90 GetStack(uint64_t *stack, uint64_t *stack_len, CrashRegisters *regs, char *buffer, size_t size)
91 {
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);
98
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;
104 }
105 len -= pgsz;
106 }
107
108 if (len > size)
109 len = size;
110
111 *stack = p;
112 *stack_len = len;
113
114 /* Get the register state. */
115 ucontext_t context;
116 if (getcontext(&context) != 0)
117 return false;
118
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
130
131 js_memcpy(buffer, (void *)p, len);
132
133 return true;
134 }
135
136 #else
137
138 static bool
139 GetStack(uint64_t *stack, uint64_t *stack_len, CrashRegisters *regs, char *buffer, size_t size)
140 {
141 return false;
142 }
143
144 #endif
145
146 namespace js {
147 namespace crash {
148
149 class Stack : private CrashStack
150 {
151 public:
152 Stack(uint64_t id);
153
154 bool snapshot();
155 };
156
157 Stack::Stack(uint64_t id)
158 : CrashStack(id)
159 {
160 }
161
162 bool
163 Stack::snapshot()
164 {
165 snaptime = time(nullptr);
166 return GetStack(&stack_base, &stack_len, &regs, stack, sizeof(stack));
167 }
168
169 class Ring : private CrashRing
170 {
171 public:
172 Ring(uint64_t id);
173
174 void push(uint64_t tag, void *data, size_t size);
175
176 private:
177 size_t bufferSize() { return crash_buffer_size; }
178 void copyBytes(void *data, size_t size);
179 };
180
181 Ring::Ring(uint64_t id)
182 : CrashRing(id)
183 {
184 }
185
186 void
187 Ring::push(uint64_t tag, void *data, size_t size)
188 {
189 uint64_t t = time(nullptr);
190
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));
196 }
197
198 void
199 Ring::copyBytes(void *data, size_t size)
200 {
201 if (size >= bufferSize())
202 size = bufferSize();
203
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;
213 }
214 }
215
216 } /* namespace crash */
217 } /* namespace js */
218
219 #ifdef JS_CRASH_DIAGNOSTICS
220 static bool gInitialized;
221
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
226
227 void
228 js::crash::SnapshotGCStack()
229 {
230 #ifdef JS_CRASH_DIAGNOSTICS
231 if (gInitialized)
232 gGCStack.snapshot();
233 #endif
234 }
235
236 void
237 js::crash::SnapshotErrorStack()
238 {
239 #ifdef JS_CRASH_DIAGNOSTICS
240 if (gInitialized)
241 gErrorStack.snapshot();
242 #endif
243 }
244
245 void
246 js::crash::SaveCrashData(uint64_t tag, void *ptr, size_t size)
247 {
248 #ifdef JS_CRASH_DIAGNOSTICS
249 if (gInitialized)
250 gRingBuffer.push(tag, ptr, size);
251 #endif
252 }
253
254 JS_PUBLIC_API(void)
255 JS_EnumerateDiagnosticMemoryRegions(JSEnumerateDiagnosticMemoryCallback callback)
256 {
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));
263 }
264 #endif
265 }
266

mercurial