1 // Copyright (c) 2006, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "google_breakpad/processor/minidump_processor.h"
31
32 #include <assert.h>
33
34 #include <string>
35
36 #include "common/scoped_ptr.h"
37 #include "common/stdio_wrapper.h"
38 #include "common/using_std_string.h"
39 #include "google_breakpad/processor/call_stack.h"
40 #include "google_breakpad/processor/minidump.h"
41 #include "google_breakpad/processor/process_state.h"
42 #include "google_breakpad/processor/exploitability.h"
43 #include "google_breakpad/processor/stack_frame_symbolizer.h"
44 #include "processor/logging.h"
45 #include "processor/stackwalker_x86.h"
46 #include "processor/symbolic_constants_win.h"
47
48 namespace google_breakpad {
49
MinidumpProcessor(SymbolSupplier * supplier,SourceLineResolverInterface * resolver)50 MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier,
51 SourceLineResolverInterface *resolver)
52 : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)),
53 own_frame_symbolizer_(true),
54 enable_exploitability_(false),
55 enable_objdump_(false) {
56 }
57
MinidumpProcessor(SymbolSupplier * supplier,SourceLineResolverInterface * resolver,bool enable_exploitability)58 MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier,
59 SourceLineResolverInterface *resolver,
60 bool enable_exploitability)
61 : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)),
62 own_frame_symbolizer_(true),
63 enable_exploitability_(enable_exploitability),
64 enable_objdump_(false) {
65 }
66
MinidumpProcessor(StackFrameSymbolizer * frame_symbolizer,bool enable_exploitability)67 MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer *frame_symbolizer,
68 bool enable_exploitability)
69 : frame_symbolizer_(frame_symbolizer),
70 own_frame_symbolizer_(false),
71 enable_exploitability_(enable_exploitability),
72 enable_objdump_(false) {
73 assert(frame_symbolizer_);
74 }
75
~MinidumpProcessor()76 MinidumpProcessor::~MinidumpProcessor() {
77 if (own_frame_symbolizer_) delete frame_symbolizer_;
78 }
79
Process(Minidump * dump,ProcessState * process_state)80 ProcessResult MinidumpProcessor::Process(
81 Minidump *dump, ProcessState *process_state) {
82 assert(dump);
83 assert(process_state);
84
85 process_state->Clear();
86
87 const MDRawHeader *header = dump->header();
88 if (!header) {
89 BPLOG(ERROR) << "Minidump " << dump->path() << " has no header";
90 return PROCESS_ERROR_NO_MINIDUMP_HEADER;
91 }
92 process_state->time_date_stamp_ = header->time_date_stamp;
93
94 bool has_process_create_time =
95 GetProcessCreateTime(dump, &process_state->process_create_time_);
96
97 bool has_cpu_info = GetCPUInfo(dump, &process_state->system_info_);
98 bool has_os_info = GetOSInfo(dump, &process_state->system_info_);
99
100 uint32_t dump_thread_id = 0;
101 bool has_dump_thread = false;
102 uint32_t requesting_thread_id = 0;
103 bool has_requesting_thread = false;
104
105 MinidumpBreakpadInfo *breakpad_info = dump->GetBreakpadInfo();
106 if (breakpad_info) {
107 has_dump_thread = breakpad_info->GetDumpThreadID(&dump_thread_id);
108 has_requesting_thread =
109 breakpad_info->GetRequestingThreadID(&requesting_thread_id);
110 }
111
112 MinidumpException *exception = dump->GetException();
113 if (exception) {
114 process_state->crashed_ = true;
115 has_requesting_thread = exception->GetThreadID(&requesting_thread_id);
116
117 process_state->crash_reason_ = GetCrashReason(
118 dump, &process_state->crash_address_);
119
120 process_state->exception_record_.set_code(
121 exception->exception()->exception_record.exception_code,
122 // TODO(ivanpe): Populate description.
123 /* description = */ "");
124 process_state->exception_record_.set_flags(
125 exception->exception()->exception_record.exception_flags,
126 // TODO(ivanpe): Populate description.
127 /* description = */ "");
128 process_state->exception_record_.set_nested_exception_record_address(
129 exception->exception()->exception_record.exception_record);
130 process_state->exception_record_.set_address(process_state->crash_address_);
131 for (uint32_t i = 0;
132 i < exception->exception()->exception_record.number_parameters; i++) {
133 process_state->exception_record_.add_parameter(
134 exception->exception()->exception_record.exception_information[i],
135 // TODO(ivanpe): Populate description.
136 /* description = */ "");
137 }
138 }
139
140 // This will just return an empty string if it doesn't exist.
141 process_state->assertion_ = GetAssertion(dump);
142
143 MinidumpModuleList *module_list = dump->GetModuleList();
144
145 // Put a copy of the module list into ProcessState object. This is not
146 // necessarily a MinidumpModuleList, but it adheres to the CodeModules
147 // interface, which is all that ProcessState needs to expose.
148 if (module_list) {
149 process_state->modules_ = module_list->Copy();
150 process_state->shrunk_range_modules_ =
151 process_state->modules_->GetShrunkRangeModules();
152 for (unsigned int i = 0;
153 i < process_state->shrunk_range_modules_.size();
154 i++) {
155 linked_ptr<const CodeModule> module =
156 process_state->shrunk_range_modules_[i];
157 BPLOG(INFO) << "The range for module " << module->code_file()
158 << " was shrunk down by " << HexString(
159 module->shrink_down_delta()) << " bytes. ";
160 }
161 }
162
163 MinidumpUnloadedModuleList *unloaded_module_list =
164 dump->GetUnloadedModuleList();
165 if (unloaded_module_list) {
166 process_state->unloaded_modules_ = unloaded_module_list->Copy();
167 }
168
169 MinidumpMemoryList *memory_list = dump->GetMemoryList();
170 if (memory_list) {
171 BPLOG(INFO) << "Found " << memory_list->region_count()
172 << " memory regions.";
173 }
174
175 MinidumpThreadList *threads = dump->GetThreadList();
176 if (!threads) {
177 BPLOG(ERROR) << "Minidump " << dump->path() << " has no thread list";
178 return PROCESS_ERROR_NO_THREAD_LIST;
179 }
180
181 BPLOG(INFO) << "Minidump " << dump->path() << " has " <<
182 (has_cpu_info ? "" : "no ") << "CPU info, " <<
183 (has_os_info ? "" : "no ") << "OS info, " <<
184 (breakpad_info != NULL ? "" : "no ") << "Breakpad info, " <<
185 (exception != NULL ? "" : "no ") << "exception, " <<
186 (module_list != NULL ? "" : "no ") << "module list, " <<
187 (threads != NULL ? "" : "no ") << "thread list, " <<
188 (has_dump_thread ? "" : "no ") << "dump thread, " <<
189 (has_requesting_thread ? "" : "no ") << "requesting thread, and " <<
190 (has_process_create_time ? "" : "no ") << "process create time";
191
192 bool interrupted = false;
193 bool found_requesting_thread = false;
194 unsigned int thread_count = threads->thread_count();
195
196 // Reset frame_symbolizer_ at the beginning of stackwalk for each minidump.
197 frame_symbolizer_->Reset();
198
199 for (unsigned int thread_index = 0;
200 thread_index < thread_count;
201 ++thread_index) {
202 char thread_string_buffer[64];
203 snprintf(thread_string_buffer, sizeof(thread_string_buffer), "%d/%d",
204 thread_index, thread_count);
205 string thread_string = dump->path() + ":" + thread_string_buffer;
206
207 MinidumpThread *thread = threads->GetThreadAtIndex(thread_index);
208 if (!thread) {
209 BPLOG(ERROR) << "Could not get thread for " << thread_string;
210 return PROCESS_ERROR_GETTING_THREAD;
211 }
212
213 uint32_t thread_id;
214 if (!thread->GetThreadID(&thread_id)) {
215 BPLOG(ERROR) << "Could not get thread ID for " << thread_string;
216 return PROCESS_ERROR_GETTING_THREAD_ID;
217 }
218
219 thread_string += " id " + HexString(thread_id);
220 BPLOG(INFO) << "Looking at thread " << thread_string;
221
222 // If this thread is the thread that produced the minidump, don't process
223 // it. Because of the problems associated with a thread producing a
224 // dump of itself (when both its context and its stack are in flux),
225 // processing that stack wouldn't provide much useful data.
226 if (has_dump_thread && thread_id == dump_thread_id) {
227 continue;
228 }
229
230 MinidumpContext *context = thread->GetContext();
231
232 if (has_requesting_thread && thread_id == requesting_thread_id) {
233 if (found_requesting_thread) {
234 // There can't be more than one requesting thread.
235 BPLOG(ERROR) << "Duplicate requesting thread: " << thread_string;
236 return PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS;
237 }
238
239 // Use processed_state->threads_.size() instead of thread_index.
240 // thread_index points to the thread index in the minidump, which
241 // might be greater than the thread index in the threads vector if
242 // any of the minidump's threads are skipped and not placed into the
243 // processed threads vector. The thread vector's current size will
244 // be the index of the current thread when it's pushed into the
245 // vector.
246 process_state->requesting_thread_ = process_state->threads_.size();
247
248 found_requesting_thread = true;
249
250 if (process_state->crashed_) {
251 // Use the exception record's context for the crashed thread, instead
252 // of the thread's own context. For the crashed thread, the thread's
253 // own context is the state inside the exception handler. Using it
254 // would not result in the expected stack trace from the time of the
255 // crash. If the exception context is invalid, however, we fall back
256 // on the thread context.
257 MinidumpContext *ctx = exception->GetContext();
258 context = ctx ? ctx : thread->GetContext();
259 }
260 }
261
262 // If the memory region for the stack cannot be read using the RVA stored
263 // in the memory descriptor inside MINIDUMP_THREAD, try to locate and use
264 // a memory region (containing the stack) from the minidump memory list.
265 MinidumpMemoryRegion *thread_memory = thread->GetMemory();
266 if (!thread_memory && memory_list) {
267 uint64_t start_stack_memory_range = thread->GetStartOfStackMemoryRange();
268 if (start_stack_memory_range) {
269 thread_memory = memory_list->GetMemoryRegionForAddress(
270 start_stack_memory_range);
271 }
272 }
273 if (!thread_memory) {
274 BPLOG(ERROR) << "No memory region for " << thread_string;
275 }
276
277 // Use process_state->modules_ instead of module_list, because the
278 // |modules| argument will be used to populate the |module| fields in
279 // the returned StackFrame objects, which will be placed into the
280 // returned ProcessState object. module_list's lifetime is only as
281 // long as the Minidump object: it will be deleted when this function
282 // returns. process_state->modules_ is owned by the ProcessState object
283 // (just like the StackFrame objects), and is much more suitable for this
284 // task.
285 scoped_ptr<Stackwalker> stackwalker(
286 Stackwalker::StackwalkerForCPU(process_state->system_info(),
287 context,
288 thread_memory,
289 process_state->modules_,
290 process_state->unloaded_modules_,
291 frame_symbolizer_));
292
293 scoped_ptr<CallStack> stack(new CallStack());
294 if (stackwalker.get()) {
295 if (!stackwalker->Walk(stack.get(),
296 &process_state->modules_without_symbols_,
297 &process_state->modules_with_corrupt_symbols_)) {
298 BPLOG(INFO) << "Stackwalker interrupt (missing symbols?) at "
299 << thread_string;
300 interrupted = true;
301 }
302 } else {
303 // Threads with missing CPU contexts will hit this, but
304 // don't abort processing the rest of the dump just for
305 // one bad thread.
306 BPLOG(ERROR) << "No stackwalker for " << thread_string;
307 }
308 stack->set_tid(thread_id);
309 process_state->threads_.push_back(stack.release());
310 process_state->thread_memory_regions_.push_back(thread_memory);
311 }
312
313 if (interrupted) {
314 BPLOG(INFO) << "Processing interrupted for " << dump->path();
315 return PROCESS_SYMBOL_SUPPLIER_INTERRUPTED;
316 }
317
318 // If a requesting thread was indicated, it must be present.
319 if (has_requesting_thread && !found_requesting_thread) {
320 // Don't mark as an error, but invalidate the requesting thread
321 BPLOG(ERROR) << "Minidump indicated requesting thread " <<
322 HexString(requesting_thread_id) << ", not found in " <<
323 dump->path();
324 process_state->requesting_thread_ = -1;
325 }
326
327 // Exploitability defaults to EXPLOITABILITY_NOT_ANALYZED
328 process_state->exploitability_ = EXPLOITABILITY_NOT_ANALYZED;
329
330 // If an exploitability run was requested we perform the platform specific
331 // rating.
332 if (enable_exploitability_) {
333 scoped_ptr<Exploitability> exploitability(
334 Exploitability::ExploitabilityForPlatform(dump,
335 process_state,
336 enable_objdump_));
337 // The engine will be null if the platform is not supported
338 if (exploitability != NULL) {
339 process_state->exploitability_ = exploitability->CheckExploitability();
340 } else {
341 process_state->exploitability_ = EXPLOITABILITY_ERR_NOENGINE;
342 }
343 }
344
345 BPLOG(INFO) << "Processed " << dump->path();
346 return PROCESS_OK;
347 }
348
Process(const string & minidump_file,ProcessState * process_state)349 ProcessResult MinidumpProcessor::Process(
350 const string &minidump_file, ProcessState *process_state) {
351 BPLOG(INFO) << "Processing minidump in file " << minidump_file;
352
353 Minidump dump(minidump_file);
354 if (!dump.Read()) {
355 BPLOG(ERROR) << "Minidump " << dump.path() << " could not be read";
356 return PROCESS_ERROR_MINIDUMP_NOT_FOUND;
357 }
358
359 return Process(&dump, process_state);
360 }
361
362 // Returns the MDRawSystemInfo from a minidump, or NULL if system info is
363 // not available from the minidump. If system_info is non-NULL, it is used
364 // to pass back the MinidumpSystemInfo object.
GetSystemInfo(Minidump * dump,MinidumpSystemInfo ** system_info)365 static const MDRawSystemInfo* GetSystemInfo(Minidump *dump,
366 MinidumpSystemInfo **system_info) {
367 MinidumpSystemInfo *minidump_system_info = dump->GetSystemInfo();
368 if (!minidump_system_info)
369 return NULL;
370
371 if (system_info)
372 *system_info = minidump_system_info;
373
374 return minidump_system_info->system_info();
375 }
376
GetAddressForArchitecture(const MDCPUArchitecture architecture,size_t raw_address)377 static uint64_t GetAddressForArchitecture(const MDCPUArchitecture architecture,
378 size_t raw_address)
379 {
380 switch (architecture) {
381 case MD_CPU_ARCHITECTURE_X86:
382 case MD_CPU_ARCHITECTURE_MIPS:
383 case MD_CPU_ARCHITECTURE_PPC:
384 case MD_CPU_ARCHITECTURE_SHX:
385 case MD_CPU_ARCHITECTURE_ARM:
386 case MD_CPU_ARCHITECTURE_X86_WIN64:
387 // 32-bit architectures, mask the upper bits.
388 return raw_address & 0xffffffffULL;
389
390 default:
391 // All other architectures either have 64-bit pointers or it's impossible
392 // to tell from the minidump (e.g. MSIL or SPARC) so use 64-bits anyway.
393 return raw_address;
394 }
395 }
396
397 // Extract CPU info string from ARM-specific MDRawSystemInfo structure.
398 // raw_info: pointer to source MDRawSystemInfo.
399 // cpu_info: address of target string, cpu info text will be appended to it.
GetARMCpuInfo(const MDRawSystemInfo * raw_info,string * cpu_info)400 static void GetARMCpuInfo(const MDRawSystemInfo* raw_info,
401 string* cpu_info) {
402 assert(raw_info != NULL && cpu_info != NULL);
403
404 // Write ARM architecture version.
405 char cpu_string[32];
406 snprintf(cpu_string, sizeof(cpu_string), "ARMv%d",
407 raw_info->processor_level);
408 cpu_info->append(cpu_string);
409
410 // There is no good list of implementer id values, but the following
411 // pages provide some help:
412 // http://comments.gmane.org/gmane.linux.linaro.devel/6903
413 // http://forum.xda-developers.com/archive/index.php/t-480226.html
414 const struct {
415 uint32_t id;
416 const char* name;
417 } vendors[] = {
418 { 0x41, "ARM" },
419 { 0x51, "Qualcomm" },
420 { 0x56, "Marvell" },
421 { 0x69, "Intel/Marvell" },
422 };
423 const struct {
424 uint32_t id;
425 const char* name;
426 } parts[] = {
427 { 0x4100c050, "Cortex-A5" },
428 { 0x4100c080, "Cortex-A8" },
429 { 0x4100c090, "Cortex-A9" },
430 { 0x4100c0f0, "Cortex-A15" },
431 { 0x4100c140, "Cortex-R4" },
432 { 0x4100c150, "Cortex-R5" },
433 { 0x4100b360, "ARM1136" },
434 { 0x4100b560, "ARM1156" },
435 { 0x4100b760, "ARM1176" },
436 { 0x4100b020, "ARM11-MPCore" },
437 { 0x41009260, "ARM926" },
438 { 0x41009460, "ARM946" },
439 { 0x41009660, "ARM966" },
440 { 0x510006f0, "Krait" },
441 { 0x510000f0, "Scorpion" },
442 };
443
444 const struct {
445 uint32_t hwcap;
446 const char* name;
447 } features[] = {
448 { MD_CPU_ARM_ELF_HWCAP_SWP, "swp" },
449 { MD_CPU_ARM_ELF_HWCAP_HALF, "half" },
450 { MD_CPU_ARM_ELF_HWCAP_THUMB, "thumb" },
451 { MD_CPU_ARM_ELF_HWCAP_26BIT, "26bit" },
452 { MD_CPU_ARM_ELF_HWCAP_FAST_MULT, "fastmult" },
453 { MD_CPU_ARM_ELF_HWCAP_FPA, "fpa" },
454 { MD_CPU_ARM_ELF_HWCAP_VFP, "vfpv2" },
455 { MD_CPU_ARM_ELF_HWCAP_EDSP, "edsp" },
456 { MD_CPU_ARM_ELF_HWCAP_JAVA, "java" },
457 { MD_CPU_ARM_ELF_HWCAP_IWMMXT, "iwmmxt" },
458 { MD_CPU_ARM_ELF_HWCAP_CRUNCH, "crunch" },
459 { MD_CPU_ARM_ELF_HWCAP_THUMBEE, "thumbee" },
460 { MD_CPU_ARM_ELF_HWCAP_NEON, "neon" },
461 { MD_CPU_ARM_ELF_HWCAP_VFPv3, "vfpv3" },
462 { MD_CPU_ARM_ELF_HWCAP_VFPv3D16, "vfpv3d16" },
463 { MD_CPU_ARM_ELF_HWCAP_TLS, "tls" },
464 { MD_CPU_ARM_ELF_HWCAP_VFPv4, "vfpv4" },
465 { MD_CPU_ARM_ELF_HWCAP_IDIVA, "idiva" },
466 { MD_CPU_ARM_ELF_HWCAP_IDIVT, "idivt" },
467 };
468
469 uint32_t cpuid = raw_info->cpu.arm_cpu_info.cpuid;
470 if (cpuid != 0) {
471 // Extract vendor name from CPUID
472 const char* vendor = NULL;
473 uint32_t vendor_id = (cpuid >> 24) & 0xff;
474 for (size_t i = 0; i < sizeof(vendors)/sizeof(vendors[0]); ++i) {
475 if (vendors[i].id == vendor_id) {
476 vendor = vendors[i].name;
477 break;
478 }
479 }
480 cpu_info->append(" ");
481 if (vendor) {
482 cpu_info->append(vendor);
483 } else {
484 snprintf(cpu_string, sizeof(cpu_string), "vendor(0x%x)", vendor_id);
485 cpu_info->append(cpu_string);
486 }
487
488 // Extract part name from CPUID
489 uint32_t part_id = (cpuid & 0xff00fff0);
490 const char* part = NULL;
491 for (size_t i = 0; i < sizeof(parts)/sizeof(parts[0]); ++i) {
492 if (parts[i].id == part_id) {
493 part = parts[i].name;
494 break;
495 }
496 }
497 cpu_info->append(" ");
498 if (part != NULL) {
499 cpu_info->append(part);
500 } else {
501 snprintf(cpu_string, sizeof(cpu_string), "part(0x%x)", part_id);
502 cpu_info->append(cpu_string);
503 }
504 }
505 uint32_t elf_hwcaps = raw_info->cpu.arm_cpu_info.elf_hwcaps;
506 if (elf_hwcaps != 0) {
507 cpu_info->append(" features: ");
508 const char* comma = "";
509 for (size_t i = 0; i < sizeof(features)/sizeof(features[0]); ++i) {
510 if (elf_hwcaps & features[i].hwcap) {
511 cpu_info->append(comma);
512 cpu_info->append(features[i].name);
513 comma = ",";
514 }
515 }
516 }
517 }
518
519 // static
GetCPUInfo(Minidump * dump,SystemInfo * info)520 bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) {
521 assert(dump);
522 assert(info);
523
524 info->cpu.clear();
525 info->cpu_info.clear();
526
527 MinidumpSystemInfo *system_info;
528 const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info);
529 if (!raw_system_info)
530 return false;
531
532 switch (raw_system_info->processor_architecture) {
533 case MD_CPU_ARCHITECTURE_X86:
534 case MD_CPU_ARCHITECTURE_AMD64: {
535 if (raw_system_info->processor_architecture ==
536 MD_CPU_ARCHITECTURE_X86)
537 info->cpu = "x86";
538 else
539 info->cpu = "amd64";
540
541 const string *cpu_vendor = system_info->GetCPUVendor();
542 if (cpu_vendor) {
543 info->cpu_info = *cpu_vendor;
544 info->cpu_info.append(" ");
545 }
546
547 char x86_info[36];
548 snprintf(x86_info, sizeof(x86_info), "family %u model %u stepping %u",
549 raw_system_info->processor_level,
550 raw_system_info->processor_revision >> 8,
551 raw_system_info->processor_revision & 0xff);
552 info->cpu_info.append(x86_info);
553 break;
554 }
555
556 case MD_CPU_ARCHITECTURE_PPC: {
557 info->cpu = "ppc";
558 break;
559 }
560
561 case MD_CPU_ARCHITECTURE_PPC64: {
562 info->cpu = "ppc64";
563 break;
564 }
565
566 case MD_CPU_ARCHITECTURE_SPARC: {
567 info->cpu = "sparc";
568 break;
569 }
570
571 case MD_CPU_ARCHITECTURE_ARM: {
572 info->cpu = "arm";
573 GetARMCpuInfo(raw_system_info, &info->cpu_info);
574 break;
575 }
576
577 case MD_CPU_ARCHITECTURE_ARM64:
578 case MD_CPU_ARCHITECTURE_ARM64_OLD: {
579 info->cpu = "arm64";
580 break;
581 }
582
583 case MD_CPU_ARCHITECTURE_MIPS: {
584 info->cpu = "mips";
585 break;
586 }
587 case MD_CPU_ARCHITECTURE_MIPS64: {
588 info->cpu = "mips64";
589 break;
590 }
591
592 default: {
593 // Assign the numeric architecture ID into the CPU string.
594 char cpu_string[7];
595 snprintf(cpu_string, sizeof(cpu_string), "0x%04x",
596 raw_system_info->processor_architecture);
597 info->cpu = cpu_string;
598 break;
599 }
600 }
601
602 info->cpu_count = raw_system_info->number_of_processors;
603
604 return true;
605 }
606
607 // static
GetOSInfo(Minidump * dump,SystemInfo * info)608 bool MinidumpProcessor::GetOSInfo(Minidump *dump, SystemInfo *info) {
609 assert(dump);
610 assert(info);
611
612 info->os.clear();
613 info->os_short.clear();
614 info->os_version.clear();
615
616 MinidumpSystemInfo *system_info;
617 const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info);
618 if (!raw_system_info)
619 return false;
620
621 info->os_short = system_info->GetOS();
622
623 switch (raw_system_info->platform_id) {
624 case MD_OS_WIN32_NT: {
625 info->os = "Windows NT";
626 break;
627 }
628
629 case MD_OS_WIN32_WINDOWS: {
630 info->os = "Windows";
631 break;
632 }
633
634 case MD_OS_MAC_OS_X: {
635 info->os = "Mac OS X";
636 break;
637 }
638
639 case MD_OS_IOS: {
640 info->os = "iOS";
641 break;
642 }
643
644 case MD_OS_LINUX: {
645 info->os = "Linux";
646 break;
647 }
648
649 case MD_OS_SOLARIS: {
650 info->os = "Solaris";
651 break;
652 }
653
654 case MD_OS_ANDROID: {
655 info->os = "Android";
656 break;
657 }
658
659 case MD_OS_PS3: {
660 info->os = "PS3";
661 break;
662 }
663
664 case MD_OS_NACL: {
665 info->os = "NaCl";
666 break;
667 }
668
669 case MD_OS_FUCHSIA: {
670 info->os = "Fuchsia";
671 break;
672 }
673
674 default: {
675 // Assign the numeric platform ID into the OS string.
676 char os_string[11];
677 snprintf(os_string, sizeof(os_string), "0x%08x",
678 raw_system_info->platform_id);
679 info->os = os_string;
680 break;
681 }
682 }
683
684 char os_version_string[33];
685 snprintf(os_version_string, sizeof(os_version_string), "%u.%u.%u",
686 raw_system_info->major_version,
687 raw_system_info->minor_version,
688 raw_system_info->build_number);
689 info->os_version = os_version_string;
690
691 const string *csd_version = system_info->GetCSDVersion();
692 if (csd_version) {
693 info->os_version.append(" ");
694 info->os_version.append(*csd_version);
695 }
696
697 return true;
698 }
699
700 // static
GetProcessCreateTime(Minidump * dump,uint32_t * process_create_time)701 bool MinidumpProcessor::GetProcessCreateTime(Minidump* dump,
702 uint32_t* process_create_time) {
703 assert(dump);
704 assert(process_create_time);
705
706 *process_create_time = 0;
707
708 MinidumpMiscInfo* minidump_misc_info = dump->GetMiscInfo();
709 if (!minidump_misc_info) {
710 return false;
711 }
712
713 const MDRawMiscInfo* md_raw_misc_info = minidump_misc_info->misc_info();
714 if (!md_raw_misc_info) {
715 return false;
716 }
717
718 if (!(md_raw_misc_info->flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES)) {
719 return false;
720 }
721
722 *process_create_time = md_raw_misc_info->process_create_time;
723 return true;
724 }
725
726 // static
GetCrashReason(Minidump * dump,uint64_t * address)727 string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) {
728 MinidumpException *exception = dump->GetException();
729 if (!exception)
730 return "";
731
732 const MDRawExceptionStream *raw_exception = exception->exception();
733 if (!raw_exception)
734 return "";
735
736 if (address)
737 *address = raw_exception->exception_record.exception_address;
738
739 // The reason value is OS-specific and possibly CPU-specific. Set up
740 // sensible numeric defaults for the reason string in case we can't
741 // map the codes to a string (because there's no system info, or because
742 // it's an unrecognized platform, or because it's an unrecognized code.)
743 char reason_string[24];
744 char flags_string[11];
745 uint32_t exception_code = raw_exception->exception_record.exception_code;
746 uint32_t exception_flags = raw_exception->exception_record.exception_flags;
747 snprintf(flags_string, sizeof(flags_string), "0x%08x", exception_flags);
748 snprintf(reason_string, sizeof(reason_string), "0x%08x / %s", exception_code,
749 flags_string);
750 string reason = reason_string;
751
752 const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, NULL);
753 if (!raw_system_info)
754 return reason;
755
756 switch (raw_system_info->platform_id) {
757 case MD_OS_FUCHSIA: {
758 switch (exception_code) {
759 case MD_EXCEPTION_CODE_FUCHSIA_GENERAL:
760 reason = "GENERAL / ";
761 reason.append(flags_string);
762 break;
763 case MD_EXCEPTION_CODE_FUCHSIA_FATAL_PAGE_FAULT:
764 reason = "FATAL_PAGE_FAULT / ";
765 reason.append(flags_string);
766 break;
767 case MD_EXCEPTION_CODE_FUCHSIA_UNDEFINED_INSTRUCTION:
768 reason = "UNDEFINED_INSTRUCTION / ";
769 reason.append(flags_string);
770 break;
771 case MD_EXCEPTION_CODE_FUCHSIA_SW_BREAKPOINT:
772 reason = "SW_BREAKPOINT / ";
773 reason.append(flags_string);
774 break;
775 case MD_EXCEPTION_CODE_FUCHSIA_HW_BREAKPOINT:
776 reason = "HW_BREAKPOINT / ";
777 reason.append(flags_string);
778 break;
779 case MD_EXCEPTION_CODE_FUCHSIA_UNALIGNED_ACCESS:
780 reason = "UNALIGNED_ACCESS / ";
781 reason.append(flags_string);
782 break;
783 case MD_EXCEPTION_CODE_FUCHSIA_THREAD_STARTING:
784 reason = "THREAD_STARTING / ";
785 reason.append(flags_string);
786 break;
787 case MD_EXCEPTION_CODE_FUCHSIA_THREAD_EXITING:
788 reason = "THREAD_EXITING / ";
789 reason.append(flags_string);
790 break;
791 case MD_EXCEPTION_CODE_FUCHSIA_POLICY_ERROR:
792 reason = "POLICY_ERROR / ";
793 reason.append(flags_string);
794 break;
795 case MD_EXCEPTION_CODE_FUCHSIA_PROCESS_STARTING:
796 reason = "PROCESS_STARTING / ";
797 reason.append(flags_string);
798 break;
799 default:
800 BPLOG(INFO) << "Unknown exception reason " << reason;
801 }
802 break;
803 }
804
805 case MD_OS_MAC_OS_X:
806 case MD_OS_IOS: {
807 switch (exception_code) {
808 case MD_EXCEPTION_MAC_BAD_ACCESS:
809 reason = "EXC_BAD_ACCESS / ";
810 switch (exception_flags) {
811 case MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS:
812 reason.append("KERN_INVALID_ADDRESS");
813 break;
814 case MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE:
815 reason.append("KERN_PROTECTION_FAILURE");
816 break;
817 case MD_EXCEPTION_CODE_MAC_NO_ACCESS:
818 reason.append("KERN_NO_ACCESS");
819 break;
820 case MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE:
821 reason.append("KERN_MEMORY_FAILURE");
822 break;
823 case MD_EXCEPTION_CODE_MAC_MEMORY_ERROR:
824 reason.append("KERN_MEMORY_ERROR");
825 break;
826 case MD_EXCEPTION_CODE_MAC_CODESIGN_ERROR:
827 reason.append("KERN_CODESIGN_ERROR");
828 break;
829 default:
830 // arm and ppc overlap
831 if (raw_system_info->processor_architecture ==
832 MD_CPU_ARCHITECTURE_ARM ||
833 raw_system_info->processor_architecture ==
834 MD_CPU_ARCHITECTURE_ARM64_OLD) {
835 switch (exception_flags) {
836 case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN:
837 reason.append("EXC_ARM_DA_ALIGN");
838 break;
839 case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG:
840 reason.append("EXC_ARM_DA_DEBUG");
841 break;
842 default:
843 reason.append(flags_string);
844 BPLOG(INFO) << "Unknown exception reason " << reason;
845 break;
846 }
847 } else if (raw_system_info->processor_architecture ==
848 MD_CPU_ARCHITECTURE_PPC) {
849 switch (exception_flags) {
850 case MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ:
851 reason.append("EXC_PPC_VM_PROT_READ");
852 break;
853 case MD_EXCEPTION_CODE_MAC_PPC_BADSPACE:
854 reason.append("EXC_PPC_BADSPACE");
855 break;
856 case MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED:
857 reason.append("EXC_PPC_UNALIGNED");
858 break;
859 default:
860 reason.append(flags_string);
861 BPLOG(INFO) << "Unknown exception reason " << reason;
862 break;
863 }
864 } else if (raw_system_info->processor_architecture ==
865 MD_CPU_ARCHITECTURE_X86 ||
866 raw_system_info->processor_architecture ==
867 MD_CPU_ARCHITECTURE_AMD64) {
868 switch (exception_flags) {
869 case MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT:
870 reason.append("EXC_I386_GPFLT");
871 break;
872 default:
873 reason.append(flags_string);
874 BPLOG(INFO) << "Unknown exception reason " << reason;
875 break;
876 }
877 } else {
878 reason.append(flags_string);
879 BPLOG(INFO) << "Unknown exception reason " << reason;
880 }
881 break;
882 }
883 break;
884 case MD_EXCEPTION_MAC_BAD_INSTRUCTION:
885 reason = "EXC_BAD_INSTRUCTION / ";
886 switch (raw_system_info->processor_architecture) {
887 case MD_CPU_ARCHITECTURE_ARM:
888 case MD_CPU_ARCHITECTURE_ARM64_OLD: {
889 switch (exception_flags) {
890 case MD_EXCEPTION_CODE_MAC_ARM_UNDEFINED:
891 reason.append("EXC_ARM_UNDEFINED");
892 break;
893 default:
894 reason.append(flags_string);
895 BPLOG(INFO) << "Unknown exception reason " << reason;
896 break;
897 }
898 break;
899 }
900 case MD_CPU_ARCHITECTURE_PPC: {
901 switch (exception_flags) {
902 case MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL:
903 reason.append("EXC_PPC_INVALID_SYSCALL");
904 break;
905 case MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION:
906 reason.append("EXC_PPC_UNIPL_INST");
907 break;
908 case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION:
909 reason.append("EXC_PPC_PRIVINST");
910 break;
911 case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER:
912 reason.append("EXC_PPC_PRIVREG");
913 break;
914 case MD_EXCEPTION_CODE_MAC_PPC_TRACE:
915 reason.append("EXC_PPC_TRACE");
916 break;
917 case MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR:
918 reason.append("EXC_PPC_PERFMON");
919 break;
920 default:
921 reason.append(flags_string);
922 BPLOG(INFO) << "Unknown exception reason " << reason;
923 break;
924 }
925 break;
926 }
927 case MD_CPU_ARCHITECTURE_AMD64:
928 case MD_CPU_ARCHITECTURE_X86: {
929 switch (exception_flags) {
930 case MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION:
931 reason.append("EXC_I386_INVOP");
932 break;
933 case MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT:
934 reason.append("EXC_I386_INVTSSFLT");
935 break;
936 case MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT:
937 reason.append("EXC_I386_SEGNPFLT");
938 break;
939 case MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT:
940 reason.append("EXC_I386_STKFLT");
941 break;
942 case MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT:
943 reason.append("EXC_I386_GPFLT");
944 break;
945 case MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT:
946 reason.append("EXC_I386_ALIGNFLT");
947 break;
948 default:
949 reason.append(flags_string);
950 BPLOG(INFO) << "Unknown exception reason " << reason;
951 break;
952 }
953 break;
954 }
955 default:
956 reason.append(flags_string);
957 BPLOG(INFO) << "Unknown exception reason " << reason;
958 break;
959 }
960 break;
961 case MD_EXCEPTION_MAC_ARITHMETIC:
962 reason = "EXC_ARITHMETIC / ";
963 switch (raw_system_info->processor_architecture) {
964 case MD_CPU_ARCHITECTURE_PPC: {
965 switch (exception_flags) {
966 case MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW:
967 reason.append("EXC_PPC_OVERFLOW");
968 break;
969 case MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE:
970 reason.append("EXC_PPC_ZERO_DIVIDE");
971 break;
972 case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT:
973 reason.append("EXC_FLT_INEXACT");
974 break;
975 case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE:
976 reason.append("EXC_PPC_FLT_ZERO_DIVIDE");
977 break;
978 case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW:
979 reason.append("EXC_PPC_FLT_UNDERFLOW");
980 break;
981 case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW:
982 reason.append("EXC_PPC_FLT_OVERFLOW");
983 break;
984 case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER:
985 reason.append("EXC_PPC_FLT_NOT_A_NUMBER");
986 break;
987 case MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION:
988 reason.append("EXC_PPC_NOEMULATION");
989 break;
990 case MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST:
991 reason.append("EXC_PPC_ALTIVECASSIST");
992 break;
993 default:
994 reason.append(flags_string);
995 BPLOG(INFO) << "Unknown exception reason " << reason;
996 break;
997 }
998 break;
999 }
1000 case MD_CPU_ARCHITECTURE_AMD64:
1001 case MD_CPU_ARCHITECTURE_X86: {
1002 switch (exception_flags) {
1003 case MD_EXCEPTION_CODE_MAC_X86_DIV:
1004 reason.append("EXC_I386_DIV");
1005 break;
1006 case MD_EXCEPTION_CODE_MAC_X86_INTO:
1007 reason.append("EXC_I386_INTO");
1008 break;
1009 case MD_EXCEPTION_CODE_MAC_X86_NOEXT:
1010 reason.append("EXC_I386_NOEXT");
1011 break;
1012 case MD_EXCEPTION_CODE_MAC_X86_EXTOVR:
1013 reason.append("EXC_I386_EXTOVR");
1014 break;
1015 case MD_EXCEPTION_CODE_MAC_X86_EXTERR:
1016 reason.append("EXC_I386_EXTERR");
1017 break;
1018 case MD_EXCEPTION_CODE_MAC_X86_EMERR:
1019 reason.append("EXC_I386_EMERR");
1020 break;
1021 case MD_EXCEPTION_CODE_MAC_X86_BOUND:
1022 reason.append("EXC_I386_BOUND");
1023 break;
1024 case MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR:
1025 reason.append("EXC_I386_SSEEXTERR");
1026 break;
1027 default:
1028 reason.append(flags_string);
1029 BPLOG(INFO) << "Unknown exception reason " << reason;
1030 break;
1031 }
1032 break;
1033 }
1034 default:
1035 reason.append(flags_string);
1036 BPLOG(INFO) << "Unknown exception reason " << reason;
1037 break;
1038 }
1039 break;
1040 case MD_EXCEPTION_MAC_EMULATION:
1041 reason = "EXC_EMULATION / ";
1042 reason.append(flags_string);
1043 break;
1044 case MD_EXCEPTION_MAC_SOFTWARE:
1045 reason = "EXC_SOFTWARE / ";
1046 switch (exception_flags) {
1047 case MD_EXCEPTION_CODE_MAC_ABORT:
1048 reason.append("SIGABRT");
1049 break;
1050 case MD_EXCEPTION_CODE_MAC_NS_EXCEPTION:
1051 reason.append("UNCAUGHT_NS_EXCEPTION");
1052 break;
1053 // These are ppc only but shouldn't be a problem as they're
1054 // unused on x86
1055 case MD_EXCEPTION_CODE_MAC_PPC_TRAP:
1056 reason.append("EXC_PPC_TRAP");
1057 break;
1058 case MD_EXCEPTION_CODE_MAC_PPC_MIGRATE:
1059 reason.append("EXC_PPC_MIGRATE");
1060 break;
1061 default:
1062 reason.append(flags_string);
1063 BPLOG(INFO) << "Unknown exception reason " << reason;
1064 break;
1065 }
1066 break;
1067 case MD_EXCEPTION_MAC_BREAKPOINT:
1068 reason = "EXC_BREAKPOINT / ";
1069 switch (raw_system_info->processor_architecture) {
1070 case MD_CPU_ARCHITECTURE_ARM:
1071 case MD_CPU_ARCHITECTURE_ARM64_OLD: {
1072 switch (exception_flags) {
1073 case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN:
1074 reason.append("EXC_ARM_DA_ALIGN");
1075 break;
1076 case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG:
1077 reason.append("EXC_ARM_DA_DEBUG");
1078 break;
1079 case MD_EXCEPTION_CODE_MAC_ARM_BREAKPOINT:
1080 reason.append("EXC_ARM_BREAKPOINT");
1081 break;
1082 default:
1083 reason.append(flags_string);
1084 BPLOG(INFO) << "Unknown exception reason " << reason;
1085 break;
1086 }
1087 break;
1088 }
1089 case MD_CPU_ARCHITECTURE_PPC: {
1090 switch (exception_flags) {
1091 case MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT:
1092 reason.append("EXC_PPC_BREAKPOINT");
1093 break;
1094 default:
1095 reason.append(flags_string);
1096 BPLOG(INFO) << "Unknown exception reason " << reason;
1097 break;
1098 }
1099 break;
1100 }
1101 case MD_CPU_ARCHITECTURE_AMD64:
1102 case MD_CPU_ARCHITECTURE_X86: {
1103 switch (exception_flags) {
1104 case MD_EXCEPTION_CODE_MAC_X86_SGL:
1105 reason.append("EXC_I386_SGL");
1106 break;
1107 case MD_EXCEPTION_CODE_MAC_X86_BPT:
1108 reason.append("EXC_I386_BPT");
1109 break;
1110 default:
1111 reason.append(flags_string);
1112 BPLOG(INFO) << "Unknown exception reason " << reason;
1113 break;
1114 }
1115 break;
1116 }
1117 default:
1118 reason.append(flags_string);
1119 BPLOG(INFO) << "Unknown exception reason " << reason;
1120 break;
1121 }
1122 break;
1123 case MD_EXCEPTION_MAC_SYSCALL:
1124 reason = "EXC_SYSCALL / ";
1125 reason.append(flags_string);
1126 break;
1127 case MD_EXCEPTION_MAC_MACH_SYSCALL:
1128 reason = "EXC_MACH_SYSCALL / ";
1129 reason.append(flags_string);
1130 break;
1131 case MD_EXCEPTION_MAC_RPC_ALERT:
1132 reason = "EXC_RPC_ALERT / ";
1133 reason.append(flags_string);
1134 break;
1135 case MD_EXCEPTION_MAC_SIMULATED:
1136 reason = "Simulated Exception";
1137 break;
1138 }
1139 break;
1140 }
1141
1142 case MD_OS_WIN32_NT:
1143 case MD_OS_WIN32_WINDOWS: {
1144 switch (exception_code) {
1145 case MD_EXCEPTION_CODE_WIN_CONTROL_C:
1146 reason = "DBG_CONTROL_C";
1147 break;
1148 case MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION:
1149 reason = "EXCEPTION_GUARD_PAGE";
1150 break;
1151 case MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT:
1152 reason = "EXCEPTION_DATATYPE_MISALIGNMENT";
1153 break;
1154 case MD_EXCEPTION_CODE_WIN_BREAKPOINT:
1155 reason = "EXCEPTION_BREAKPOINT";
1156 break;
1157 case MD_EXCEPTION_CODE_WIN_SINGLE_STEP:
1158 reason = "EXCEPTION_SINGLE_STEP";
1159 break;
1160 case MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION:
1161 // For EXCEPTION_ACCESS_VIOLATION, Windows puts the address that
1162 // caused the fault in exception_information[1].
1163 // exception_information[0] is 0 if the violation was caused by
1164 // an attempt to read data, 1 if it was an attempt to write data,
1165 // and 8 if this was a data execution violation.
1166 // This information is useful in addition to the code address, which
1167 // will be present in the crash thread's instruction field anyway.
1168 if (raw_exception->exception_record.number_parameters >= 1) {
1169 MDAccessViolationTypeWin av_type =
1170 static_cast<MDAccessViolationTypeWin>
1171 (raw_exception->exception_record.exception_information[0]);
1172 switch (av_type) {
1173 case MD_ACCESS_VIOLATION_WIN_READ:
1174 reason = "EXCEPTION_ACCESS_VIOLATION_READ";
1175 break;
1176 case MD_ACCESS_VIOLATION_WIN_WRITE:
1177 reason = "EXCEPTION_ACCESS_VIOLATION_WRITE";
1178 break;
1179 case MD_ACCESS_VIOLATION_WIN_EXEC:
1180 reason = "EXCEPTION_ACCESS_VIOLATION_EXEC";
1181 break;
1182 default:
1183 reason = "EXCEPTION_ACCESS_VIOLATION";
1184 break;
1185 }
1186 } else {
1187 reason = "EXCEPTION_ACCESS_VIOLATION";
1188 }
1189 if (address &&
1190 raw_exception->exception_record.number_parameters >= 2) {
1191 *address =
1192 raw_exception->exception_record.exception_information[1];
1193 }
1194 break;
1195 case MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR:
1196 // For EXCEPTION_IN_PAGE_ERROR, Windows puts the address that
1197 // caused the fault in exception_information[1].
1198 // exception_information[0] is 0 if the violation was caused by
1199 // an attempt to read data, 1 if it was an attempt to write data,
1200 // and 8 if this was a data execution violation.
1201 // exception_information[2] contains the underlying NTSTATUS code,
1202 // which is the explanation for why this error occured.
1203 // This information is useful in addition to the code address, which
1204 // will be present in the crash thread's instruction field anyway.
1205 if (raw_exception->exception_record.number_parameters >= 1) {
1206 MDInPageErrorTypeWin av_type =
1207 static_cast<MDInPageErrorTypeWin>
1208 (raw_exception->exception_record.exception_information[0]);
1209 switch (av_type) {
1210 case MD_IN_PAGE_ERROR_WIN_READ:
1211 reason = "EXCEPTION_IN_PAGE_ERROR_READ";
1212 break;
1213 case MD_IN_PAGE_ERROR_WIN_WRITE:
1214 reason = "EXCEPTION_IN_PAGE_ERROR_WRITE";
1215 break;
1216 case MD_IN_PAGE_ERROR_WIN_EXEC:
1217 reason = "EXCEPTION_IN_PAGE_ERROR_EXEC";
1218 break;
1219 default:
1220 reason = "EXCEPTION_IN_PAGE_ERROR";
1221 break;
1222 }
1223 } else {
1224 reason = "EXCEPTION_IN_PAGE_ERROR";
1225 }
1226 if (address &&
1227 raw_exception->exception_record.number_parameters >= 2) {
1228 *address =
1229 raw_exception->exception_record.exception_information[1];
1230 }
1231 if (raw_exception->exception_record.number_parameters >= 3) {
1232 uint32_t ntstatus =
1233 static_cast<uint32_t>
1234 (raw_exception->exception_record.exception_information[2]);
1235 reason.append(" / ");
1236 reason.append(NTStatusToString(ntstatus));
1237 }
1238 break;
1239 case MD_EXCEPTION_CODE_WIN_INVALID_HANDLE:
1240 reason = "EXCEPTION_INVALID_HANDLE";
1241 break;
1242 case MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION:
1243 reason = "EXCEPTION_ILLEGAL_INSTRUCTION";
1244 break;
1245 case MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION:
1246 reason = "EXCEPTION_NONCONTINUABLE_EXCEPTION";
1247 break;
1248 case MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION:
1249 reason = "EXCEPTION_INVALID_DISPOSITION";
1250 break;
1251 case MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED:
1252 reason = "EXCEPTION_BOUNDS_EXCEEDED";
1253 break;
1254 case MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND:
1255 reason = "EXCEPTION_FLT_DENORMAL_OPERAND";
1256 break;
1257 case MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO:
1258 reason = "EXCEPTION_FLT_DIVIDE_BY_ZERO";
1259 break;
1260 case MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT:
1261 reason = "EXCEPTION_FLT_INEXACT_RESULT";
1262 break;
1263 case MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION:
1264 reason = "EXCEPTION_FLT_INVALID_OPERATION";
1265 break;
1266 case MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW:
1267 reason = "EXCEPTION_FLT_OVERFLOW";
1268 break;
1269 case MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK:
1270 reason = "EXCEPTION_FLT_STACK_CHECK";
1271 break;
1272 case MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW:
1273 reason = "EXCEPTION_FLT_UNDERFLOW";
1274 break;
1275 case MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO:
1276 reason = "EXCEPTION_INT_DIVIDE_BY_ZERO";
1277 break;
1278 case MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW:
1279 reason = "EXCEPTION_INT_OVERFLOW";
1280 break;
1281 case MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION:
1282 reason = "EXCEPTION_PRIV_INSTRUCTION";
1283 break;
1284 case MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW:
1285 reason = "EXCEPTION_STACK_OVERFLOW";
1286 break;
1287 case MD_EXCEPTION_CODE_WIN_BAD_FUNCTION_TABLE:
1288 reason = "EXCEPTION_BAD_FUNCTION_TABLE";
1289 break;
1290 case MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK:
1291 reason = "EXCEPTION_POSSIBLE_DEADLOCK";
1292 break;
1293 case MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN:
1294 reason = "EXCEPTION_STACK_BUFFER_OVERRUN";
1295 break;
1296 case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION:
1297 reason = "EXCEPTION_HEAP_CORRUPTION";
1298 break;
1299 case MD_EXCEPTION_OUT_OF_MEMORY:
1300 reason = "Out of Memory";
1301 break;
1302 case MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION:
1303 reason = "Unhandled C++ Exception";
1304 break;
1305 case MD_EXCEPTION_CODE_WIN_SIMULATED:
1306 reason = "Simulated Exception";
1307 break;
1308 default:
1309 BPLOG(INFO) << "Unknown exception reason " << reason;
1310 break;
1311 }
1312 break;
1313 }
1314
1315 case MD_OS_ANDROID:
1316 case MD_OS_LINUX: {
1317 switch (exception_code) {
1318 case MD_EXCEPTION_CODE_LIN_SIGHUP:
1319 reason = "SIGHUP";
1320 break;
1321 case MD_EXCEPTION_CODE_LIN_SIGINT:
1322 reason = "SIGINT";
1323 break;
1324 case MD_EXCEPTION_CODE_LIN_SIGQUIT:
1325 reason = "SIGQUIT";
1326 break;
1327 case MD_EXCEPTION_CODE_LIN_SIGILL:
1328 reason = "SIGILL / ";
1329 switch (exception_flags) {
1330 case MD_EXCEPTION_FLAG_LIN_ILL_ILLOPC:
1331 reason.append("ILL_ILLOPC");
1332 break;
1333 case MD_EXCEPTION_FLAG_LIN_ILL_ILLOPN:
1334 reason.append("ILL_ILLOPN");
1335 break;
1336 case MD_EXCEPTION_FLAG_LIN_ILL_ILLADR:
1337 reason.append("ILL_ILLADR");
1338 break;
1339 case MD_EXCEPTION_FLAG_LIN_ILL_ILLTRP:
1340 reason.append("ILL_ILLTRP");
1341 break;
1342 case MD_EXCEPTION_FLAG_LIN_ILL_PRVOPC:
1343 reason.append("ILL_PRVOPC");
1344 break;
1345 case MD_EXCEPTION_FLAG_LIN_ILL_PRVREG:
1346 reason.append("ILL_PRVREG");
1347 break;
1348 case MD_EXCEPTION_FLAG_LIN_ILL_COPROC:
1349 reason.append("ILL_COPROC");
1350 break;
1351 case MD_EXCEPTION_FLAG_LIN_ILL_BADSTK:
1352 reason.append("ILL_BADSTK");
1353 break;
1354 default:
1355 reason.append(flags_string);
1356 BPLOG(INFO) << "Unknown exception reason " << reason;
1357 break;
1358 }
1359 break;
1360 case MD_EXCEPTION_CODE_LIN_SIGTRAP:
1361 reason = "SIGTRAP";
1362 break;
1363 case MD_EXCEPTION_CODE_LIN_SIGABRT:
1364 reason = "SIGABRT";
1365 break;
1366 case MD_EXCEPTION_CODE_LIN_SIGBUS:
1367 reason = "SIGBUS / ";
1368 switch (exception_flags) {
1369 case MD_EXCEPTION_FLAG_LIN_BUS_ADRALN:
1370 reason.append("BUS_ADRALN");
1371 break;
1372 case MD_EXCEPTION_FLAG_LIN_BUS_ADRERR:
1373 reason.append("BUS_ADRERR");
1374 break;
1375 case MD_EXCEPTION_FLAG_LIN_BUS_OBJERR:
1376 reason.append("BUS_OBJERR");
1377 break;
1378 case MD_EXCEPTION_FLAG_LIN_BUS_MCEERR_AR:
1379 reason.append("BUS_MCEERR_AR");
1380 break;
1381 case MD_EXCEPTION_FLAG_LIN_BUS_MCEERR_AO:
1382 reason.append("BUS_MCEERR_AO");
1383 break;
1384 default:
1385 reason.append(flags_string);
1386 BPLOG(INFO) << "Unknown exception reason " << reason;
1387 break;
1388 }
1389 break;
1390 case MD_EXCEPTION_CODE_LIN_SIGFPE:
1391 reason = "SIGFPE / ";
1392 switch (exception_flags) {
1393 case MD_EXCEPTION_FLAG_LIN_FPE_INTDIV:
1394 reason.append("FPE_INTDIV");
1395 break;
1396 case MD_EXCEPTION_FLAG_LIN_FPE_INTOVF:
1397 reason.append("FPE_INTOVF");
1398 break;
1399 case MD_EXCEPTION_FLAG_LIN_FPE_FLTDIV:
1400 reason.append("FPE_FLTDIV");
1401 break;
1402 case MD_EXCEPTION_FLAG_LIN_FPE_FLTOVF:
1403 reason.append("FPE_FLTOVF");
1404 break;
1405 case MD_EXCEPTION_FLAG_LIN_FPE_FLTUND:
1406 reason.append("FPE_FLTUND");
1407 break;
1408 case MD_EXCEPTION_FLAG_LIN_FPE_FLTRES:
1409 reason.append("FPE_FLTRES");
1410 break;
1411 case MD_EXCEPTION_FLAG_LIN_FPE_FLTINV:
1412 reason.append("FPE_FLTINV");
1413 break;
1414 case MD_EXCEPTION_FLAG_LIN_FPE_FLTSUB:
1415 reason.append("FPE_FLTSUB");
1416 break;
1417 default:
1418 reason.append(flags_string);
1419 BPLOG(INFO) << "Unknown exception reason " << reason;
1420 break;
1421 }
1422 break;
1423 case MD_EXCEPTION_CODE_LIN_SIGKILL:
1424 reason = "SIGKILL";
1425 break;
1426 case MD_EXCEPTION_CODE_LIN_SIGUSR1:
1427 reason = "SIGUSR1";
1428 break;
1429 case MD_EXCEPTION_CODE_LIN_SIGSEGV:
1430 reason = "SIGSEGV /";
1431 switch (exception_flags) {
1432 case MD_EXCEPTION_FLAG_LIN_SEGV_MAPERR:
1433 reason.append("SEGV_MAPERR");
1434 break;
1435 case MD_EXCEPTION_FLAG_LIN_SEGV_ACCERR:
1436 reason.append("SEGV_ACCERR");
1437 break;
1438 case MD_EXCEPTION_FLAG_LIN_SEGV_BNDERR:
1439 reason.append("SEGV_BNDERR");
1440 break;
1441 case MD_EXCEPTION_FLAG_LIN_SEGV_PKUERR:
1442 reason.append("SEGV_PKUERR");
1443 break;
1444 default:
1445 reason.append(flags_string);
1446 BPLOG(INFO) << "Unknown exception reason " << reason;
1447 break;
1448 }
1449 break;
1450 case MD_EXCEPTION_CODE_LIN_SIGUSR2:
1451 reason = "SIGUSR2";
1452 break;
1453 case MD_EXCEPTION_CODE_LIN_SIGPIPE:
1454 reason = "SIGPIPE";
1455 break;
1456 case MD_EXCEPTION_CODE_LIN_SIGALRM:
1457 reason = "SIGALRM";
1458 break;
1459 case MD_EXCEPTION_CODE_LIN_SIGTERM:
1460 reason = "SIGTERM";
1461 break;
1462 case MD_EXCEPTION_CODE_LIN_SIGSTKFLT:
1463 reason = "SIGSTKFLT";
1464 break;
1465 case MD_EXCEPTION_CODE_LIN_SIGCHLD:
1466 reason = "SIGCHLD";
1467 break;
1468 case MD_EXCEPTION_CODE_LIN_SIGCONT:
1469 reason = "SIGCONT";
1470 break;
1471 case MD_EXCEPTION_CODE_LIN_SIGSTOP:
1472 reason = "SIGSTOP";
1473 break;
1474 case MD_EXCEPTION_CODE_LIN_SIGTSTP:
1475 reason = "SIGTSTP";
1476 break;
1477 case MD_EXCEPTION_CODE_LIN_SIGTTIN:
1478 reason = "SIGTTIN";
1479 break;
1480 case MD_EXCEPTION_CODE_LIN_SIGTTOU:
1481 reason = "SIGTTOU";
1482 break;
1483 case MD_EXCEPTION_CODE_LIN_SIGURG:
1484 reason = "SIGURG";
1485 break;
1486 case MD_EXCEPTION_CODE_LIN_SIGXCPU:
1487 reason = "SIGXCPU";
1488 break;
1489 case MD_EXCEPTION_CODE_LIN_SIGXFSZ:
1490 reason = "SIGXFSZ";
1491 break;
1492 case MD_EXCEPTION_CODE_LIN_SIGVTALRM:
1493 reason = "SIGVTALRM";
1494 break;
1495 case MD_EXCEPTION_CODE_LIN_SIGPROF:
1496 reason = "SIGPROF";
1497 break;
1498 case MD_EXCEPTION_CODE_LIN_SIGWINCH:
1499 reason = "SIGWINCH";
1500 break;
1501 case MD_EXCEPTION_CODE_LIN_SIGIO:
1502 reason = "SIGIO";
1503 break;
1504 case MD_EXCEPTION_CODE_LIN_SIGPWR:
1505 reason = "SIGPWR";
1506 break;
1507 case MD_EXCEPTION_CODE_LIN_SIGSYS:
1508 reason = "SIGSYS";
1509 break;
1510 case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED:
1511 reason = "DUMP_REQUESTED";
1512 break;
1513 default:
1514 BPLOG(INFO) << "Unknown exception reason " << reason;
1515 break;
1516 }
1517 break;
1518 }
1519
1520 case MD_OS_SOLARIS: {
1521 switch (exception_code) {
1522 case MD_EXCEPTION_CODE_SOL_SIGHUP:
1523 reason = "SIGHUP";
1524 break;
1525 case MD_EXCEPTION_CODE_SOL_SIGINT:
1526 reason = "SIGINT";
1527 break;
1528 case MD_EXCEPTION_CODE_SOL_SIGQUIT:
1529 reason = "SIGQUIT";
1530 break;
1531 case MD_EXCEPTION_CODE_SOL_SIGILL:
1532 reason = "SIGILL";
1533 break;
1534 case MD_EXCEPTION_CODE_SOL_SIGTRAP:
1535 reason = "SIGTRAP";
1536 break;
1537 case MD_EXCEPTION_CODE_SOL_SIGIOT:
1538 reason = "SIGIOT | SIGABRT";
1539 break;
1540 case MD_EXCEPTION_CODE_SOL_SIGEMT:
1541 reason = "SIGEMT";
1542 break;
1543 case MD_EXCEPTION_CODE_SOL_SIGFPE:
1544 reason = "SIGFPE";
1545 break;
1546 case MD_EXCEPTION_CODE_SOL_SIGKILL:
1547 reason = "SIGKILL";
1548 break;
1549 case MD_EXCEPTION_CODE_SOL_SIGBUS:
1550 reason = "SIGBUS";
1551 break;
1552 case MD_EXCEPTION_CODE_SOL_SIGSEGV:
1553 reason = "SIGSEGV";
1554 break;
1555 case MD_EXCEPTION_CODE_SOL_SIGSYS:
1556 reason = "SIGSYS";
1557 break;
1558 case MD_EXCEPTION_CODE_SOL_SIGPIPE:
1559 reason = "SIGPIPE";
1560 break;
1561 case MD_EXCEPTION_CODE_SOL_SIGALRM:
1562 reason = "SIGALRM";
1563 break;
1564 case MD_EXCEPTION_CODE_SOL_SIGTERM:
1565 reason = "SIGTERM";
1566 break;
1567 case MD_EXCEPTION_CODE_SOL_SIGUSR1:
1568 reason = "SIGUSR1";
1569 break;
1570 case MD_EXCEPTION_CODE_SOL_SIGUSR2:
1571 reason = "SIGUSR2";
1572 break;
1573 case MD_EXCEPTION_CODE_SOL_SIGCLD:
1574 reason = "SIGCLD | SIGCHLD";
1575 break;
1576 case MD_EXCEPTION_CODE_SOL_SIGPWR:
1577 reason = "SIGPWR";
1578 break;
1579 case MD_EXCEPTION_CODE_SOL_SIGWINCH:
1580 reason = "SIGWINCH";
1581 break;
1582 case MD_EXCEPTION_CODE_SOL_SIGURG:
1583 reason = "SIGURG";
1584 break;
1585 case MD_EXCEPTION_CODE_SOL_SIGPOLL:
1586 reason = "SIGPOLL | SIGIO";
1587 break;
1588 case MD_EXCEPTION_CODE_SOL_SIGSTOP:
1589 reason = "SIGSTOP";
1590 break;
1591 case MD_EXCEPTION_CODE_SOL_SIGTSTP:
1592 reason = "SIGTSTP";
1593 break;
1594 case MD_EXCEPTION_CODE_SOL_SIGCONT:
1595 reason = "SIGCONT";
1596 break;
1597 case MD_EXCEPTION_CODE_SOL_SIGTTIN:
1598 reason = "SIGTTIN";
1599 break;
1600 case MD_EXCEPTION_CODE_SOL_SIGTTOU:
1601 reason = "SIGTTOU";
1602 break;
1603 case MD_EXCEPTION_CODE_SOL_SIGVTALRM:
1604 reason = "SIGVTALRM";
1605 break;
1606 case MD_EXCEPTION_CODE_SOL_SIGPROF:
1607 reason = "SIGPROF";
1608 break;
1609 case MD_EXCEPTION_CODE_SOL_SIGXCPU:
1610 reason = "SIGXCPU";
1611 break;
1612 case MD_EXCEPTION_CODE_SOL_SIGXFSZ:
1613 reason = "SIGXFSZ";
1614 break;
1615 case MD_EXCEPTION_CODE_SOL_SIGWAITING:
1616 reason = "SIGWAITING";
1617 break;
1618 case MD_EXCEPTION_CODE_SOL_SIGLWP:
1619 reason = "SIGLWP";
1620 break;
1621 case MD_EXCEPTION_CODE_SOL_SIGFREEZE:
1622 reason = "SIGFREEZE";
1623 break;
1624 case MD_EXCEPTION_CODE_SOL_SIGTHAW:
1625 reason = "SIGTHAW";
1626 break;
1627 case MD_EXCEPTION_CODE_SOL_SIGCANCEL:
1628 reason = "SIGCANCEL";
1629 break;
1630 case MD_EXCEPTION_CODE_SOL_SIGLOST:
1631 reason = "SIGLOST";
1632 break;
1633 case MD_EXCEPTION_CODE_SOL_SIGXRES:
1634 reason = "SIGXRES";
1635 break;
1636 case MD_EXCEPTION_CODE_SOL_SIGJVM1:
1637 reason = "SIGJVM1";
1638 break;
1639 case MD_EXCEPTION_CODE_SOL_SIGJVM2:
1640 reason = "SIGJVM2";
1641 break;
1642 default:
1643 BPLOG(INFO) << "Unknown exception reason " << reason;
1644 break;
1645 }
1646 break;
1647 }
1648
1649 case MD_OS_PS3: {
1650 switch (exception_code) {
1651 case MD_EXCEPTION_CODE_PS3_UNKNOWN:
1652 reason = "UNKNOWN";
1653 break;
1654 case MD_EXCEPTION_CODE_PS3_TRAP_EXCEP:
1655 reason = "TRAP_EXCEP";
1656 break;
1657 case MD_EXCEPTION_CODE_PS3_PRIV_INSTR:
1658 reason = "PRIV_INSTR";
1659 break;
1660 case MD_EXCEPTION_CODE_PS3_ILLEGAL_INSTR:
1661 reason = "ILLEGAL_INSTR";
1662 break;
1663 case MD_EXCEPTION_CODE_PS3_INSTR_STORAGE:
1664 reason = "INSTR_STORAGE";
1665 break;
1666 case MD_EXCEPTION_CODE_PS3_INSTR_SEGMENT:
1667 reason = "INSTR_SEGMENT";
1668 break;
1669 case MD_EXCEPTION_CODE_PS3_DATA_STORAGE:
1670 reason = "DATA_STORAGE";
1671 break;
1672 case MD_EXCEPTION_CODE_PS3_DATA_SEGMENT:
1673 reason = "DATA_SEGMENT";
1674 break;
1675 case MD_EXCEPTION_CODE_PS3_FLOAT_POINT:
1676 reason = "FLOAT_POINT";
1677 break;
1678 case MD_EXCEPTION_CODE_PS3_DABR_MATCH:
1679 reason = "DABR_MATCH";
1680 break;
1681 case MD_EXCEPTION_CODE_PS3_ALIGN_EXCEP:
1682 reason = "ALIGN_EXCEP";
1683 break;
1684 case MD_EXCEPTION_CODE_PS3_MEMORY_ACCESS:
1685 reason = "MEMORY_ACCESS";
1686 break;
1687 case MD_EXCEPTION_CODE_PS3_COPRO_ALIGN:
1688 reason = "COPRO_ALIGN";
1689 break;
1690 case MD_EXCEPTION_CODE_PS3_COPRO_INVALID_COM:
1691 reason = "COPRO_INVALID_COM";
1692 break;
1693 case MD_EXCEPTION_CODE_PS3_COPRO_ERR:
1694 reason = "COPRO_ERR";
1695 break;
1696 case MD_EXCEPTION_CODE_PS3_COPRO_FIR:
1697 reason = "COPRO_FIR";
1698 break;
1699 case MD_EXCEPTION_CODE_PS3_COPRO_DATA_SEGMENT:
1700 reason = "COPRO_DATA_SEGMENT";
1701 break;
1702 case MD_EXCEPTION_CODE_PS3_COPRO_DATA_STORAGE:
1703 reason = "COPRO_DATA_STORAGE";
1704 break;
1705 case MD_EXCEPTION_CODE_PS3_COPRO_STOP_INSTR:
1706 reason = "COPRO_STOP_INSTR";
1707 break;
1708 case MD_EXCEPTION_CODE_PS3_COPRO_HALT_INSTR:
1709 reason = "COPRO_HALT_INSTR";
1710 break;
1711 case MD_EXCEPTION_CODE_PS3_COPRO_HALTINST_UNKNOWN:
1712 reason = "COPRO_HALTINSTR_UNKNOWN";
1713 break;
1714 case MD_EXCEPTION_CODE_PS3_COPRO_MEMORY_ACCESS:
1715 reason = "COPRO_MEMORY_ACCESS";
1716 break;
1717 case MD_EXCEPTION_CODE_PS3_GRAPHIC:
1718 reason = "GRAPHIC";
1719 break;
1720 default:
1721 BPLOG(INFO) << "Unknown exception reason "<< reason;
1722 break;
1723 }
1724 break;
1725 }
1726
1727 default: {
1728 BPLOG(INFO) << "Unknown exception reason " << reason;
1729 break;
1730 }
1731 }
1732
1733 if (address) {
1734 *address = GetAddressForArchitecture(
1735 static_cast<MDCPUArchitecture>(raw_system_info->processor_architecture),
1736 *address);
1737 }
1738
1739 return reason;
1740 }
1741
1742 // static
GetAssertion(Minidump * dump)1743 string MinidumpProcessor::GetAssertion(Minidump *dump) {
1744 MinidumpAssertion *assertion = dump->GetAssertion();
1745 if (!assertion)
1746 return "";
1747
1748 const MDRawAssertionInfo *raw_assertion = assertion->assertion();
1749 if (!raw_assertion)
1750 return "";
1751
1752 string assertion_string;
1753 switch (raw_assertion->type) {
1754 case MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER:
1755 assertion_string = "Invalid parameter passed to library function";
1756 break;
1757 case MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL:
1758 assertion_string = "Pure virtual function called";
1759 break;
1760 default: {
1761 char assertion_type[32];
1762 snprintf(assertion_type, sizeof(assertion_type),
1763 "0x%08x", raw_assertion->type);
1764 assertion_string = "Unknown assertion type ";
1765 assertion_string += assertion_type;
1766 break;
1767 }
1768 }
1769
1770 string expression = assertion->expression();
1771 if (!expression.empty()) {
1772 assertion_string.append(" " + expression);
1773 }
1774
1775 string function = assertion->function();
1776 if (!function.empty()) {
1777 assertion_string.append(" in function " + function);
1778 }
1779
1780 string file = assertion->file();
1781 if (!file.empty()) {
1782 assertion_string.append(", in file " + file);
1783 }
1784
1785 if (raw_assertion->line != 0) {
1786 char assertion_line[32];
1787 snprintf(assertion_line, sizeof(assertion_line), "%u", raw_assertion->line);
1788 assertion_string.append(" at line ");
1789 assertion_string.append(assertion_line);
1790 }
1791
1792 return assertion_string;
1793 }
1794
1795 } // namespace google_breakpad
1796