xref: /aosp_15_r20/external/google-breakpad/src/processor/minidump_processor.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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 
MinidumpProcessor(SymbolSupplier * supplier,SourceLineResolverInterface * resolver)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 
MinidumpProcessor(SymbolSupplier * supplier,SourceLineResolverInterface * resolver,bool enable_exploitability)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 
MinidumpProcessor(StackFrameSymbolizer * frame_symbolizer,bool enable_exploitability)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 
~MinidumpProcessor()90 MinidumpProcessor::~MinidumpProcessor() {
91   if (own_frame_symbolizer_) delete frame_symbolizer_;
92 }
93 
Process(Minidump * dump,ProcessState * process_state)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 
Process(const string & minidump_file,ProcessState * process_state)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.
GetSystemInfo(Minidump * dump,MinidumpSystemInfo ** system_info)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 
GetAddressForArchitecture(const MDCPUArchitecture architecture,size_t raw_address)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.
GetARMCpuInfo(const MDRawSystemInfo * raw_info,string * cpu_info)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
GetCPUInfo(Minidump * dump,SystemInfo * info)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
GetOSInfo(Minidump * dump,SystemInfo * info)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
GetProcessCreateTime(Minidump * dump,uint32_t * process_create_time)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 
IsCanonicalAddress(uint64_t address)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 
CalculateFaultAddressFromInstruction(Minidump * dump,uint64_t * address)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
GetCrashReason(Minidump * dump,uint64_t * address,bool enable_objdump)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
GetAssertion(Minidump * dump)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
2179