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