Home | History | Annotate | Download | only in processor
      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 
     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 
     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 
     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 
     73 MinidumpProcessor::~MinidumpProcessor() {
     74   if (own_frame_symbolizer_) delete frame_symbolizer_;
     75 }
     76 
     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 
    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.
    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.
    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
    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
    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
    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
    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
   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