1
// Copyright 2010 the V8 project authors. All rights reserved.
2
// Redistribution and use in source and binary forms, with or without
3
// modification, are permitted provided that the following conditions are
6
// * Redistributions of source code must retain the above copyright
7
// notice, this list of conditions and the following disclaimer.
8
// * Redistributions in binary form must reproduce the above
9
// copyright notice, this list of conditions and the following
10
// disclaimer in the documentation and/or other materials provided
11
// with the distribution.
12
// * Neither the name of Google Inc. nor the names of its
13
// contributors may be used to endorse or promote products derived
14
// from this software without specific prior written permission.
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
#include <google_breakpad/processor/minidump.h>
35
#define ENABLE_DEBUGGER_SUPPORT
41
using google_breakpad::Minidump;
42
using google_breakpad::MinidumpContext;
43
using google_breakpad::MinidumpThread;
44
using google_breakpad::MinidumpThreadList;
45
using google_breakpad::MinidumpException;
46
using google_breakpad::MinidumpMemoryRegion;
48
const char* InstanceTypeToString(int type) {
49
static char const* names[v8::internal::LAST_TYPE] = {0};
50
if (names[v8::internal::STRING_TYPE] == NULL) {
51
using namespace v8::internal;
52
#define SET(type) names[type] = #type;
53
INSTANCE_TYPE_LIST(SET)
60
u_int32_t ReadPointedValue(MinidumpMemoryRegion* region,
64
CHECK(region->GetMemoryAtAddress(base + 4 * offset, &ptr));
66
CHECK(region->GetMemoryAtAddress(ptr, &value));
71
void ReadArray(MinidumpMemoryRegion* region,
75
for (int i = 0; i < size; i++) {
77
CHECK(region->GetMemoryAtAddress(array_ptr + 4 * i, &value));
83
u_int32_t ReadArrayFrom(MinidumpMemoryRegion* region,
89
CHECK(region->GetMemoryAtAddress(base + 4 * offset, &ptr));
90
ReadArray(region, ptr, size, output);
94
double toM(int size) {
95
return size / (1024. * 1024.);
99
class IndirectSorter {
101
explicit IndirectSorter(int* a) : a_(a) { }
103
bool operator() (int i0, int i1) {
104
return a_[i0] > a_[i1];
111
void DumpHeapStats(const char *minidump_file) {
112
Minidump minidump(minidump_file);
113
CHECK(minidump.Read());
115
MinidumpException *exception = minidump.GetException();
118
MinidumpContext* crash_context = exception->GetContext();
119
CHECK(crash_context);
121
u_int32_t exception_thread_id = 0;
122
CHECK(exception->GetThreadID(&exception_thread_id));
124
MinidumpThreadList* thread_list = minidump.GetThreadList();
127
MinidumpThread* exception_thread =
128
thread_list->GetThreadByID(exception_thread_id);
129
CHECK(exception_thread);
131
// Currently only 32-bit Windows minidumps are supported.
132
CHECK_EQ(MD_CONTEXT_X86, crash_context->GetContextCPU());
134
const MDRawContextX86* contextX86 = crash_context->GetContextX86();
137
const u_int32_t esp = contextX86->esp;
139
MinidumpMemoryRegion* memory_region = exception_thread->GetMemory();
140
CHECK(memory_region);
142
const u_int64_t last = memory_region->GetBase() + memory_region->GetSize();
144
u_int64_t heap_stats_addr = 0;
145
for (u_int64_t addr = esp; addr < last; addr += 4) {
147
CHECK(memory_region->GetMemoryAtAddress(addr, &value));
148
if (value >= esp && value < last) {
149
u_int32_t value2 = 0;
150
CHECK(memory_region->GetMemoryAtAddress(value, &value2));
151
if (value2 == v8::internal::HeapStats::kStartMarker) {
152
heap_stats_addr = addr;
157
CHECK(heap_stats_addr);
161
#define READ_FIELD(offset) \
162
ReadPointedValue(memory_region, heap_stats_addr, offset)
164
CHECK(READ_FIELD(0) == v8::internal::HeapStats::kStartMarker);
165
CHECK(READ_FIELD(24) == v8::internal::HeapStats::kEndMarker);
167
const int new_space_size = READ_FIELD(1);
168
const int new_space_capacity = READ_FIELD(2);
169
const int old_pointer_space_size = READ_FIELD(3);
170
const int old_pointer_space_capacity = READ_FIELD(4);
171
const int old_data_space_size = READ_FIELD(5);
172
const int old_data_space_capacity = READ_FIELD(6);
173
const int code_space_size = READ_FIELD(7);
174
const int code_space_capacity = READ_FIELD(8);
175
const int map_space_size = READ_FIELD(9);
176
const int map_space_capacity = READ_FIELD(10);
177
const int cell_space_size = READ_FIELD(11);
178
const int cell_space_capacity = READ_FIELD(12);
179
const int lo_space_size = READ_FIELD(13);
180
const int global_handle_count = READ_FIELD(14);
181
const int weak_global_handle_count = READ_FIELD(15);
182
const int pending_global_handle_count = READ_FIELD(16);
183
const int near_death_global_handle_count = READ_FIELD(17);
184
const int destroyed_global_handle_count = READ_FIELD(18);
185
const int memory_allocator_size = READ_FIELD(19);
186
const int memory_allocator_capacity = READ_FIELD(20);
187
const int os_error = READ_FIELD(23);
190
int objects_per_type[v8::internal::LAST_TYPE + 1] = {0};
191
ReadArrayFrom(memory_region, heap_stats_addr, 21,
192
v8::internal::LAST_TYPE + 1, objects_per_type);
194
int size_per_type[v8::internal::LAST_TYPE + 1] = {0};
195
ReadArrayFrom(memory_region, heap_stats_addr, 22, v8::internal::LAST_TYPE + 1,
198
int js_global_objects =
199
objects_per_type[v8::internal::JS_GLOBAL_OBJECT_TYPE];
200
int js_builtins_objects =
201
objects_per_type[v8::internal::JS_BUILTINS_OBJECT_TYPE];
202
int js_global_proxies =
203
objects_per_type[v8::internal::JS_GLOBAL_PROXY_TYPE];
205
int indices[v8::internal::LAST_TYPE + 1];
206
for (int i = 0; i <= v8::internal::LAST_TYPE; i++) {
210
std::stable_sort(indices, indices + sizeof(indices)/sizeof(indices[0]),
211
IndirectSorter(size_per_type));
214
for (int i = 0; i <= v8::internal::LAST_TYPE; i++) {
215
total_size += size_per_type[i];
220
printf("exception thread ID: %" PRIu32 " (%#" PRIx32 ")\n",
221
exception_thread_id, exception_thread_id);
222
printf("heap stats address: %#" PRIx64 "\n", heap_stats_addr);
223
#define PRINT_INT_STAT(stat) \
224
printf("\t%-25s\t% 10d\n", #stat ":", stat);
225
#define PRINT_MB_STAT(stat) \
226
printf("\t%-25s\t% 10.3f MB\n", #stat ":", toM(stat));
227
PRINT_MB_STAT(new_space_size);
228
PRINT_MB_STAT(new_space_capacity);
229
PRINT_MB_STAT(old_pointer_space_size);
230
PRINT_MB_STAT(old_pointer_space_capacity);
231
PRINT_MB_STAT(old_data_space_size);
232
PRINT_MB_STAT(old_data_space_capacity);
233
PRINT_MB_STAT(code_space_size);
234
PRINT_MB_STAT(code_space_capacity);
235
PRINT_MB_STAT(map_space_size);
236
PRINT_MB_STAT(map_space_capacity);
237
PRINT_MB_STAT(cell_space_size);
238
PRINT_MB_STAT(cell_space_capacity);
239
PRINT_MB_STAT(lo_space_size);
240
PRINT_INT_STAT(global_handle_count);
241
PRINT_INT_STAT(weak_global_handle_count);
242
PRINT_INT_STAT(pending_global_handle_count);
243
PRINT_INT_STAT(near_death_global_handle_count);
244
PRINT_INT_STAT(destroyed_global_handle_count);
245
PRINT_MB_STAT(memory_allocator_size);
246
PRINT_MB_STAT(memory_allocator_capacity);
247
PRINT_INT_STAT(os_error);
253
"\tJS_GLOBAL_OBJECT_TYPE/JS_BUILTINS_OBJECT_TYPE/JS_GLOBAL_PROXY_TYPE: "
255
js_global_objects, js_builtins_objects, js_global_proxies);
257
int running_size = 0;
258
for (int i = 0; i <= v8::internal::LAST_TYPE; i++) {
259
int type = indices[i];
260
const char* name = InstanceTypeToString(type);
262
// Unknown instance type. Check that there is no objects of that type.
263
CHECK_EQ(0, objects_per_type[type]);
264
CHECK_EQ(0, size_per_type[type]);
267
int size = size_per_type[type];
268
running_size += size;
269
printf("\t%-37s% 9d% 11.3f MB% 10.3f%%% 10.3f%%\n",
270
name, objects_per_type[type], toM(size),
271
100. * size / total_size, 100. * running_size / total_size);
273
printf("\t%-37s% 9d% 11.3f MB% 10.3f%%% 10.3f%%\n",
274
"total", 0, toM(total_size), 100., 100.);
279
int main(int argc, char **argv) {
281
fprintf(stderr, "usage: %s <minidump>\n", argv[0]);
285
DumpHeapStats(argv[1]);