blob: 581e1914e2e345497c9a4a2a47f319a10e7ae07b [file] [log] [blame]
Iain Merrick75681382010-08-19 15:07:18 +01001// 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
4// met:
5//
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.
15//
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.
27
28#include <stdio.h>
29#include <stdlib.h>
30
31#include <algorithm>
32
33#include <google_breakpad/processor/minidump.h>
34
Iain Merrick75681382010-08-19 15:07:18 +010035#include <v8.h>
36
37namespace {
38
39using google_breakpad::Minidump;
40using google_breakpad::MinidumpContext;
41using google_breakpad::MinidumpThread;
42using google_breakpad::MinidumpThreadList;
43using google_breakpad::MinidumpException;
44using google_breakpad::MinidumpMemoryRegion;
45
46const char* InstanceTypeToString(int type) {
47 static char const* names[v8::internal::LAST_TYPE] = {0};
48 if (names[v8::internal::STRING_TYPE] == NULL) {
49 using namespace v8::internal;
50#define SET(type) names[type] = #type;
51 INSTANCE_TYPE_LIST(SET)
52#undef SET
53 }
54 return names[type];
55}
56
57
58u_int32_t ReadPointedValue(MinidumpMemoryRegion* region,
59 u_int64_t base,
60 int offset) {
61 u_int32_t ptr = 0;
62 CHECK(region->GetMemoryAtAddress(base + 4 * offset, &ptr));
63 u_int32_t value = 0;
64 CHECK(region->GetMemoryAtAddress(ptr, &value));
65 return value;
66}
67
68
69void ReadArray(MinidumpMemoryRegion* region,
70 u_int64_t array_ptr,
71 int size,
72 int* output) {
73 for (int i = 0; i < size; i++) {
74 u_int32_t value;
75 CHECK(region->GetMemoryAtAddress(array_ptr + 4 * i, &value));
76 output[i] = value;
77 }
78}
79
80
81u_int32_t ReadArrayFrom(MinidumpMemoryRegion* region,
82 u_int64_t base,
83 int offset,
84 int size,
85 int* output) {
86 u_int32_t ptr = 0;
87 CHECK(region->GetMemoryAtAddress(base + 4 * offset, &ptr));
88 ReadArray(region, ptr, size, output);
89}
90
91
92double toM(int size) {
93 return size / (1024. * 1024.);
94}
95
96
97class IndirectSorter {
98 public:
99 explicit IndirectSorter(int* a) : a_(a) { }
100
101 bool operator() (int i0, int i1) {
102 return a_[i0] > a_[i1];
103 }
104
105 private:
106 int* a_;
107};
108
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000109
Iain Merrick75681382010-08-19 15:07:18 +0100110void DumpHeapStats(const char *minidump_file) {
111 Minidump minidump(minidump_file);
112 CHECK(minidump.Read());
113
114 MinidumpException *exception = minidump.GetException();
115 CHECK(exception);
116
117 MinidumpContext* crash_context = exception->GetContext();
118 CHECK(crash_context);
119
120 u_int32_t exception_thread_id = 0;
121 CHECK(exception->GetThreadID(&exception_thread_id));
122
123 MinidumpThreadList* thread_list = minidump.GetThreadList();
124 CHECK(thread_list);
125
126 MinidumpThread* exception_thread =
127 thread_list->GetThreadByID(exception_thread_id);
128 CHECK(exception_thread);
129
130 // Currently only 32-bit Windows minidumps are supported.
131 CHECK_EQ(MD_CONTEXT_X86, crash_context->GetContextCPU());
132
133 const MDRawContextX86* contextX86 = crash_context->GetContextX86();
134 CHECK(contextX86);
135
136 const u_int32_t esp = contextX86->esp;
137
138 MinidumpMemoryRegion* memory_region = exception_thread->GetMemory();
139 CHECK(memory_region);
140
141 const u_int64_t last = memory_region->GetBase() + memory_region->GetSize();
142
143 u_int64_t heap_stats_addr = 0;
144 for (u_int64_t addr = esp; addr < last; addr += 4) {
145 u_int32_t value = 0;
146 CHECK(memory_region->GetMemoryAtAddress(addr, &value));
147 if (value >= esp && value < last) {
148 u_int32_t value2 = 0;
149 CHECK(memory_region->GetMemoryAtAddress(value, &value2));
150 if (value2 == v8::internal::HeapStats::kStartMarker) {
151 heap_stats_addr = addr;
152 break;
153 }
154 }
155 }
156 CHECK(heap_stats_addr);
157
158 // Read heap stats.
159
160#define READ_FIELD(offset) \
161 ReadPointedValue(memory_region, heap_stats_addr, offset)
162
163 CHECK(READ_FIELD(0) == v8::internal::HeapStats::kStartMarker);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100164 CHECK(READ_FIELD(24) == v8::internal::HeapStats::kEndMarker);
Iain Merrick75681382010-08-19 15:07:18 +0100165
166 const int new_space_size = READ_FIELD(1);
167 const int new_space_capacity = READ_FIELD(2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000168 const int old_space_size = READ_FIELD(3);
169 const int old_space_capacity = READ_FIELD(4);
170 const int code_space_size = READ_FIELD(5);
171 const int code_space_capacity = READ_FIELD(6);
172 const int map_space_size = READ_FIELD(7);
173 const int map_space_capacity = READ_FIELD(8);
174 const int cell_space_size = READ_FIELD(9);
175 const int cell_space_capacity = READ_FIELD(10);
176 const int lo_space_size = READ_FIELD(11);
177 const int global_handle_count = READ_FIELD(12);
178 const int weak_global_handle_count = READ_FIELD(13);
179 const int pending_global_handle_count = READ_FIELD(14);
180 const int near_death_global_handle_count = READ_FIELD(15);
181 const int destroyed_global_handle_count = READ_FIELD(16);
182 const int memory_allocator_size = READ_FIELD(17);
183 const int memory_allocator_capacity = READ_FIELD(18);
184 const int os_error = READ_FIELD(19);
Iain Merrick75681382010-08-19 15:07:18 +0100185#undef READ_FIELD
186
187 int objects_per_type[v8::internal::LAST_TYPE + 1] = {0};
188 ReadArrayFrom(memory_region, heap_stats_addr, 21,
189 v8::internal::LAST_TYPE + 1, objects_per_type);
190
191 int size_per_type[v8::internal::LAST_TYPE + 1] = {0};
192 ReadArrayFrom(memory_region, heap_stats_addr, 22, v8::internal::LAST_TYPE + 1,
193 size_per_type);
194
195 int js_global_objects =
196 objects_per_type[v8::internal::JS_GLOBAL_OBJECT_TYPE];
197 int js_builtins_objects =
198 objects_per_type[v8::internal::JS_BUILTINS_OBJECT_TYPE];
199 int js_global_proxies =
200 objects_per_type[v8::internal::JS_GLOBAL_PROXY_TYPE];
201
202 int indices[v8::internal::LAST_TYPE + 1];
203 for (int i = 0; i <= v8::internal::LAST_TYPE; i++) {
204 indices[i] = i;
205 }
206
207 std::stable_sort(indices, indices + sizeof(indices)/sizeof(indices[0]),
208 IndirectSorter(size_per_type));
209
210 int total_size = 0;
211 for (int i = 0; i <= v8::internal::LAST_TYPE; i++) {
212 total_size += size_per_type[i];
213 }
214
215 // Print heap stats.
216
217 printf("exception thread ID: %" PRIu32 " (%#" PRIx32 ")\n",
218 exception_thread_id, exception_thread_id);
219 printf("heap stats address: %#" PRIx64 "\n", heap_stats_addr);
220#define PRINT_INT_STAT(stat) \
221 printf("\t%-25s\t% 10d\n", #stat ":", stat);
222#define PRINT_MB_STAT(stat) \
223 printf("\t%-25s\t% 10.3f MB\n", #stat ":", toM(stat));
224 PRINT_MB_STAT(new_space_size);
225 PRINT_MB_STAT(new_space_capacity);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000226 PRINT_MB_STAT(old_space_size);
227 PRINT_MB_STAT(old_space_capacity);
Iain Merrick75681382010-08-19 15:07:18 +0100228 PRINT_MB_STAT(code_space_size);
229 PRINT_MB_STAT(code_space_capacity);
230 PRINT_MB_STAT(map_space_size);
231 PRINT_MB_STAT(map_space_capacity);
232 PRINT_MB_STAT(cell_space_size);
233 PRINT_MB_STAT(cell_space_capacity);
234 PRINT_MB_STAT(lo_space_size);
235 PRINT_INT_STAT(global_handle_count);
236 PRINT_INT_STAT(weak_global_handle_count);
237 PRINT_INT_STAT(pending_global_handle_count);
238 PRINT_INT_STAT(near_death_global_handle_count);
239 PRINT_INT_STAT(destroyed_global_handle_count);
240 PRINT_MB_STAT(memory_allocator_size);
241 PRINT_MB_STAT(memory_allocator_capacity);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100242 PRINT_INT_STAT(os_error);
Iain Merrick75681382010-08-19 15:07:18 +0100243#undef PRINT_STAT
244
245 printf("\n");
246
247 printf(
248 "\tJS_GLOBAL_OBJECT_TYPE/JS_BUILTINS_OBJECT_TYPE/JS_GLOBAL_PROXY_TYPE: "
249 "%d/%d/%d\n\n",
250 js_global_objects, js_builtins_objects, js_global_proxies);
251
252 int running_size = 0;
253 for (int i = 0; i <= v8::internal::LAST_TYPE; i++) {
254 int type = indices[i];
255 const char* name = InstanceTypeToString(type);
256 if (name == NULL) {
257 // Unknown instance type. Check that there is no objects of that type.
258 CHECK_EQ(0, objects_per_type[type]);
259 CHECK_EQ(0, size_per_type[type]);
260 continue;
261 }
262 int size = size_per_type[type];
263 running_size += size;
264 printf("\t%-37s% 9d% 11.3f MB% 10.3f%%% 10.3f%%\n",
265 name, objects_per_type[type], toM(size),
266 100. * size / total_size, 100. * running_size / total_size);
267 }
268 printf("\t%-37s% 9d% 11.3f MB% 10.3f%%% 10.3f%%\n",
269 "total", 0, toM(total_size), 100., 100.);
270}
271
272} // namespace
273
274int main(int argc, char **argv) {
275 if (argc != 2) {
276 fprintf(stderr, "usage: %s <minidump>\n", argv[0]);
277 return 1;
278 }
279
280 DumpHeapStats(argv[1]);
281
282 return 0;
283}