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
48namespace google_breakpad {
49
50MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier,
51                                     SourceLineResolverInterface *resolver)
52    : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)),
53      own_frame_symbolizer_(true),
54      enable_exploitability_(false) {
55}
56
57MinidumpProcessor::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
65MinidumpProcessor::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
73MinidumpProcessor::~MinidumpProcessor() {
74  if (own_frame_symbolizer_) delete frame_symbolizer_;
75}
76
77ProcessResult 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
305ProcessResult 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.
321static 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.
336static 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
456bool 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
539bool 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
627bool 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
653string 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
1484string 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