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"
12 #include "jscrashformat.h"
16 using namespace js::crash
;
20 static const int stack_snapshot_max_size
= 32768;
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. */
29 MEMORY_BASIC_INFORMATION info
;
30 if (VirtualQuery(reinterpret_cast<LPCVOID
>(&dummy
), &info
, sizeof(info
)) == 0)
32 if (info
.State
!= MEM_COMMIT
)
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
;
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
;
64 RtlCaptureContext(&context
);
66 regs
->ip
= context
.Eip
;
67 regs
->sp
= context
.Esp
;
68 regs
->bp
= context
.Ebp
;
70 regs
->ip
= context
.Rip
;
71 regs
->sp
= context
.Rsp
;
72 regs
->bp
= context
.Rbp
;
74 #error unknown cpu architecture
78 js_memcpy(buffer
, (void *)p
, len
);
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. */
94 uint64_t p
= uint64_t(&dummy
) - 256;
95 uint64_t pgsz
= getpagesize();
96 uint64_t len
= stack_snapshot_max_size
;
99 /* Try to figure out how big the stack is. */
101 if (mlock((const void *)p
, len
) == 0) {
102 munlock((const void *)p
, len
);
114 /* Get the register state. */
116 if (getcontext(&context
) != 0)
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
];
128 #error unknown cpu architecture
131 js_memcpy(buffer
, (void *)p
, len
);
139 GetStack(uint64_t *stack
, uint64_t *stack_len
, CrashRegisters
*regs
, char *buffer
, size_t size
)
149 class Stack
: private CrashStack
152 explicit Stack(uint64_t id
);
157 Stack::Stack(uint64_t id
)
165 snaptime
= time(nullptr);
166 return GetStack(&stack_base
, &stack_len
, ®s
, stack
, sizeof(stack
));
169 class Ring
: private CrashRing
172 explicit Ring(uint64_t id
);
174 void push(uint64_t tag
, void *data
, size_t size
);
177 size_t bufferSize() { return crash_buffer_size
; }
178 void copyBytes(void *data
, size_t size
);
181 Ring::Ring(uint64_t id
)
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));
199 Ring::copyBytes(void *data
, size_t size
)
201 if (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
);
211 js_memcpy(&buffer
[offset
], data
, size
);
216 } /* namespace crash */
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
);
228 js::crash::SnapshotGCStack()
230 #ifdef JS_CRASH_DIAGNOSTICS
237 js::crash::SnapshotErrorStack()
239 #ifdef JS_CRASH_DIAGNOSTICS
241 gErrorStack
.snapshot();
246 js::crash::SaveCrashData(uint64_t tag
, void *ptr
, size_t size
)
248 #ifdef JS_CRASH_DIAGNOSTICS
250 gRingBuffer
.push(tag
, ptr
, size
);
255 JS_EnumerateDiagnosticMemoryRegions(JSEnumerateDiagnosticMemoryCallback callback
)
257 #ifdef JS_CRASH_DIAGNOSTICS
260 (*callback
)(&gGCStack
, sizeof(gGCStack
));
261 (*callback
)(&gErrorStack
, sizeof(gErrorStack
));
262 (*callback
)(&gRingBuffer
, sizeof(gRingBuffer
));