• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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