michael@0: // Copyright (c) 2006, Google Inc. michael@0: // All rights reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: #include "google_breakpad/processor/minidump_processor.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "common/scoped_ptr.h" michael@0: #include "google_breakpad/processor/call_stack.h" michael@0: #include "google_breakpad/processor/minidump.h" michael@0: #include "google_breakpad/processor/process_state.h" michael@0: #include "google_breakpad/processor/exploitability.h" michael@0: #include "google_breakpad/processor/stack_frame_symbolizer.h" michael@0: #include "processor/logging.h" michael@0: #include "processor/stackwalker_x86.h" michael@0: michael@0: namespace google_breakpad { michael@0: michael@0: MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier, michael@0: SourceLineResolverInterface *resolver) michael@0: : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)), michael@0: own_frame_symbolizer_(true), michael@0: enable_exploitability_(false) { michael@0: } michael@0: michael@0: MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier, michael@0: SourceLineResolverInterface *resolver, michael@0: bool enable_exploitability) michael@0: : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)), michael@0: own_frame_symbolizer_(true), michael@0: enable_exploitability_(enable_exploitability) { michael@0: } michael@0: michael@0: MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer *frame_symbolizer, michael@0: bool enable_exploitability) michael@0: : frame_symbolizer_(frame_symbolizer), michael@0: own_frame_symbolizer_(false), michael@0: enable_exploitability_(enable_exploitability) { michael@0: assert(frame_symbolizer_); michael@0: } michael@0: michael@0: MinidumpProcessor::~MinidumpProcessor() { michael@0: if (own_frame_symbolizer_) delete frame_symbolizer_; michael@0: } michael@0: michael@0: ProcessResult MinidumpProcessor::Process( michael@0: Minidump *dump, ProcessState *process_state) { michael@0: assert(dump); michael@0: assert(process_state); michael@0: michael@0: process_state->Clear(); michael@0: michael@0: const MDRawHeader *header = dump->header(); michael@0: if (!header) { michael@0: BPLOG(ERROR) << "Minidump " << dump->path() << " has no header"; michael@0: return PROCESS_ERROR_NO_MINIDUMP_HEADER; michael@0: } michael@0: process_state->time_date_stamp_ = header->time_date_stamp; michael@0: michael@0: bool has_cpu_info = GetCPUInfo(dump, &process_state->system_info_); michael@0: bool has_os_info = GetOSInfo(dump, &process_state->system_info_); michael@0: michael@0: uint32_t dump_thread_id = 0; michael@0: bool has_dump_thread = false; michael@0: uint32_t requesting_thread_id = 0; michael@0: bool has_requesting_thread = false; michael@0: michael@0: MinidumpBreakpadInfo *breakpad_info = dump->GetBreakpadInfo(); michael@0: if (breakpad_info) { michael@0: has_dump_thread = breakpad_info->GetDumpThreadID(&dump_thread_id); michael@0: has_requesting_thread = michael@0: breakpad_info->GetRequestingThreadID(&requesting_thread_id); michael@0: } michael@0: michael@0: MinidumpException *exception = dump->GetException(); michael@0: if (exception) { michael@0: process_state->crashed_ = true; michael@0: has_requesting_thread = exception->GetThreadID(&requesting_thread_id); michael@0: michael@0: process_state->crash_reason_ = GetCrashReason( michael@0: dump, &process_state->crash_address_); michael@0: } michael@0: michael@0: // This will just return an empty string if it doesn't exist. michael@0: process_state->assertion_ = GetAssertion(dump); michael@0: michael@0: MinidumpModuleList *module_list = dump->GetModuleList(); michael@0: michael@0: // Put a copy of the module list into ProcessState object. This is not michael@0: // necessarily a MinidumpModuleList, but it adheres to the CodeModules michael@0: // interface, which is all that ProcessState needs to expose. michael@0: if (module_list) michael@0: process_state->modules_ = module_list->Copy(); michael@0: michael@0: MinidumpThreadList *threads = dump->GetThreadList(); michael@0: if (!threads) { michael@0: BPLOG(ERROR) << "Minidump " << dump->path() << " has no thread list"; michael@0: return PROCESS_ERROR_NO_THREAD_LIST; michael@0: } michael@0: michael@0: BPLOG(INFO) << "Minidump " << dump->path() << " has " << michael@0: (has_cpu_info ? "" : "no ") << "CPU info, " << michael@0: (has_os_info ? "" : "no ") << "OS info, " << michael@0: (breakpad_info != NULL ? "" : "no ") << "Breakpad info, " << michael@0: (exception != NULL ? "" : "no ") << "exception, " << michael@0: (module_list != NULL ? "" : "no ") << "module list, " << michael@0: (threads != NULL ? "" : "no ") << "thread list, " << michael@0: (has_dump_thread ? "" : "no ") << "dump thread, and " << michael@0: (has_requesting_thread ? "" : "no ") << "requesting thread"; michael@0: michael@0: bool interrupted = false; michael@0: bool found_requesting_thread = false; michael@0: unsigned int thread_count = threads->thread_count(); michael@0: michael@0: // Reset frame_symbolizer_ at the beginning of stackwalk for each minidump. michael@0: frame_symbolizer_->Reset(); michael@0: michael@0: for (unsigned int thread_index = 0; michael@0: thread_index < thread_count; michael@0: ++thread_index) { michael@0: char thread_string_buffer[64]; michael@0: snprintf(thread_string_buffer, sizeof(thread_string_buffer), "%d/%d", michael@0: thread_index, thread_count); michael@0: string thread_string = dump->path() + ":" + thread_string_buffer; michael@0: michael@0: MinidumpThread *thread = threads->GetThreadAtIndex(thread_index); michael@0: if (!thread) { michael@0: BPLOG(ERROR) << "Could not get thread for " << thread_string; michael@0: return PROCESS_ERROR_GETTING_THREAD; michael@0: } michael@0: michael@0: uint32_t thread_id; michael@0: if (!thread->GetThreadID(&thread_id)) { michael@0: BPLOG(ERROR) << "Could not get thread ID for " << thread_string; michael@0: return PROCESS_ERROR_GETTING_THREAD_ID; michael@0: } michael@0: michael@0: thread_string += " id " + HexString(thread_id); michael@0: BPLOG(INFO) << "Looking at thread " << thread_string; michael@0: michael@0: // If this thread is the thread that produced the minidump, don't process michael@0: // it. Because of the problems associated with a thread producing a michael@0: // dump of itself (when both its context and its stack are in flux), michael@0: // processing that stack wouldn't provide much useful data. michael@0: if (has_dump_thread && thread_id == dump_thread_id) { michael@0: continue; michael@0: } michael@0: michael@0: MinidumpContext *context = thread->GetContext(); michael@0: michael@0: if (has_requesting_thread && thread_id == requesting_thread_id) { michael@0: if (found_requesting_thread) { michael@0: // There can't be more than one requesting thread. michael@0: BPLOG(ERROR) << "Duplicate requesting thread: " << thread_string; michael@0: return PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS; michael@0: } michael@0: michael@0: // Use processed_state->threads_.size() instead of thread_index. michael@0: // thread_index points to the thread index in the minidump, which michael@0: // might be greater than the thread index in the threads vector if michael@0: // any of the minidump's threads are skipped and not placed into the michael@0: // processed threads vector. The thread vector's current size will michael@0: // be the index of the current thread when it's pushed into the michael@0: // vector. michael@0: process_state->requesting_thread_ = process_state->threads_.size(); michael@0: michael@0: found_requesting_thread = true; michael@0: michael@0: if (process_state->crashed_) { michael@0: // Use the exception record's context for the crashed thread, instead michael@0: // of the thread's own context. For the crashed thread, the thread's michael@0: // own context is the state inside the exception handler. Using it michael@0: // would not result in the expected stack trace from the time of the michael@0: // crash. If the exception context is invalid, however, we fall back michael@0: // on the thread context. michael@0: MinidumpContext *ctx = exception->GetContext(); michael@0: context = ctx ? ctx : thread->GetContext(); michael@0: } michael@0: } michael@0: michael@0: MinidumpMemoryRegion *thread_memory = thread->GetMemory(); michael@0: if (!thread_memory) { michael@0: BPLOG(ERROR) << "No memory region for " << thread_string; michael@0: } michael@0: michael@0: // Use process_state->modules_ instead of module_list, because the michael@0: // |modules| argument will be used to populate the |module| fields in michael@0: // the returned StackFrame objects, which will be placed into the michael@0: // returned ProcessState object. module_list's lifetime is only as michael@0: // long as the Minidump object: it will be deleted when this function michael@0: // returns. process_state->modules_ is owned by the ProcessState object michael@0: // (just like the StackFrame objects), and is much more suitable for this michael@0: // task. michael@0: scoped_ptr stackwalker( michael@0: Stackwalker::StackwalkerForCPU(process_state->system_info(), michael@0: context, michael@0: thread_memory, michael@0: process_state->modules_, michael@0: frame_symbolizer_)); michael@0: michael@0: scoped_ptr stack(new CallStack()); michael@0: if (stackwalker.get()) { michael@0: if (!stackwalker->Walk(stack.get(), michael@0: &process_state->modules_without_symbols_)) { michael@0: BPLOG(INFO) << "Stackwalker interrupt (missing symbols?) at " michael@0: << thread_string; michael@0: interrupted = true; michael@0: } michael@0: } else { michael@0: // Threads with missing CPU contexts will hit this, but michael@0: // don't abort processing the rest of the dump just for michael@0: // one bad thread. michael@0: BPLOG(ERROR) << "No stackwalker for " << thread_string; michael@0: } michael@0: process_state->threads_.push_back(stack.release()); michael@0: process_state->thread_memory_regions_.push_back(thread_memory); michael@0: } michael@0: michael@0: if (interrupted) { michael@0: BPLOG(INFO) << "Processing interrupted for " << dump->path(); michael@0: return PROCESS_SYMBOL_SUPPLIER_INTERRUPTED; michael@0: } michael@0: michael@0: // If a requesting thread was indicated, it must be present. michael@0: if (has_requesting_thread && !found_requesting_thread) { michael@0: // Don't mark as an error, but invalidate the requesting thread michael@0: BPLOG(ERROR) << "Minidump indicated requesting thread " << michael@0: HexString(requesting_thread_id) << ", not found in " << michael@0: dump->path(); michael@0: process_state->requesting_thread_ = -1; michael@0: } michael@0: michael@0: // Exploitability defaults to EXPLOITABILITY_NOT_ANALYZED michael@0: process_state->exploitability_ = EXPLOITABILITY_NOT_ANALYZED; michael@0: michael@0: // If an exploitability run was requested we perform the platform specific michael@0: // rating. michael@0: if (enable_exploitability_) { michael@0: scoped_ptr exploitability( michael@0: Exploitability::ExploitabilityForPlatform(dump, process_state)); michael@0: // The engine will be null if the platform is not supported michael@0: if (exploitability != NULL) { michael@0: process_state->exploitability_ = exploitability->CheckExploitability(); michael@0: } else { michael@0: process_state->exploitability_ = EXPLOITABILITY_ERR_NOENGINE; michael@0: } michael@0: } michael@0: michael@0: BPLOG(INFO) << "Processed " << dump->path(); michael@0: return PROCESS_OK; michael@0: } michael@0: michael@0: ProcessResult MinidumpProcessor::Process( michael@0: const string &minidump_file, ProcessState *process_state) { michael@0: BPLOG(INFO) << "Processing minidump in file " << minidump_file; michael@0: michael@0: Minidump dump(minidump_file); michael@0: if (!dump.Read()) { michael@0: BPLOG(ERROR) << "Minidump " << dump.path() << " could not be read"; michael@0: return PROCESS_ERROR_MINIDUMP_NOT_FOUND; michael@0: } michael@0: michael@0: return Process(&dump, process_state); michael@0: } michael@0: michael@0: // Returns the MDRawSystemInfo from a minidump, or NULL if system info is michael@0: // not available from the minidump. If system_info is non-NULL, it is used michael@0: // to pass back the MinidumpSystemInfo object. michael@0: static const MDRawSystemInfo* GetSystemInfo(Minidump *dump, michael@0: MinidumpSystemInfo **system_info) { michael@0: MinidumpSystemInfo *minidump_system_info = dump->GetSystemInfo(); michael@0: if (!minidump_system_info) michael@0: return NULL; michael@0: michael@0: if (system_info) michael@0: *system_info = minidump_system_info; michael@0: michael@0: return minidump_system_info->system_info(); michael@0: } michael@0: michael@0: // static michael@0: bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) { michael@0: assert(dump); michael@0: assert(info); michael@0: michael@0: info->cpu.clear(); michael@0: info->cpu_info.clear(); michael@0: michael@0: MinidumpSystemInfo *system_info; michael@0: const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info); michael@0: if (!raw_system_info) michael@0: return false; michael@0: michael@0: switch (raw_system_info->processor_architecture) { michael@0: case MD_CPU_ARCHITECTURE_X86: michael@0: case MD_CPU_ARCHITECTURE_AMD64: { michael@0: if (raw_system_info->processor_architecture == michael@0: MD_CPU_ARCHITECTURE_X86) michael@0: info->cpu = "x86"; michael@0: else michael@0: info->cpu = "amd64"; michael@0: michael@0: const string *cpu_vendor = system_info->GetCPUVendor(); michael@0: if (cpu_vendor) { michael@0: info->cpu_info = *cpu_vendor; michael@0: info->cpu_info.append(" "); michael@0: } michael@0: michael@0: char x86_info[36]; michael@0: snprintf(x86_info, sizeof(x86_info), "family %u model %u stepping %u", michael@0: raw_system_info->processor_level, michael@0: raw_system_info->processor_revision >> 8, michael@0: raw_system_info->processor_revision & 0xff); michael@0: info->cpu_info.append(x86_info); michael@0: break; michael@0: } michael@0: michael@0: case MD_CPU_ARCHITECTURE_PPC: { michael@0: info->cpu = "ppc"; michael@0: break; michael@0: } michael@0: michael@0: case MD_CPU_ARCHITECTURE_SPARC: { michael@0: info->cpu = "sparc"; michael@0: break; michael@0: } michael@0: michael@0: case MD_CPU_ARCHITECTURE_ARM: { michael@0: info->cpu = "arm"; michael@0: break; michael@0: } michael@0: michael@0: default: { michael@0: // Assign the numeric architecture ID into the CPU string. michael@0: char cpu_string[7]; michael@0: snprintf(cpu_string, sizeof(cpu_string), "0x%04x", michael@0: raw_system_info->processor_architecture); michael@0: info->cpu = cpu_string; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: info->cpu_count = raw_system_info->number_of_processors; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: // static michael@0: bool MinidumpProcessor::GetOSInfo(Minidump *dump, SystemInfo *info) { michael@0: assert(dump); michael@0: assert(info); michael@0: michael@0: info->os.clear(); michael@0: info->os_short.clear(); michael@0: info->os_version.clear(); michael@0: michael@0: MinidumpSystemInfo *system_info; michael@0: const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info); michael@0: if (!raw_system_info) michael@0: return false; michael@0: michael@0: info->os_short = system_info->GetOS(); michael@0: michael@0: switch (raw_system_info->platform_id) { michael@0: case MD_OS_WIN32_NT: { michael@0: info->os = "Windows NT"; michael@0: break; michael@0: } michael@0: michael@0: case MD_OS_WIN32_WINDOWS: { michael@0: info->os = "Windows"; michael@0: break; michael@0: } michael@0: michael@0: case MD_OS_MAC_OS_X: { michael@0: info->os = "Mac OS X"; michael@0: break; michael@0: } michael@0: michael@0: case MD_OS_IOS: { michael@0: info->os = "iOS"; michael@0: break; michael@0: } michael@0: michael@0: case MD_OS_LINUX: { michael@0: info->os = "Linux"; michael@0: break; michael@0: } michael@0: michael@0: case MD_OS_SOLARIS: { michael@0: info->os = "Solaris"; michael@0: break; michael@0: } michael@0: michael@0: case MD_OS_ANDROID: { michael@0: info->os = "Android"; michael@0: break; michael@0: } michael@0: michael@0: default: { michael@0: // Assign the numeric platform ID into the OS string. michael@0: char os_string[11]; michael@0: snprintf(os_string, sizeof(os_string), "0x%08x", michael@0: raw_system_info->platform_id); michael@0: info->os = os_string; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: char os_version_string[33]; michael@0: snprintf(os_version_string, sizeof(os_version_string), "%u.%u.%u", michael@0: raw_system_info->major_version, michael@0: raw_system_info->minor_version, michael@0: raw_system_info->build_number); michael@0: info->os_version = os_version_string; michael@0: michael@0: const string *csd_version = system_info->GetCSDVersion(); michael@0: if (csd_version) { michael@0: info->os_version.append(" "); michael@0: info->os_version.append(*csd_version); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: // static michael@0: string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) { michael@0: MinidumpException *exception = dump->GetException(); michael@0: if (!exception) michael@0: return ""; michael@0: michael@0: const MDRawExceptionStream *raw_exception = exception->exception(); michael@0: if (!raw_exception) michael@0: return ""; michael@0: michael@0: if (address) michael@0: *address = raw_exception->exception_record.exception_address; michael@0: michael@0: // The reason value is OS-specific and possibly CPU-specific. Set up michael@0: // sensible numeric defaults for the reason string in case we can't michael@0: // map the codes to a string (because there's no system info, or because michael@0: // it's an unrecognized platform, or because it's an unrecognized code.) michael@0: char reason_string[24]; michael@0: uint32_t exception_code = raw_exception->exception_record.exception_code; michael@0: uint32_t exception_flags = raw_exception->exception_record.exception_flags; michael@0: snprintf(reason_string, sizeof(reason_string), "0x%08x / 0x%08x", michael@0: exception_code, exception_flags); michael@0: string reason = reason_string; michael@0: michael@0: const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, NULL); michael@0: if (!raw_system_info) michael@0: return reason; michael@0: michael@0: switch (raw_system_info->platform_id) { michael@0: case MD_OS_MAC_OS_X: michael@0: case MD_OS_IOS: { michael@0: char flags_string[11]; michael@0: snprintf(flags_string, sizeof(flags_string), "0x%08x", exception_flags); michael@0: switch (exception_code) { michael@0: case MD_EXCEPTION_MAC_BAD_ACCESS: michael@0: reason = "EXC_BAD_ACCESS / "; michael@0: switch (exception_flags) { michael@0: case MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS: michael@0: reason.append("KERN_INVALID_ADDRESS"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE: michael@0: reason.append("KERN_PROTECTION_FAILURE"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_NO_ACCESS: michael@0: reason.append("KERN_NO_ACCESS"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE: michael@0: reason.append("KERN_MEMORY_FAILURE"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_MEMORY_ERROR: michael@0: reason.append("KERN_MEMORY_ERROR"); michael@0: break; michael@0: default: michael@0: // arm and ppc overlap michael@0: if (raw_system_info->processor_architecture == michael@0: MD_CPU_ARCHITECTURE_ARM) { michael@0: switch (exception_flags) { michael@0: case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN: michael@0: reason.append("EXC_ARM_DA_ALIGN"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG: michael@0: reason.append("EXC_ARM_DA_DEBUG"); michael@0: break; michael@0: default: michael@0: reason.append(flags_string); michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: } else if (raw_system_info->processor_architecture == michael@0: MD_CPU_ARCHITECTURE_PPC) { michael@0: switch (exception_flags) { michael@0: case MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ: michael@0: reason.append("EXC_PPC_VM_PROT_READ"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_BADSPACE: michael@0: reason.append("EXC_PPC_BADSPACE"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED: michael@0: reason.append("EXC_PPC_UNALIGNED"); michael@0: break; michael@0: default: michael@0: reason.append(flags_string); michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: } else { michael@0: reason.append(flags_string); michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: } michael@0: break; michael@0: } michael@0: break; michael@0: case MD_EXCEPTION_MAC_BAD_INSTRUCTION: michael@0: reason = "EXC_BAD_INSTRUCTION / "; michael@0: switch (raw_system_info->processor_architecture) { michael@0: case MD_CPU_ARCHITECTURE_ARM: { michael@0: switch (exception_flags) { michael@0: case MD_EXCEPTION_CODE_MAC_ARM_UNDEFINED: michael@0: reason.append("EXC_ARM_UNDEFINED"); michael@0: break; michael@0: default: michael@0: reason.append(flags_string); michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: break; michael@0: } michael@0: case MD_CPU_ARCHITECTURE_PPC: { michael@0: switch (exception_flags) { michael@0: case MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL: michael@0: reason.append("EXC_PPC_INVALID_SYSCALL"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION: michael@0: reason.append("EXC_PPC_UNIPL_INST"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION: michael@0: reason.append("EXC_PPC_PRIVINST"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER: michael@0: reason.append("EXC_PPC_PRIVREG"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_TRACE: michael@0: reason.append("EXC_PPC_TRACE"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR: michael@0: reason.append("EXC_PPC_PERFMON"); michael@0: break; michael@0: default: michael@0: reason.append(flags_string); michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: break; michael@0: } michael@0: case MD_CPU_ARCHITECTURE_X86: { michael@0: switch (exception_flags) { michael@0: case MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION: michael@0: reason.append("EXC_I386_INVOP"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT: michael@0: reason.append("EXC_INVTSSFLT"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT: michael@0: reason.append("EXC_SEGNPFLT"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT: michael@0: reason.append("EXC_STKFLT"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT: michael@0: reason.append("EXC_GPFLT"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT: michael@0: reason.append("EXC_ALIGNFLT"); michael@0: break; michael@0: default: michael@0: reason.append(flags_string); michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: break; michael@0: } michael@0: default: michael@0: reason.append(flags_string); michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: break; michael@0: case MD_EXCEPTION_MAC_ARITHMETIC: michael@0: reason = "EXC_ARITHMETIC / "; michael@0: switch (raw_system_info->processor_architecture) { michael@0: case MD_CPU_ARCHITECTURE_PPC: { michael@0: switch (exception_flags) { michael@0: case MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW: michael@0: reason.append("EXC_PPC_OVERFLOW"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE: michael@0: reason.append("EXC_PPC_ZERO_DIVIDE"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT: michael@0: reason.append("EXC_FLT_INEXACT"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE: michael@0: reason.append("EXC_PPC_FLT_ZERO_DIVIDE"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW: michael@0: reason.append("EXC_PPC_FLT_UNDERFLOW"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW: michael@0: reason.append("EXC_PPC_FLT_OVERFLOW"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER: michael@0: reason.append("EXC_PPC_FLT_NOT_A_NUMBER"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION: michael@0: reason.append("EXC_PPC_NOEMULATION"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST: michael@0: reason.append("EXC_PPC_ALTIVECASSIST"); michael@0: default: michael@0: reason.append(flags_string); michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: break; michael@0: } michael@0: case MD_CPU_ARCHITECTURE_X86: { michael@0: switch (exception_flags) { michael@0: case MD_EXCEPTION_CODE_MAC_X86_DIV: michael@0: reason.append("EXC_I386_DIV"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_X86_INTO: michael@0: reason.append("EXC_I386_INTO"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_X86_NOEXT: michael@0: reason.append("EXC_I386_NOEXT"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_X86_EXTOVR: michael@0: reason.append("EXC_I386_EXTOVR"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_X86_EXTERR: michael@0: reason.append("EXC_I386_EXTERR"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_X86_EMERR: michael@0: reason.append("EXC_I386_EMERR"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_X86_BOUND: michael@0: reason.append("EXC_I386_BOUND"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR: michael@0: reason.append("EXC_I386_SSEEXTERR"); michael@0: break; michael@0: default: michael@0: reason.append(flags_string); michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: break; michael@0: } michael@0: default: michael@0: reason.append(flags_string); michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: break; michael@0: case MD_EXCEPTION_MAC_EMULATION: michael@0: reason = "EXC_EMULATION / "; michael@0: reason.append(flags_string); michael@0: break; michael@0: case MD_EXCEPTION_MAC_SOFTWARE: michael@0: reason = "EXC_SOFTWARE / "; michael@0: switch (exception_flags) { michael@0: case MD_EXCEPTION_CODE_MAC_ABORT: michael@0: reason.append("SIGABRT"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_NS_EXCEPTION: michael@0: reason.append("UNCAUGHT_NS_EXCEPTION"); michael@0: break; michael@0: // These are ppc only but shouldn't be a problem as they're michael@0: // unused on x86 michael@0: case MD_EXCEPTION_CODE_MAC_PPC_TRAP: michael@0: reason.append("EXC_PPC_TRAP"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_PPC_MIGRATE: michael@0: reason.append("EXC_PPC_MIGRATE"); michael@0: break; michael@0: default: michael@0: reason.append(flags_string); michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: break; michael@0: case MD_EXCEPTION_MAC_BREAKPOINT: michael@0: reason = "EXC_BREAKPOINT / "; michael@0: switch (raw_system_info->processor_architecture) { michael@0: case MD_CPU_ARCHITECTURE_ARM: { michael@0: switch (exception_flags) { michael@0: case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN: michael@0: reason.append("EXC_ARM_DA_ALIGN"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG: michael@0: reason.append("EXC_ARM_DA_DEBUG"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_ARM_BREAKPOINT: michael@0: reason.append("EXC_ARM_BREAKPOINT"); michael@0: break; michael@0: default: michael@0: reason.append(flags_string); michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: break; michael@0: } michael@0: case MD_CPU_ARCHITECTURE_PPC: { michael@0: switch (exception_flags) { michael@0: case MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT: michael@0: reason.append("EXC_PPC_BREAKPOINT"); michael@0: break; michael@0: default: michael@0: reason.append(flags_string); michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: break; michael@0: } michael@0: case MD_CPU_ARCHITECTURE_X86: { michael@0: switch (exception_flags) { michael@0: case MD_EXCEPTION_CODE_MAC_X86_SGL: michael@0: reason.append("EXC_I386_SGL"); michael@0: break; michael@0: case MD_EXCEPTION_CODE_MAC_X86_BPT: michael@0: reason.append("EXC_I386_BPT"); michael@0: break; michael@0: default: michael@0: reason.append(flags_string); michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: break; michael@0: } michael@0: default: michael@0: reason.append(flags_string); michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: break; michael@0: case MD_EXCEPTION_MAC_SYSCALL: michael@0: reason = "EXC_SYSCALL / "; michael@0: reason.append(flags_string); michael@0: break; michael@0: case MD_EXCEPTION_MAC_MACH_SYSCALL: michael@0: reason = "EXC_MACH_SYSCALL / "; michael@0: reason.append(flags_string); michael@0: break; michael@0: case MD_EXCEPTION_MAC_RPC_ALERT: michael@0: reason = "EXC_RPC_ALERT / "; michael@0: reason.append(flags_string); michael@0: break; michael@0: } michael@0: break; michael@0: } michael@0: michael@0: case MD_OS_WIN32_NT: michael@0: case MD_OS_WIN32_WINDOWS: { michael@0: switch (exception_code) { michael@0: case MD_EXCEPTION_CODE_WIN_CONTROL_C: michael@0: reason = "DBG_CONTROL_C"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION: michael@0: reason = "EXCEPTION_GUARD_PAGE"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT: michael@0: reason = "EXCEPTION_DATATYPE_MISALIGNMENT"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_BREAKPOINT: michael@0: reason = "EXCEPTION_BREAKPOINT"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_SINGLE_STEP: michael@0: reason = "EXCEPTION_SINGLE_STEP"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION: michael@0: // For EXCEPTION_ACCESS_VIOLATION, Windows puts the address that michael@0: // caused the fault in exception_information[1]. michael@0: // exception_information[0] is 0 if the violation was caused by michael@0: // an attempt to read data and 1 if it was an attempt to write michael@0: // data. michael@0: // This information is useful in addition to the code address, which michael@0: // will be present in the crash thread's instruction field anyway. michael@0: if (raw_exception->exception_record.number_parameters >= 1) { michael@0: MDAccessViolationTypeWin av_type = michael@0: static_cast michael@0: (raw_exception->exception_record.exception_information[0]); michael@0: switch (av_type) { michael@0: case MD_ACCESS_VIOLATION_WIN_READ: michael@0: reason = "EXCEPTION_ACCESS_VIOLATION_READ"; michael@0: break; michael@0: case MD_ACCESS_VIOLATION_WIN_WRITE: michael@0: reason = "EXCEPTION_ACCESS_VIOLATION_WRITE"; michael@0: break; michael@0: case MD_ACCESS_VIOLATION_WIN_EXEC: michael@0: reason = "EXCEPTION_ACCESS_VIOLATION_EXEC"; michael@0: break; michael@0: default: michael@0: reason = "EXCEPTION_ACCESS_VIOLATION"; michael@0: break; michael@0: } michael@0: } else { michael@0: reason = "EXCEPTION_ACCESS_VIOLATION"; michael@0: } michael@0: if (address && michael@0: raw_exception->exception_record.number_parameters >= 2) { michael@0: *address = michael@0: raw_exception->exception_record.exception_information[1]; michael@0: } michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR: michael@0: reason = "EXCEPTION_IN_PAGE_ERROR"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_INVALID_HANDLE: michael@0: reason = "EXCEPTION_INVALID_HANDLE"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION: michael@0: reason = "EXCEPTION_ILLEGAL_INSTRUCTION"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION: michael@0: reason = "EXCEPTION_NONCONTINUABLE_EXCEPTION"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION: michael@0: reason = "EXCEPTION_INVALID_DISPOSITION"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED: michael@0: reason = "EXCEPTION_BOUNDS_EXCEEDED"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND: michael@0: reason = "EXCEPTION_FLT_DENORMAL_OPERAND"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO: michael@0: reason = "EXCEPTION_FLT_DIVIDE_BY_ZERO"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT: michael@0: reason = "EXCEPTION_FLT_INEXACT_RESULT"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION: michael@0: reason = "EXCEPTION_FLT_INVALID_OPERATION"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW: michael@0: reason = "EXCEPTION_FLT_OVERFLOW"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK: michael@0: reason = "EXCEPTION_FLT_STACK_CHECK"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW: michael@0: reason = "EXCEPTION_FLT_UNDERFLOW"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO: michael@0: reason = "EXCEPTION_INT_DIVIDE_BY_ZERO"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW: michael@0: reason = "EXCEPTION_INT_OVERFLOW"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION: michael@0: reason = "EXCEPTION_PRIV_INSTRUCTION"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW: michael@0: reason = "EXCEPTION_STACK_OVERFLOW"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK: michael@0: reason = "EXCEPTION_POSSIBLE_DEADLOCK"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN: michael@0: reason = "EXCEPTION_STACK_BUFFER_OVERRUN"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION: michael@0: reason = "EXCEPTION_HEAP_CORRUPTION"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION: michael@0: reason = "Unhandled C++ Exception"; michael@0: break; michael@0: default: michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: break; michael@0: } michael@0: michael@0: case MD_OS_ANDROID: michael@0: case MD_OS_LINUX: { michael@0: switch (exception_code) { michael@0: case MD_EXCEPTION_CODE_LIN_SIGHUP: michael@0: reason = "SIGHUP"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGINT: michael@0: reason = "SIGINT"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGQUIT: michael@0: reason = "SIGQUIT"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGILL: michael@0: reason = "SIGILL"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGTRAP: michael@0: reason = "SIGTRAP"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGABRT: michael@0: reason = "SIGABRT"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGBUS: michael@0: reason = "SIGBUS"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGFPE: michael@0: reason = "SIGFPE"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGKILL: michael@0: reason = "SIGKILL"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGUSR1: michael@0: reason = "SIGUSR1"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGSEGV: michael@0: reason = "SIGSEGV"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGUSR2: michael@0: reason = "SIGUSR2"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGPIPE: michael@0: reason = "SIGPIPE"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGALRM: michael@0: reason = "SIGALRM"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGTERM: michael@0: reason = "SIGTERM"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGSTKFLT: michael@0: reason = "SIGSTKFLT"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGCHLD: michael@0: reason = "SIGCHLD"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGCONT: michael@0: reason = "SIGCONT"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGSTOP: michael@0: reason = "SIGSTOP"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGTSTP: michael@0: reason = "SIGTSTP"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGTTIN: michael@0: reason = "SIGTTIN"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGTTOU: michael@0: reason = "SIGTTOU"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGURG: michael@0: reason = "SIGURG"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGXCPU: michael@0: reason = "SIGXCPU"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGXFSZ: michael@0: reason = "SIGXFSZ"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGVTALRM: michael@0: reason = "SIGVTALRM"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGPROF: michael@0: reason = "SIGPROF"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGWINCH: michael@0: reason = "SIGWINCH"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGIO: michael@0: reason = "SIGIO"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGPWR: michael@0: reason = "SIGPWR"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_SIGSYS: michael@0: reason = "SIGSYS"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED: michael@0: reason = "DUMP_REQUESTED"; michael@0: break; michael@0: default: michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: break; michael@0: } michael@0: michael@0: case MD_OS_SOLARIS: { michael@0: switch (exception_code) { michael@0: case MD_EXCEPTION_CODE_SOL_SIGHUP: michael@0: reason = "SIGHUP"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGINT: michael@0: reason = "SIGINT"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGQUIT: michael@0: reason = "SIGQUIT"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGILL: michael@0: reason = "SIGILL"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGTRAP: michael@0: reason = "SIGTRAP"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGIOT: michael@0: reason = "SIGIOT | SIGABRT"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGEMT: michael@0: reason = "SIGEMT"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGFPE: michael@0: reason = "SIGFPE"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGKILL: michael@0: reason = "SIGKILL"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGBUS: michael@0: reason = "SIGBUS"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGSEGV: michael@0: reason = "SIGSEGV"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGSYS: michael@0: reason = "SIGSYS"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGPIPE: michael@0: reason = "SIGPIPE"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGALRM: michael@0: reason = "SIGALRM"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGTERM: michael@0: reason = "SIGTERM"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGUSR1: michael@0: reason = "SIGUSR1"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGUSR2: michael@0: reason = "SIGUSR2"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGCLD: michael@0: reason = "SIGCLD | SIGCHLD"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGPWR: michael@0: reason = "SIGPWR"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGWINCH: michael@0: reason = "SIGWINCH"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGURG: michael@0: reason = "SIGURG"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGPOLL: michael@0: reason = "SIGPOLL | SIGIO"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGSTOP: michael@0: reason = "SIGSTOP"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGTSTP: michael@0: reason = "SIGTSTP"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGCONT: michael@0: reason = "SIGCONT"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGTTIN: michael@0: reason = "SIGTTIN"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGTTOU: michael@0: reason = "SIGTTOU"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGVTALRM: michael@0: reason = "SIGVTALRM"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGPROF: michael@0: reason = "SIGPROF"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGXCPU: michael@0: reason = "SIGXCPU"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGXFSZ: michael@0: reason = "SIGXFSZ"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGWAITING: michael@0: reason = "SIGWAITING"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGLWP: michael@0: reason = "SIGLWP"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGFREEZE: michael@0: reason = "SIGFREEZE"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGTHAW: michael@0: reason = "SIGTHAW"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGCANCEL: michael@0: reason = "SIGCANCEL"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGLOST: michael@0: reason = "SIGLOST"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGXRES: michael@0: reason = "SIGXRES"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGJVM1: michael@0: reason = "SIGJVM1"; michael@0: break; michael@0: case MD_EXCEPTION_CODE_SOL_SIGJVM2: michael@0: reason = "SIGJVM2"; michael@0: break; michael@0: default: michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: break; michael@0: } michael@0: michael@0: default: { michael@0: BPLOG(INFO) << "Unknown exception reason " << reason; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: return reason; michael@0: } michael@0: michael@0: // static michael@0: string MinidumpProcessor::GetAssertion(Minidump *dump) { michael@0: MinidumpAssertion *assertion = dump->GetAssertion(); michael@0: if (!assertion) michael@0: return ""; michael@0: michael@0: const MDRawAssertionInfo *raw_assertion = assertion->assertion(); michael@0: if (!raw_assertion) michael@0: return ""; michael@0: michael@0: string assertion_string; michael@0: switch (raw_assertion->type) { michael@0: case MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER: michael@0: assertion_string = "Invalid parameter passed to library function"; michael@0: break; michael@0: case MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL: michael@0: assertion_string = "Pure virtual function called"; michael@0: break; michael@0: default: { michael@0: char assertion_type[32]; michael@0: snprintf(assertion_type, sizeof(assertion_type), michael@0: "0x%08x", raw_assertion->type); michael@0: assertion_string = "Unknown assertion type "; michael@0: assertion_string += assertion_type; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: string expression = assertion->expression(); michael@0: if (!expression.empty()) { michael@0: assertion_string.append(" " + expression); michael@0: } michael@0: michael@0: string function = assertion->function(); michael@0: if (!function.empty()) { michael@0: assertion_string.append(" in function " + function); michael@0: } michael@0: michael@0: string file = assertion->file(); michael@0: if (!file.empty()) { michael@0: assertion_string.append(", in file " + file); michael@0: } michael@0: michael@0: if (raw_assertion->line != 0) { michael@0: char assertion_line[32]; michael@0: snprintf(assertion_line, sizeof(assertion_line), "%u", raw_assertion->line); michael@0: assertion_string.append(" at line "); michael@0: assertion_string.append(assertion_line); michael@0: } michael@0: michael@0: return assertion_string; michael@0: } michael@0: michael@0: } // namespace google_breakpad