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