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