Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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.
30 #include "google_breakpad/processor/minidump_processor.h"
32 #include <assert.h>
33 #include <stdio.h>
35 #include "common/scoped_ptr.h"
36 #include "google_breakpad/processor/call_stack.h"
37 #include "google_breakpad/processor/minidump.h"
38 #include "google_breakpad/processor/process_state.h"
39 #include "google_breakpad/processor/exploitability.h"
40 #include "google_breakpad/processor/stack_frame_symbolizer.h"
41 #include "processor/logging.h"
42 #include "processor/stackwalker_x86.h"
44 namespace google_breakpad {
46 MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier,
47 SourceLineResolverInterface *resolver)
48 : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)),
49 own_frame_symbolizer_(true),
50 enable_exploitability_(false) {
51 }
53 MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier,
54 SourceLineResolverInterface *resolver,
55 bool enable_exploitability)
56 : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)),
57 own_frame_symbolizer_(true),
58 enable_exploitability_(enable_exploitability) {
59 }
61 MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer *frame_symbolizer,
62 bool enable_exploitability)
63 : frame_symbolizer_(frame_symbolizer),
64 own_frame_symbolizer_(false),
65 enable_exploitability_(enable_exploitability) {
66 assert(frame_symbolizer_);
67 }
69 MinidumpProcessor::~MinidumpProcessor() {
70 if (own_frame_symbolizer_) delete frame_symbolizer_;
71 }
73 ProcessResult MinidumpProcessor::Process(
74 Minidump *dump, ProcessState *process_state) {
75 assert(dump);
76 assert(process_state);
78 process_state->Clear();
80 const MDRawHeader *header = dump->header();
81 if (!header) {
82 BPLOG(ERROR) << "Minidump " << dump->path() << " has no header";
83 return PROCESS_ERROR_NO_MINIDUMP_HEADER;
84 }
85 process_state->time_date_stamp_ = header->time_date_stamp;
87 bool has_cpu_info = GetCPUInfo(dump, &process_state->system_info_);
88 bool has_os_info = GetOSInfo(dump, &process_state->system_info_);
90 uint32_t dump_thread_id = 0;
91 bool has_dump_thread = false;
92 uint32_t requesting_thread_id = 0;
93 bool has_requesting_thread = false;
95 MinidumpBreakpadInfo *breakpad_info = dump->GetBreakpadInfo();
96 if (breakpad_info) {
97 has_dump_thread = breakpad_info->GetDumpThreadID(&dump_thread_id);
98 has_requesting_thread =
99 breakpad_info->GetRequestingThreadID(&requesting_thread_id);
100 }
102 MinidumpException *exception = dump->GetException();
103 if (exception) {
104 process_state->crashed_ = true;
105 has_requesting_thread = exception->GetThreadID(&requesting_thread_id);
107 process_state->crash_reason_ = GetCrashReason(
108 dump, &process_state->crash_address_);
109 }
111 // This will just return an empty string if it doesn't exist.
112 process_state->assertion_ = GetAssertion(dump);
114 MinidumpModuleList *module_list = dump->GetModuleList();
116 // Put a copy of the module list into ProcessState object. This is not
117 // necessarily a MinidumpModuleList, but it adheres to the CodeModules
118 // interface, which is all that ProcessState needs to expose.
119 if (module_list)
120 process_state->modules_ = module_list->Copy();
122 MinidumpThreadList *threads = dump->GetThreadList();
123 if (!threads) {
124 BPLOG(ERROR) << "Minidump " << dump->path() << " has no thread list";
125 return PROCESS_ERROR_NO_THREAD_LIST;
126 }
128 BPLOG(INFO) << "Minidump " << dump->path() << " has " <<
129 (has_cpu_info ? "" : "no ") << "CPU info, " <<
130 (has_os_info ? "" : "no ") << "OS info, " <<
131 (breakpad_info != NULL ? "" : "no ") << "Breakpad info, " <<
132 (exception != NULL ? "" : "no ") << "exception, " <<
133 (module_list != NULL ? "" : "no ") << "module list, " <<
134 (threads != NULL ? "" : "no ") << "thread list, " <<
135 (has_dump_thread ? "" : "no ") << "dump thread, and " <<
136 (has_requesting_thread ? "" : "no ") << "requesting thread";
138 bool interrupted = false;
139 bool found_requesting_thread = false;
140 unsigned int thread_count = threads->thread_count();
142 // Reset frame_symbolizer_ at the beginning of stackwalk for each minidump.
143 frame_symbolizer_->Reset();
145 for (unsigned int thread_index = 0;
146 thread_index < thread_count;
147 ++thread_index) {
148 char thread_string_buffer[64];
149 snprintf(thread_string_buffer, sizeof(thread_string_buffer), "%d/%d",
150 thread_index, thread_count);
151 string thread_string = dump->path() + ":" + thread_string_buffer;
153 MinidumpThread *thread = threads->GetThreadAtIndex(thread_index);
154 if (!thread) {
155 BPLOG(ERROR) << "Could not get thread for " << thread_string;
156 return PROCESS_ERROR_GETTING_THREAD;
157 }
159 uint32_t thread_id;
160 if (!thread->GetThreadID(&thread_id)) {
161 BPLOG(ERROR) << "Could not get thread ID for " << thread_string;
162 return PROCESS_ERROR_GETTING_THREAD_ID;
163 }
165 thread_string += " id " + HexString(thread_id);
166 BPLOG(INFO) << "Looking at thread " << thread_string;
168 // If this thread is the thread that produced the minidump, don't process
169 // it. Because of the problems associated with a thread producing a
170 // dump of itself (when both its context and its stack are in flux),
171 // processing that stack wouldn't provide much useful data.
172 if (has_dump_thread && thread_id == dump_thread_id) {
173 continue;
174 }
176 MinidumpContext *context = thread->GetContext();
178 if (has_requesting_thread && thread_id == requesting_thread_id) {
179 if (found_requesting_thread) {
180 // There can't be more than one requesting thread.
181 BPLOG(ERROR) << "Duplicate requesting thread: " << thread_string;
182 return PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS;
183 }
185 // Use processed_state->threads_.size() instead of thread_index.
186 // thread_index points to the thread index in the minidump, which
187 // might be greater than the thread index in the threads vector if
188 // any of the minidump's threads are skipped and not placed into the
189 // processed threads vector. The thread vector's current size will
190 // be the index of the current thread when it's pushed into the
191 // vector.
192 process_state->requesting_thread_ = process_state->threads_.size();
194 found_requesting_thread = true;
196 if (process_state->crashed_) {
197 // Use the exception record's context for the crashed thread, instead
198 // of the thread's own context. For the crashed thread, the thread's
199 // own context is the state inside the exception handler. Using it
200 // would not result in the expected stack trace from the time of the
201 // crash. If the exception context is invalid, however, we fall back
202 // on the thread context.
203 MinidumpContext *ctx = exception->GetContext();
204 context = ctx ? ctx : thread->GetContext();
205 }
206 }
208 MinidumpMemoryRegion *thread_memory = thread->GetMemory();
209 if (!thread_memory) {
210 BPLOG(ERROR) << "No memory region for " << thread_string;
211 }
213 // Use process_state->modules_ instead of module_list, because the
214 // |modules| argument will be used to populate the |module| fields in
215 // the returned StackFrame objects, which will be placed into the
216 // returned ProcessState object. module_list's lifetime is only as
217 // long as the Minidump object: it will be deleted when this function
218 // returns. process_state->modules_ is owned by the ProcessState object
219 // (just like the StackFrame objects), and is much more suitable for this
220 // task.
221 scoped_ptr<Stackwalker> stackwalker(
222 Stackwalker::StackwalkerForCPU(process_state->system_info(),
223 context,
224 thread_memory,
225 process_state->modules_,
226 frame_symbolizer_));
228 scoped_ptr<CallStack> stack(new CallStack());
229 if (stackwalker.get()) {
230 if (!stackwalker->Walk(stack.get(),
231 &process_state->modules_without_symbols_)) {
232 BPLOG(INFO) << "Stackwalker interrupt (missing symbols?) at "
233 << thread_string;
234 interrupted = true;
235 }
236 } else {
237 // Threads with missing CPU contexts will hit this, but
238 // don't abort processing the rest of the dump just for
239 // one bad thread.
240 BPLOG(ERROR) << "No stackwalker for " << thread_string;
241 }
242 process_state->threads_.push_back(stack.release());
243 process_state->thread_memory_regions_.push_back(thread_memory);
244 }
246 if (interrupted) {
247 BPLOG(INFO) << "Processing interrupted for " << dump->path();
248 return PROCESS_SYMBOL_SUPPLIER_INTERRUPTED;
249 }
251 // If a requesting thread was indicated, it must be present.
252 if (has_requesting_thread && !found_requesting_thread) {
253 // Don't mark as an error, but invalidate the requesting thread
254 BPLOG(ERROR) << "Minidump indicated requesting thread " <<
255 HexString(requesting_thread_id) << ", not found in " <<
256 dump->path();
257 process_state->requesting_thread_ = -1;
258 }
260 // Exploitability defaults to EXPLOITABILITY_NOT_ANALYZED
261 process_state->exploitability_ = EXPLOITABILITY_NOT_ANALYZED;
263 // If an exploitability run was requested we perform the platform specific
264 // rating.
265 if (enable_exploitability_) {
266 scoped_ptr<Exploitability> exploitability(
267 Exploitability::ExploitabilityForPlatform(dump, process_state));
268 // The engine will be null if the platform is not supported
269 if (exploitability != NULL) {
270 process_state->exploitability_ = exploitability->CheckExploitability();
271 } else {
272 process_state->exploitability_ = EXPLOITABILITY_ERR_NOENGINE;
273 }
274 }
276 BPLOG(INFO) << "Processed " << dump->path();
277 return PROCESS_OK;
278 }
280 ProcessResult MinidumpProcessor::Process(
281 const string &minidump_file, ProcessState *process_state) {
282 BPLOG(INFO) << "Processing minidump in file " << minidump_file;
284 Minidump dump(minidump_file);
285 if (!dump.Read()) {
286 BPLOG(ERROR) << "Minidump " << dump.path() << " could not be read";
287 return PROCESS_ERROR_MINIDUMP_NOT_FOUND;
288 }
290 return Process(&dump, process_state);
291 }
293 // Returns the MDRawSystemInfo from a minidump, or NULL if system info is
294 // not available from the minidump. If system_info is non-NULL, it is used
295 // to pass back the MinidumpSystemInfo object.
296 static const MDRawSystemInfo* GetSystemInfo(Minidump *dump,
297 MinidumpSystemInfo **system_info) {
298 MinidumpSystemInfo *minidump_system_info = dump->GetSystemInfo();
299 if (!minidump_system_info)
300 return NULL;
302 if (system_info)
303 *system_info = minidump_system_info;
305 return minidump_system_info->system_info();
306 }
308 // static
309 bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) {
310 assert(dump);
311 assert(info);
313 info->cpu.clear();
314 info->cpu_info.clear();
316 MinidumpSystemInfo *system_info;
317 const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info);
318 if (!raw_system_info)
319 return false;
321 switch (raw_system_info->processor_architecture) {
322 case MD_CPU_ARCHITECTURE_X86:
323 case MD_CPU_ARCHITECTURE_AMD64: {
324 if (raw_system_info->processor_architecture ==
325 MD_CPU_ARCHITECTURE_X86)
326 info->cpu = "x86";
327 else
328 info->cpu = "amd64";
330 const string *cpu_vendor = system_info->GetCPUVendor();
331 if (cpu_vendor) {
332 info->cpu_info = *cpu_vendor;
333 info->cpu_info.append(" ");
334 }
336 char x86_info[36];
337 snprintf(x86_info, sizeof(x86_info), "family %u model %u stepping %u",
338 raw_system_info->processor_level,
339 raw_system_info->processor_revision >> 8,
340 raw_system_info->processor_revision & 0xff);
341 info->cpu_info.append(x86_info);
342 break;
343 }
345 case MD_CPU_ARCHITECTURE_PPC: {
346 info->cpu = "ppc";
347 break;
348 }
350 case MD_CPU_ARCHITECTURE_SPARC: {
351 info->cpu = "sparc";
352 break;
353 }
355 case MD_CPU_ARCHITECTURE_ARM: {
356 info->cpu = "arm";
357 break;
358 }
360 default: {
361 // Assign the numeric architecture ID into the CPU string.
362 char cpu_string[7];
363 snprintf(cpu_string, sizeof(cpu_string), "0x%04x",
364 raw_system_info->processor_architecture);
365 info->cpu = cpu_string;
366 break;
367 }
368 }
370 info->cpu_count = raw_system_info->number_of_processors;
372 return true;
373 }
375 // static
376 bool MinidumpProcessor::GetOSInfo(Minidump *dump, SystemInfo *info) {
377 assert(dump);
378 assert(info);
380 info->os.clear();
381 info->os_short.clear();
382 info->os_version.clear();
384 MinidumpSystemInfo *system_info;
385 const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info);
386 if (!raw_system_info)
387 return false;
389 info->os_short = system_info->GetOS();
391 switch (raw_system_info->platform_id) {
392 case MD_OS_WIN32_NT: {
393 info->os = "Windows NT";
394 break;
395 }
397 case MD_OS_WIN32_WINDOWS: {
398 info->os = "Windows";
399 break;
400 }
402 case MD_OS_MAC_OS_X: {
403 info->os = "Mac OS X";
404 break;
405 }
407 case MD_OS_IOS: {
408 info->os = "iOS";
409 break;
410 }
412 case MD_OS_LINUX: {
413 info->os = "Linux";
414 break;
415 }
417 case MD_OS_SOLARIS: {
418 info->os = "Solaris";
419 break;
420 }
422 case MD_OS_ANDROID: {
423 info->os = "Android";
424 break;
425 }
427 default: {
428 // Assign the numeric platform ID into the OS string.
429 char os_string[11];
430 snprintf(os_string, sizeof(os_string), "0x%08x",
431 raw_system_info->platform_id);
432 info->os = os_string;
433 break;
434 }
435 }
437 char os_version_string[33];
438 snprintf(os_version_string, sizeof(os_version_string), "%u.%u.%u",
439 raw_system_info->major_version,
440 raw_system_info->minor_version,
441 raw_system_info->build_number);
442 info->os_version = os_version_string;
444 const string *csd_version = system_info->GetCSDVersion();
445 if (csd_version) {
446 info->os_version.append(" ");
447 info->os_version.append(*csd_version);
448 }
450 return true;
451 }
453 // static
454 string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) {
455 MinidumpException *exception = dump->GetException();
456 if (!exception)
457 return "";
459 const MDRawExceptionStream *raw_exception = exception->exception();
460 if (!raw_exception)
461 return "";
463 if (address)
464 *address = raw_exception->exception_record.exception_address;
466 // The reason value is OS-specific and possibly CPU-specific. Set up
467 // sensible numeric defaults for the reason string in case we can't
468 // map the codes to a string (because there's no system info, or because
469 // it's an unrecognized platform, or because it's an unrecognized code.)
470 char reason_string[24];
471 uint32_t exception_code = raw_exception->exception_record.exception_code;
472 uint32_t exception_flags = raw_exception->exception_record.exception_flags;
473 snprintf(reason_string, sizeof(reason_string), "0x%08x / 0x%08x",
474 exception_code, exception_flags);
475 string reason = reason_string;
477 const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, NULL);
478 if (!raw_system_info)
479 return reason;
481 switch (raw_system_info->platform_id) {
482 case MD_OS_MAC_OS_X:
483 case MD_OS_IOS: {
484 char flags_string[11];
485 snprintf(flags_string, sizeof(flags_string), "0x%08x", exception_flags);
486 switch (exception_code) {
487 case MD_EXCEPTION_MAC_BAD_ACCESS:
488 reason = "EXC_BAD_ACCESS / ";
489 switch (exception_flags) {
490 case MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS:
491 reason.append("KERN_INVALID_ADDRESS");
492 break;
493 case MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE:
494 reason.append("KERN_PROTECTION_FAILURE");
495 break;
496 case MD_EXCEPTION_CODE_MAC_NO_ACCESS:
497 reason.append("KERN_NO_ACCESS");
498 break;
499 case MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE:
500 reason.append("KERN_MEMORY_FAILURE");
501 break;
502 case MD_EXCEPTION_CODE_MAC_MEMORY_ERROR:
503 reason.append("KERN_MEMORY_ERROR");
504 break;
505 default:
506 // arm and ppc overlap
507 if (raw_system_info->processor_architecture ==
508 MD_CPU_ARCHITECTURE_ARM) {
509 switch (exception_flags) {
510 case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN:
511 reason.append("EXC_ARM_DA_ALIGN");
512 break;
513 case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG:
514 reason.append("EXC_ARM_DA_DEBUG");
515 break;
516 default:
517 reason.append(flags_string);
518 BPLOG(INFO) << "Unknown exception reason " << reason;
519 break;
520 }
521 } else if (raw_system_info->processor_architecture ==
522 MD_CPU_ARCHITECTURE_PPC) {
523 switch (exception_flags) {
524 case MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ:
525 reason.append("EXC_PPC_VM_PROT_READ");
526 break;
527 case MD_EXCEPTION_CODE_MAC_PPC_BADSPACE:
528 reason.append("EXC_PPC_BADSPACE");
529 break;
530 case MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED:
531 reason.append("EXC_PPC_UNALIGNED");
532 break;
533 default:
534 reason.append(flags_string);
535 BPLOG(INFO) << "Unknown exception reason " << reason;
536 break;
537 }
538 } else {
539 reason.append(flags_string);
540 BPLOG(INFO) << "Unknown exception reason " << reason;
541 }
542 break;
543 }
544 break;
545 case MD_EXCEPTION_MAC_BAD_INSTRUCTION:
546 reason = "EXC_BAD_INSTRUCTION / ";
547 switch (raw_system_info->processor_architecture) {
548 case MD_CPU_ARCHITECTURE_ARM: {
549 switch (exception_flags) {
550 case MD_EXCEPTION_CODE_MAC_ARM_UNDEFINED:
551 reason.append("EXC_ARM_UNDEFINED");
552 break;
553 default:
554 reason.append(flags_string);
555 BPLOG(INFO) << "Unknown exception reason " << reason;
556 break;
557 }
558 break;
559 }
560 case MD_CPU_ARCHITECTURE_PPC: {
561 switch (exception_flags) {
562 case MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL:
563 reason.append("EXC_PPC_INVALID_SYSCALL");
564 break;
565 case MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION:
566 reason.append("EXC_PPC_UNIPL_INST");
567 break;
568 case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION:
569 reason.append("EXC_PPC_PRIVINST");
570 break;
571 case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER:
572 reason.append("EXC_PPC_PRIVREG");
573 break;
574 case MD_EXCEPTION_CODE_MAC_PPC_TRACE:
575 reason.append("EXC_PPC_TRACE");
576 break;
577 case MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR:
578 reason.append("EXC_PPC_PERFMON");
579 break;
580 default:
581 reason.append(flags_string);
582 BPLOG(INFO) << "Unknown exception reason " << reason;
583 break;
584 }
585 break;
586 }
587 case MD_CPU_ARCHITECTURE_X86: {
588 switch (exception_flags) {
589 case MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION:
590 reason.append("EXC_I386_INVOP");
591 break;
592 case MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT:
593 reason.append("EXC_INVTSSFLT");
594 break;
595 case MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT:
596 reason.append("EXC_SEGNPFLT");
597 break;
598 case MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT:
599 reason.append("EXC_STKFLT");
600 break;
601 case MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT:
602 reason.append("EXC_GPFLT");
603 break;
604 case MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT:
605 reason.append("EXC_ALIGNFLT");
606 break;
607 default:
608 reason.append(flags_string);
609 BPLOG(INFO) << "Unknown exception reason " << reason;
610 break;
611 }
612 break;
613 }
614 default:
615 reason.append(flags_string);
616 BPLOG(INFO) << "Unknown exception reason " << reason;
617 break;
618 }
619 break;
620 case MD_EXCEPTION_MAC_ARITHMETIC:
621 reason = "EXC_ARITHMETIC / ";
622 switch (raw_system_info->processor_architecture) {
623 case MD_CPU_ARCHITECTURE_PPC: {
624 switch (exception_flags) {
625 case MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW:
626 reason.append("EXC_PPC_OVERFLOW");
627 break;
628 case MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE:
629 reason.append("EXC_PPC_ZERO_DIVIDE");
630 break;
631 case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT:
632 reason.append("EXC_FLT_INEXACT");
633 break;
634 case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE:
635 reason.append("EXC_PPC_FLT_ZERO_DIVIDE");
636 break;
637 case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW:
638 reason.append("EXC_PPC_FLT_UNDERFLOW");
639 break;
640 case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW:
641 reason.append("EXC_PPC_FLT_OVERFLOW");
642 break;
643 case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER:
644 reason.append("EXC_PPC_FLT_NOT_A_NUMBER");
645 break;
646 case MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION:
647 reason.append("EXC_PPC_NOEMULATION");
648 break;
649 case MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST:
650 reason.append("EXC_PPC_ALTIVECASSIST");
651 default:
652 reason.append(flags_string);
653 BPLOG(INFO) << "Unknown exception reason " << reason;
654 break;
655 }
656 break;
657 }
658 case MD_CPU_ARCHITECTURE_X86: {
659 switch (exception_flags) {
660 case MD_EXCEPTION_CODE_MAC_X86_DIV:
661 reason.append("EXC_I386_DIV");
662 break;
663 case MD_EXCEPTION_CODE_MAC_X86_INTO:
664 reason.append("EXC_I386_INTO");
665 break;
666 case MD_EXCEPTION_CODE_MAC_X86_NOEXT:
667 reason.append("EXC_I386_NOEXT");
668 break;
669 case MD_EXCEPTION_CODE_MAC_X86_EXTOVR:
670 reason.append("EXC_I386_EXTOVR");
671 break;
672 case MD_EXCEPTION_CODE_MAC_X86_EXTERR:
673 reason.append("EXC_I386_EXTERR");
674 break;
675 case MD_EXCEPTION_CODE_MAC_X86_EMERR:
676 reason.append("EXC_I386_EMERR");
677 break;
678 case MD_EXCEPTION_CODE_MAC_X86_BOUND:
679 reason.append("EXC_I386_BOUND");
680 break;
681 case MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR:
682 reason.append("EXC_I386_SSEEXTERR");
683 break;
684 default:
685 reason.append(flags_string);
686 BPLOG(INFO) << "Unknown exception reason " << reason;
687 break;
688 }
689 break;
690 }
691 default:
692 reason.append(flags_string);
693 BPLOG(INFO) << "Unknown exception reason " << reason;
694 break;
695 }
696 break;
697 case MD_EXCEPTION_MAC_EMULATION:
698 reason = "EXC_EMULATION / ";
699 reason.append(flags_string);
700 break;
701 case MD_EXCEPTION_MAC_SOFTWARE:
702 reason = "EXC_SOFTWARE / ";
703 switch (exception_flags) {
704 case MD_EXCEPTION_CODE_MAC_ABORT:
705 reason.append("SIGABRT");
706 break;
707 case MD_EXCEPTION_CODE_MAC_NS_EXCEPTION:
708 reason.append("UNCAUGHT_NS_EXCEPTION");
709 break;
710 // These are ppc only but shouldn't be a problem as they're
711 // unused on x86
712 case MD_EXCEPTION_CODE_MAC_PPC_TRAP:
713 reason.append("EXC_PPC_TRAP");
714 break;
715 case MD_EXCEPTION_CODE_MAC_PPC_MIGRATE:
716 reason.append("EXC_PPC_MIGRATE");
717 break;
718 default:
719 reason.append(flags_string);
720 BPLOG(INFO) << "Unknown exception reason " << reason;
721 break;
722 }
723 break;
724 case MD_EXCEPTION_MAC_BREAKPOINT:
725 reason = "EXC_BREAKPOINT / ";
726 switch (raw_system_info->processor_architecture) {
727 case MD_CPU_ARCHITECTURE_ARM: {
728 switch (exception_flags) {
729 case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN:
730 reason.append("EXC_ARM_DA_ALIGN");
731 break;
732 case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG:
733 reason.append("EXC_ARM_DA_DEBUG");
734 break;
735 case MD_EXCEPTION_CODE_MAC_ARM_BREAKPOINT:
736 reason.append("EXC_ARM_BREAKPOINT");
737 break;
738 default:
739 reason.append(flags_string);
740 BPLOG(INFO) << "Unknown exception reason " << reason;
741 break;
742 }
743 break;
744 }
745 case MD_CPU_ARCHITECTURE_PPC: {
746 switch (exception_flags) {
747 case MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT:
748 reason.append("EXC_PPC_BREAKPOINT");
749 break;
750 default:
751 reason.append(flags_string);
752 BPLOG(INFO) << "Unknown exception reason " << reason;
753 break;
754 }
755 break;
756 }
757 case MD_CPU_ARCHITECTURE_X86: {
758 switch (exception_flags) {
759 case MD_EXCEPTION_CODE_MAC_X86_SGL:
760 reason.append("EXC_I386_SGL");
761 break;
762 case MD_EXCEPTION_CODE_MAC_X86_BPT:
763 reason.append("EXC_I386_BPT");
764 break;
765 default:
766 reason.append(flags_string);
767 BPLOG(INFO) << "Unknown exception reason " << reason;
768 break;
769 }
770 break;
771 }
772 default:
773 reason.append(flags_string);
774 BPLOG(INFO) << "Unknown exception reason " << reason;
775 break;
776 }
777 break;
778 case MD_EXCEPTION_MAC_SYSCALL:
779 reason = "EXC_SYSCALL / ";
780 reason.append(flags_string);
781 break;
782 case MD_EXCEPTION_MAC_MACH_SYSCALL:
783 reason = "EXC_MACH_SYSCALL / ";
784 reason.append(flags_string);
785 break;
786 case MD_EXCEPTION_MAC_RPC_ALERT:
787 reason = "EXC_RPC_ALERT / ";
788 reason.append(flags_string);
789 break;
790 }
791 break;
792 }
794 case MD_OS_WIN32_NT:
795 case MD_OS_WIN32_WINDOWS: {
796 switch (exception_code) {
797 case MD_EXCEPTION_CODE_WIN_CONTROL_C:
798 reason = "DBG_CONTROL_C";
799 break;
800 case MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION:
801 reason = "EXCEPTION_GUARD_PAGE";
802 break;
803 case MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT:
804 reason = "EXCEPTION_DATATYPE_MISALIGNMENT";
805 break;
806 case MD_EXCEPTION_CODE_WIN_BREAKPOINT:
807 reason = "EXCEPTION_BREAKPOINT";
808 break;
809 case MD_EXCEPTION_CODE_WIN_SINGLE_STEP:
810 reason = "EXCEPTION_SINGLE_STEP";
811 break;
812 case MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION:
813 // For EXCEPTION_ACCESS_VIOLATION, Windows puts the address that
814 // caused the fault in exception_information[1].
815 // exception_information[0] is 0 if the violation was caused by
816 // an attempt to read data and 1 if it was an attempt to write
817 // data.
818 // This information is useful in addition to the code address, which
819 // will be present in the crash thread's instruction field anyway.
820 if (raw_exception->exception_record.number_parameters >= 1) {
821 MDAccessViolationTypeWin av_type =
822 static_cast<MDAccessViolationTypeWin>
823 (raw_exception->exception_record.exception_information[0]);
824 switch (av_type) {
825 case MD_ACCESS_VIOLATION_WIN_READ:
826 reason = "EXCEPTION_ACCESS_VIOLATION_READ";
827 break;
828 case MD_ACCESS_VIOLATION_WIN_WRITE:
829 reason = "EXCEPTION_ACCESS_VIOLATION_WRITE";
830 break;
831 case MD_ACCESS_VIOLATION_WIN_EXEC:
832 reason = "EXCEPTION_ACCESS_VIOLATION_EXEC";
833 break;
834 default:
835 reason = "EXCEPTION_ACCESS_VIOLATION";
836 break;
837 }
838 } else {
839 reason = "EXCEPTION_ACCESS_VIOLATION";
840 }
841 if (address &&
842 raw_exception->exception_record.number_parameters >= 2) {
843 *address =
844 raw_exception->exception_record.exception_information[1];
845 }
846 break;
847 case MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR:
848 reason = "EXCEPTION_IN_PAGE_ERROR";
849 break;
850 case MD_EXCEPTION_CODE_WIN_INVALID_HANDLE:
851 reason = "EXCEPTION_INVALID_HANDLE";
852 break;
853 case MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION:
854 reason = "EXCEPTION_ILLEGAL_INSTRUCTION";
855 break;
856 case MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION:
857 reason = "EXCEPTION_NONCONTINUABLE_EXCEPTION";
858 break;
859 case MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION:
860 reason = "EXCEPTION_INVALID_DISPOSITION";
861 break;
862 case MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED:
863 reason = "EXCEPTION_BOUNDS_EXCEEDED";
864 break;
865 case MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND:
866 reason = "EXCEPTION_FLT_DENORMAL_OPERAND";
867 break;
868 case MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO:
869 reason = "EXCEPTION_FLT_DIVIDE_BY_ZERO";
870 break;
871 case MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT:
872 reason = "EXCEPTION_FLT_INEXACT_RESULT";
873 break;
874 case MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION:
875 reason = "EXCEPTION_FLT_INVALID_OPERATION";
876 break;
877 case MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW:
878 reason = "EXCEPTION_FLT_OVERFLOW";
879 break;
880 case MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK:
881 reason = "EXCEPTION_FLT_STACK_CHECK";
882 break;
883 case MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW:
884 reason = "EXCEPTION_FLT_UNDERFLOW";
885 break;
886 case MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO:
887 reason = "EXCEPTION_INT_DIVIDE_BY_ZERO";
888 break;
889 case MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW:
890 reason = "EXCEPTION_INT_OVERFLOW";
891 break;
892 case MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION:
893 reason = "EXCEPTION_PRIV_INSTRUCTION";
894 break;
895 case MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW:
896 reason = "EXCEPTION_STACK_OVERFLOW";
897 break;
898 case MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK:
899 reason = "EXCEPTION_POSSIBLE_DEADLOCK";
900 break;
901 case MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN:
902 reason = "EXCEPTION_STACK_BUFFER_OVERRUN";
903 break;
904 case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION:
905 reason = "EXCEPTION_HEAP_CORRUPTION";
906 break;
907 case MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION:
908 reason = "Unhandled C++ Exception";
909 break;
910 default:
911 BPLOG(INFO) << "Unknown exception reason " << reason;
912 break;
913 }
914 break;
915 }
917 case MD_OS_ANDROID:
918 case MD_OS_LINUX: {
919 switch (exception_code) {
920 case MD_EXCEPTION_CODE_LIN_SIGHUP:
921 reason = "SIGHUP";
922 break;
923 case MD_EXCEPTION_CODE_LIN_SIGINT:
924 reason = "SIGINT";
925 break;
926 case MD_EXCEPTION_CODE_LIN_SIGQUIT:
927 reason = "SIGQUIT";
928 break;
929 case MD_EXCEPTION_CODE_LIN_SIGILL:
930 reason = "SIGILL";
931 break;
932 case MD_EXCEPTION_CODE_LIN_SIGTRAP:
933 reason = "SIGTRAP";
934 break;
935 case MD_EXCEPTION_CODE_LIN_SIGABRT:
936 reason = "SIGABRT";
937 break;
938 case MD_EXCEPTION_CODE_LIN_SIGBUS:
939 reason = "SIGBUS";
940 break;
941 case MD_EXCEPTION_CODE_LIN_SIGFPE:
942 reason = "SIGFPE";
943 break;
944 case MD_EXCEPTION_CODE_LIN_SIGKILL:
945 reason = "SIGKILL";
946 break;
947 case MD_EXCEPTION_CODE_LIN_SIGUSR1:
948 reason = "SIGUSR1";
949 break;
950 case MD_EXCEPTION_CODE_LIN_SIGSEGV:
951 reason = "SIGSEGV";
952 break;
953 case MD_EXCEPTION_CODE_LIN_SIGUSR2:
954 reason = "SIGUSR2";
955 break;
956 case MD_EXCEPTION_CODE_LIN_SIGPIPE:
957 reason = "SIGPIPE";
958 break;
959 case MD_EXCEPTION_CODE_LIN_SIGALRM:
960 reason = "SIGALRM";
961 break;
962 case MD_EXCEPTION_CODE_LIN_SIGTERM:
963 reason = "SIGTERM";
964 break;
965 case MD_EXCEPTION_CODE_LIN_SIGSTKFLT:
966 reason = "SIGSTKFLT";
967 break;
968 case MD_EXCEPTION_CODE_LIN_SIGCHLD:
969 reason = "SIGCHLD";
970 break;
971 case MD_EXCEPTION_CODE_LIN_SIGCONT:
972 reason = "SIGCONT";
973 break;
974 case MD_EXCEPTION_CODE_LIN_SIGSTOP:
975 reason = "SIGSTOP";
976 break;
977 case MD_EXCEPTION_CODE_LIN_SIGTSTP:
978 reason = "SIGTSTP";
979 break;
980 case MD_EXCEPTION_CODE_LIN_SIGTTIN:
981 reason = "SIGTTIN";
982 break;
983 case MD_EXCEPTION_CODE_LIN_SIGTTOU:
984 reason = "SIGTTOU";
985 break;
986 case MD_EXCEPTION_CODE_LIN_SIGURG:
987 reason = "SIGURG";
988 break;
989 case MD_EXCEPTION_CODE_LIN_SIGXCPU:
990 reason = "SIGXCPU";
991 break;
992 case MD_EXCEPTION_CODE_LIN_SIGXFSZ:
993 reason = "SIGXFSZ";
994 break;
995 case MD_EXCEPTION_CODE_LIN_SIGVTALRM:
996 reason = "SIGVTALRM";
997 break;
998 case MD_EXCEPTION_CODE_LIN_SIGPROF:
999 reason = "SIGPROF";
1000 break;
1001 case MD_EXCEPTION_CODE_LIN_SIGWINCH:
1002 reason = "SIGWINCH";
1003 break;
1004 case MD_EXCEPTION_CODE_LIN_SIGIO:
1005 reason = "SIGIO";
1006 break;
1007 case MD_EXCEPTION_CODE_LIN_SIGPWR:
1008 reason = "SIGPWR";
1009 break;
1010 case MD_EXCEPTION_CODE_LIN_SIGSYS:
1011 reason = "SIGSYS";
1012 break;
1013 case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED:
1014 reason = "DUMP_REQUESTED";
1015 break;
1016 default:
1017 BPLOG(INFO) << "Unknown exception reason " << reason;
1018 break;
1019 }
1020 break;
1021 }
1023 case MD_OS_SOLARIS: {
1024 switch (exception_code) {
1025 case MD_EXCEPTION_CODE_SOL_SIGHUP:
1026 reason = "SIGHUP";
1027 break;
1028 case MD_EXCEPTION_CODE_SOL_SIGINT:
1029 reason = "SIGINT";
1030 break;
1031 case MD_EXCEPTION_CODE_SOL_SIGQUIT:
1032 reason = "SIGQUIT";
1033 break;
1034 case MD_EXCEPTION_CODE_SOL_SIGILL:
1035 reason = "SIGILL";
1036 break;
1037 case MD_EXCEPTION_CODE_SOL_SIGTRAP:
1038 reason = "SIGTRAP";
1039 break;
1040 case MD_EXCEPTION_CODE_SOL_SIGIOT:
1041 reason = "SIGIOT | SIGABRT";
1042 break;
1043 case MD_EXCEPTION_CODE_SOL_SIGEMT:
1044 reason = "SIGEMT";
1045 break;
1046 case MD_EXCEPTION_CODE_SOL_SIGFPE:
1047 reason = "SIGFPE";
1048 break;
1049 case MD_EXCEPTION_CODE_SOL_SIGKILL:
1050 reason = "SIGKILL";
1051 break;
1052 case MD_EXCEPTION_CODE_SOL_SIGBUS:
1053 reason = "SIGBUS";
1054 break;
1055 case MD_EXCEPTION_CODE_SOL_SIGSEGV:
1056 reason = "SIGSEGV";
1057 break;
1058 case MD_EXCEPTION_CODE_SOL_SIGSYS:
1059 reason = "SIGSYS";
1060 break;
1061 case MD_EXCEPTION_CODE_SOL_SIGPIPE:
1062 reason = "SIGPIPE";
1063 break;
1064 case MD_EXCEPTION_CODE_SOL_SIGALRM:
1065 reason = "SIGALRM";
1066 break;
1067 case MD_EXCEPTION_CODE_SOL_SIGTERM:
1068 reason = "SIGTERM";
1069 break;
1070 case MD_EXCEPTION_CODE_SOL_SIGUSR1:
1071 reason = "SIGUSR1";
1072 break;
1073 case MD_EXCEPTION_CODE_SOL_SIGUSR2:
1074 reason = "SIGUSR2";
1075 break;
1076 case MD_EXCEPTION_CODE_SOL_SIGCLD:
1077 reason = "SIGCLD | SIGCHLD";
1078 break;
1079 case MD_EXCEPTION_CODE_SOL_SIGPWR:
1080 reason = "SIGPWR";
1081 break;
1082 case MD_EXCEPTION_CODE_SOL_SIGWINCH:
1083 reason = "SIGWINCH";
1084 break;
1085 case MD_EXCEPTION_CODE_SOL_SIGURG:
1086 reason = "SIGURG";
1087 break;
1088 case MD_EXCEPTION_CODE_SOL_SIGPOLL:
1089 reason = "SIGPOLL | SIGIO";
1090 break;
1091 case MD_EXCEPTION_CODE_SOL_SIGSTOP:
1092 reason = "SIGSTOP";
1093 break;
1094 case MD_EXCEPTION_CODE_SOL_SIGTSTP:
1095 reason = "SIGTSTP";
1096 break;
1097 case MD_EXCEPTION_CODE_SOL_SIGCONT:
1098 reason = "SIGCONT";
1099 break;
1100 case MD_EXCEPTION_CODE_SOL_SIGTTIN:
1101 reason = "SIGTTIN";
1102 break;
1103 case MD_EXCEPTION_CODE_SOL_SIGTTOU:
1104 reason = "SIGTTOU";
1105 break;
1106 case MD_EXCEPTION_CODE_SOL_SIGVTALRM:
1107 reason = "SIGVTALRM";
1108 break;
1109 case MD_EXCEPTION_CODE_SOL_SIGPROF:
1110 reason = "SIGPROF";
1111 break;
1112 case MD_EXCEPTION_CODE_SOL_SIGXCPU:
1113 reason = "SIGXCPU";
1114 break;
1115 case MD_EXCEPTION_CODE_SOL_SIGXFSZ:
1116 reason = "SIGXFSZ";
1117 break;
1118 case MD_EXCEPTION_CODE_SOL_SIGWAITING:
1119 reason = "SIGWAITING";
1120 break;
1121 case MD_EXCEPTION_CODE_SOL_SIGLWP:
1122 reason = "SIGLWP";
1123 break;
1124 case MD_EXCEPTION_CODE_SOL_SIGFREEZE:
1125 reason = "SIGFREEZE";
1126 break;
1127 case MD_EXCEPTION_CODE_SOL_SIGTHAW:
1128 reason = "SIGTHAW";
1129 break;
1130 case MD_EXCEPTION_CODE_SOL_SIGCANCEL:
1131 reason = "SIGCANCEL";
1132 break;
1133 case MD_EXCEPTION_CODE_SOL_SIGLOST:
1134 reason = "SIGLOST";
1135 break;
1136 case MD_EXCEPTION_CODE_SOL_SIGXRES:
1137 reason = "SIGXRES";
1138 break;
1139 case MD_EXCEPTION_CODE_SOL_SIGJVM1:
1140 reason = "SIGJVM1";
1141 break;
1142 case MD_EXCEPTION_CODE_SOL_SIGJVM2:
1143 reason = "SIGJVM2";
1144 break;
1145 default:
1146 BPLOG(INFO) << "Unknown exception reason " << reason;
1147 break;
1148 }
1149 break;
1150 }
1152 default: {
1153 BPLOG(INFO) << "Unknown exception reason " << reason;
1154 break;
1155 }
1156 }
1158 return reason;
1159 }
1161 // static
1162 string MinidumpProcessor::GetAssertion(Minidump *dump) {
1163 MinidumpAssertion *assertion = dump->GetAssertion();
1164 if (!assertion)
1165 return "";
1167 const MDRawAssertionInfo *raw_assertion = assertion->assertion();
1168 if (!raw_assertion)
1169 return "";
1171 string assertion_string;
1172 switch (raw_assertion->type) {
1173 case MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER:
1174 assertion_string = "Invalid parameter passed to library function";
1175 break;
1176 case MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL:
1177 assertion_string = "Pure virtual function called";
1178 break;
1179 default: {
1180 char assertion_type[32];
1181 snprintf(assertion_type, sizeof(assertion_type),
1182 "0x%08x", raw_assertion->type);
1183 assertion_string = "Unknown assertion type ";
1184 assertion_string += assertion_type;
1185 break;
1186 }
1187 }
1189 string expression = assertion->expression();
1190 if (!expression.empty()) {
1191 assertion_string.append(" " + expression);
1192 }
1194 string function = assertion->function();
1195 if (!function.empty()) {
1196 assertion_string.append(" in function " + function);
1197 }
1199 string file = assertion->file();
1200 if (!file.empty()) {
1201 assertion_string.append(", in file " + file);
1202 }
1204 if (raw_assertion->line != 0) {
1205 char assertion_line[32];
1206 snprintf(assertion_line, sizeof(assertion_line), "%u", raw_assertion->line);
1207 assertion_string.append(" at line ");
1208 assertion_string.append(assertion_line);
1209 }
1211 return assertion_string;
1212 }
1214 } // namespace google_breakpad