
We do this in a lot of places, but we're inconsistent.
Normalize the code to the Google C++ style guide.
Change-Id: Ic2aceab661ce8f6b993dda21b1cdf5d2198dcbbf
Reviewed-on: 2262932
Reviewed-by: Sterling Augustine <saugustine@google.com>
Reviewed-by: Mark Mentovai <mark@chromium.org>
1798 lines
62 KiB
C++
1798 lines
62 KiB
C++
// Copyright (c) 2006, Google Inc.
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
// in the documentation and/or other materials provided with the
|
|
// distribution.
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
#include "google_breakpad/processor/minidump_processor.h"
|
|
|
|
#include <assert.h>
|
|
|
|
#include <algorithm>
|
|
#include <string>
|
|
|
|
#include "common/scoped_ptr.h"
|
|
#include "common/stdio_wrapper.h"
|
|
#include "common/using_std_string.h"
|
|
#include "google_breakpad/processor/call_stack.h"
|
|
#include "google_breakpad/processor/minidump.h"
|
|
#include "google_breakpad/processor/process_state.h"
|
|
#include "google_breakpad/processor/exploitability.h"
|
|
#include "google_breakpad/processor/stack_frame_symbolizer.h"
|
|
#include "processor/logging.h"
|
|
#include "processor/stackwalker_x86.h"
|
|
#include "processor/symbolic_constants_win.h"
|
|
|
|
namespace google_breakpad {
|
|
|
|
MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier,
|
|
SourceLineResolverInterface* resolver)
|
|
: frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)),
|
|
own_frame_symbolizer_(true),
|
|
enable_exploitability_(false),
|
|
enable_objdump_(false) {
|
|
}
|
|
|
|
MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier,
|
|
SourceLineResolverInterface* resolver,
|
|
bool enable_exploitability)
|
|
: frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)),
|
|
own_frame_symbolizer_(true),
|
|
enable_exploitability_(enable_exploitability),
|
|
enable_objdump_(false) {
|
|
}
|
|
|
|
MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer* frame_symbolizer,
|
|
bool enable_exploitability)
|
|
: frame_symbolizer_(frame_symbolizer),
|
|
own_frame_symbolizer_(false),
|
|
enable_exploitability_(enable_exploitability),
|
|
enable_objdump_(false) {
|
|
assert(frame_symbolizer_);
|
|
}
|
|
|
|
MinidumpProcessor::~MinidumpProcessor() {
|
|
if (own_frame_symbolizer_) delete frame_symbolizer_;
|
|
}
|
|
|
|
ProcessResult MinidumpProcessor::Process(
|
|
Minidump* dump, ProcessState* process_state) {
|
|
assert(dump);
|
|
assert(process_state);
|
|
|
|
process_state->Clear();
|
|
|
|
const MDRawHeader* header = dump->header();
|
|
if (!header) {
|
|
BPLOG(ERROR) << "Minidump " << dump->path() << " has no header";
|
|
return PROCESS_ERROR_NO_MINIDUMP_HEADER;
|
|
}
|
|
process_state->time_date_stamp_ = header->time_date_stamp;
|
|
|
|
bool has_process_create_time =
|
|
GetProcessCreateTime(dump, &process_state->process_create_time_);
|
|
|
|
bool has_cpu_info = GetCPUInfo(dump, &process_state->system_info_);
|
|
bool has_os_info = GetOSInfo(dump, &process_state->system_info_);
|
|
|
|
uint32_t dump_thread_id = 0;
|
|
bool has_dump_thread = false;
|
|
uint32_t requesting_thread_id = 0;
|
|
bool has_requesting_thread = false;
|
|
|
|
MinidumpBreakpadInfo* breakpad_info = dump->GetBreakpadInfo();
|
|
if (breakpad_info) {
|
|
has_dump_thread = breakpad_info->GetDumpThreadID(&dump_thread_id);
|
|
has_requesting_thread =
|
|
breakpad_info->GetRequestingThreadID(&requesting_thread_id);
|
|
}
|
|
|
|
MinidumpException* exception = dump->GetException();
|
|
if (exception) {
|
|
process_state->crashed_ = true;
|
|
has_requesting_thread = exception->GetThreadID(&requesting_thread_id);
|
|
|
|
process_state->crash_reason_ = GetCrashReason(
|
|
dump, &process_state->crash_address_);
|
|
|
|
process_state->exception_record_.set_code(
|
|
exception->exception()->exception_record.exception_code,
|
|
// TODO(ivanpe): Populate description.
|
|
/* description = */ "");
|
|
process_state->exception_record_.set_flags(
|
|
exception->exception()->exception_record.exception_flags,
|
|
// TODO(ivanpe): Populate description.
|
|
/* description = */ "");
|
|
process_state->exception_record_.set_nested_exception_record_address(
|
|
exception->exception()->exception_record.exception_record);
|
|
process_state->exception_record_.set_address(process_state->crash_address_);
|
|
const uint32_t num_parameters =
|
|
std::min(exception->exception()->exception_record.number_parameters,
|
|
MD_EXCEPTION_MAXIMUM_PARAMETERS);
|
|
for (uint32_t i = 0; i < num_parameters; ++i) {
|
|
process_state->exception_record_.add_parameter(
|
|
exception->exception()->exception_record.exception_information[i],
|
|
// TODO(ivanpe): Populate description.
|
|
/* description = */ "");
|
|
}
|
|
}
|
|
|
|
// This will just return an empty string if it doesn't exist.
|
|
process_state->assertion_ = GetAssertion(dump);
|
|
|
|
MinidumpModuleList* module_list = dump->GetModuleList();
|
|
|
|
// Put a copy of the module list into ProcessState object. This is not
|
|
// necessarily a MinidumpModuleList, but it adheres to the CodeModules
|
|
// interface, which is all that ProcessState needs to expose.
|
|
if (module_list) {
|
|
process_state->modules_ = module_list->Copy();
|
|
process_state->shrunk_range_modules_ =
|
|
process_state->modules_->GetShrunkRangeModules();
|
|
for (unsigned int i = 0;
|
|
i < process_state->shrunk_range_modules_.size();
|
|
i++) {
|
|
linked_ptr<const CodeModule> module =
|
|
process_state->shrunk_range_modules_[i];
|
|
BPLOG(INFO) << "The range for module " << module->code_file()
|
|
<< " was shrunk down by " << HexString(
|
|
module->shrink_down_delta()) << " bytes. ";
|
|
}
|
|
}
|
|
|
|
MinidumpUnloadedModuleList* unloaded_module_list =
|
|
dump->GetUnloadedModuleList();
|
|
if (unloaded_module_list) {
|
|
process_state->unloaded_modules_ = unloaded_module_list->Copy();
|
|
}
|
|
|
|
MinidumpMemoryList* memory_list = dump->GetMemoryList();
|
|
if (memory_list) {
|
|
BPLOG(INFO) << "Found " << memory_list->region_count()
|
|
<< " memory regions.";
|
|
}
|
|
|
|
MinidumpThreadList* threads = dump->GetThreadList();
|
|
if (!threads) {
|
|
BPLOG(ERROR) << "Minidump " << dump->path() << " has no thread list";
|
|
return PROCESS_ERROR_NO_THREAD_LIST;
|
|
}
|
|
|
|
BPLOG(INFO) << "Minidump " << dump->path() << " has " <<
|
|
(has_cpu_info ? "" : "no ") << "CPU info, " <<
|
|
(has_os_info ? "" : "no ") << "OS info, " <<
|
|
(breakpad_info != NULL ? "" : "no ") << "Breakpad info, " <<
|
|
(exception != NULL ? "" : "no ") << "exception, " <<
|
|
(module_list != NULL ? "" : "no ") << "module list, " <<
|
|
(threads != NULL ? "" : "no ") << "thread list, " <<
|
|
(has_dump_thread ? "" : "no ") << "dump thread, " <<
|
|
(has_requesting_thread ? "" : "no ") << "requesting thread, and " <<
|
|
(has_process_create_time ? "" : "no ") << "process create time";
|
|
|
|
bool interrupted = false;
|
|
bool found_requesting_thread = false;
|
|
unsigned int thread_count = threads->thread_count();
|
|
|
|
// Reset frame_symbolizer_ at the beginning of stackwalk for each minidump.
|
|
frame_symbolizer_->Reset();
|
|
|
|
for (unsigned int thread_index = 0;
|
|
thread_index < thread_count;
|
|
++thread_index) {
|
|
char thread_string_buffer[64];
|
|
snprintf(thread_string_buffer, sizeof(thread_string_buffer), "%d/%d",
|
|
thread_index, thread_count);
|
|
string thread_string = dump->path() + ":" + thread_string_buffer;
|
|
|
|
MinidumpThread* thread = threads->GetThreadAtIndex(thread_index);
|
|
if (!thread) {
|
|
BPLOG(ERROR) << "Could not get thread for " << thread_string;
|
|
return PROCESS_ERROR_GETTING_THREAD;
|
|
}
|
|
|
|
uint32_t thread_id;
|
|
if (!thread->GetThreadID(&thread_id)) {
|
|
BPLOG(ERROR) << "Could not get thread ID for " << thread_string;
|
|
return PROCESS_ERROR_GETTING_THREAD_ID;
|
|
}
|
|
|
|
thread_string += " id " + HexString(thread_id);
|
|
BPLOG(INFO) << "Looking at thread " << thread_string;
|
|
|
|
// If this thread is the thread that produced the minidump, don't process
|
|
// it. Because of the problems associated with a thread producing a
|
|
// dump of itself (when both its context and its stack are in flux),
|
|
// processing that stack wouldn't provide much useful data.
|
|
if (has_dump_thread && thread_id == dump_thread_id) {
|
|
continue;
|
|
}
|
|
|
|
MinidumpContext* context = thread->GetContext();
|
|
|
|
if (has_requesting_thread && thread_id == requesting_thread_id) {
|
|
if (found_requesting_thread) {
|
|
// There can't be more than one requesting thread.
|
|
BPLOG(ERROR) << "Duplicate requesting thread: " << thread_string;
|
|
return PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS;
|
|
}
|
|
|
|
// Use processed_state->threads_.size() instead of thread_index.
|
|
// thread_index points to the thread index in the minidump, which
|
|
// might be greater than the thread index in the threads vector if
|
|
// any of the minidump's threads are skipped and not placed into the
|
|
// processed threads vector. The thread vector's current size will
|
|
// be the index of the current thread when it's pushed into the
|
|
// vector.
|
|
process_state->requesting_thread_ = process_state->threads_.size();
|
|
|
|
found_requesting_thread = true;
|
|
|
|
if (process_state->crashed_) {
|
|
// Use the exception record's context for the crashed thread, instead
|
|
// of the thread's own context. For the crashed thread, the thread's
|
|
// own context is the state inside the exception handler. Using it
|
|
// would not result in the expected stack trace from the time of the
|
|
// crash. If the exception context is invalid, however, we fall back
|
|
// on the thread context.
|
|
MinidumpContext* ctx = exception->GetContext();
|
|
context = ctx ? ctx : thread->GetContext();
|
|
}
|
|
}
|
|
|
|
// If the memory region for the stack cannot be read using the RVA stored
|
|
// in the memory descriptor inside MINIDUMP_THREAD, try to locate and use
|
|
// a memory region (containing the stack) from the minidump memory list.
|
|
MinidumpMemoryRegion* thread_memory = thread->GetMemory();
|
|
if (!thread_memory && memory_list) {
|
|
uint64_t start_stack_memory_range = thread->GetStartOfStackMemoryRange();
|
|
if (start_stack_memory_range) {
|
|
thread_memory = memory_list->GetMemoryRegionForAddress(
|
|
start_stack_memory_range);
|
|
}
|
|
}
|
|
if (!thread_memory) {
|
|
BPLOG(ERROR) << "No memory region for " << thread_string;
|
|
}
|
|
|
|
// Use process_state->modules_ instead of module_list, because the
|
|
// |modules| argument will be used to populate the |module| fields in
|
|
// the returned StackFrame objects, which will be placed into the
|
|
// returned ProcessState object. module_list's lifetime is only as
|
|
// long as the Minidump object: it will be deleted when this function
|
|
// returns. process_state->modules_ is owned by the ProcessState object
|
|
// (just like the StackFrame objects), and is much more suitable for this
|
|
// task.
|
|
scoped_ptr<Stackwalker> stackwalker(
|
|
Stackwalker::StackwalkerForCPU(process_state->system_info(),
|
|
context,
|
|
thread_memory,
|
|
process_state->modules_,
|
|
process_state->unloaded_modules_,
|
|
frame_symbolizer_));
|
|
|
|
scoped_ptr<CallStack> stack(new CallStack());
|
|
if (stackwalker.get()) {
|
|
if (!stackwalker->Walk(stack.get(),
|
|
&process_state->modules_without_symbols_,
|
|
&process_state->modules_with_corrupt_symbols_)) {
|
|
BPLOG(INFO) << "Stackwalker interrupt (missing symbols?) at "
|
|
<< thread_string;
|
|
interrupted = true;
|
|
}
|
|
} else {
|
|
// Threads with missing CPU contexts will hit this, but
|
|
// don't abort processing the rest of the dump just for
|
|
// one bad thread.
|
|
BPLOG(ERROR) << "No stackwalker for " << thread_string;
|
|
}
|
|
stack->set_tid(thread_id);
|
|
process_state->threads_.push_back(stack.release());
|
|
process_state->thread_memory_regions_.push_back(thread_memory);
|
|
}
|
|
|
|
if (interrupted) {
|
|
BPLOG(INFO) << "Processing interrupted for " << dump->path();
|
|
return PROCESS_SYMBOL_SUPPLIER_INTERRUPTED;
|
|
}
|
|
|
|
// If a requesting thread was indicated, it must be present.
|
|
if (has_requesting_thread && !found_requesting_thread) {
|
|
// Don't mark as an error, but invalidate the requesting thread
|
|
BPLOG(ERROR) << "Minidump indicated requesting thread " <<
|
|
HexString(requesting_thread_id) << ", not found in " <<
|
|
dump->path();
|
|
process_state->requesting_thread_ = -1;
|
|
}
|
|
|
|
// Exploitability defaults to EXPLOITABILITY_NOT_ANALYZED
|
|
process_state->exploitability_ = EXPLOITABILITY_NOT_ANALYZED;
|
|
|
|
// If an exploitability run was requested we perform the platform specific
|
|
// rating.
|
|
if (enable_exploitability_) {
|
|
scoped_ptr<Exploitability> exploitability(
|
|
Exploitability::ExploitabilityForPlatform(dump,
|
|
process_state,
|
|
enable_objdump_));
|
|
// The engine will be null if the platform is not supported
|
|
if (exploitability != NULL) {
|
|
process_state->exploitability_ = exploitability->CheckExploitability();
|
|
} else {
|
|
process_state->exploitability_ = EXPLOITABILITY_ERR_NOENGINE;
|
|
}
|
|
}
|
|
|
|
BPLOG(INFO) << "Processed " << dump->path();
|
|
return PROCESS_OK;
|
|
}
|
|
|
|
ProcessResult MinidumpProcessor::Process(
|
|
const string& minidump_file, ProcessState* process_state) {
|
|
BPLOG(INFO) << "Processing minidump in file " << minidump_file;
|
|
|
|
Minidump dump(minidump_file);
|
|
if (!dump.Read()) {
|
|
BPLOG(ERROR) << "Minidump " << dump.path() << " could not be read";
|
|
return PROCESS_ERROR_MINIDUMP_NOT_FOUND;
|
|
}
|
|
|
|
return Process(&dump, process_state);
|
|
}
|
|
|
|
// Returns the MDRawSystemInfo from a minidump, or NULL if system info is
|
|
// not available from the minidump. If system_info is non-NULL, it is used
|
|
// to pass back the MinidumpSystemInfo object.
|
|
static const MDRawSystemInfo* GetSystemInfo(Minidump* dump,
|
|
MinidumpSystemInfo** system_info) {
|
|
MinidumpSystemInfo* minidump_system_info = dump->GetSystemInfo();
|
|
if (!minidump_system_info)
|
|
return NULL;
|
|
|
|
if (system_info)
|
|
*system_info = minidump_system_info;
|
|
|
|
return minidump_system_info->system_info();
|
|
}
|
|
|
|
static uint64_t GetAddressForArchitecture(const MDCPUArchitecture architecture,
|
|
size_t raw_address)
|
|
{
|
|
switch (architecture) {
|
|
case MD_CPU_ARCHITECTURE_X86:
|
|
case MD_CPU_ARCHITECTURE_MIPS:
|
|
case MD_CPU_ARCHITECTURE_PPC:
|
|
case MD_CPU_ARCHITECTURE_SHX:
|
|
case MD_CPU_ARCHITECTURE_ARM:
|
|
case MD_CPU_ARCHITECTURE_X86_WIN64:
|
|
// 32-bit architectures, mask the upper bits.
|
|
return raw_address & 0xffffffffULL;
|
|
|
|
default:
|
|
// All other architectures either have 64-bit pointers or it's impossible
|
|
// to tell from the minidump (e.g. MSIL or SPARC) so use 64-bits anyway.
|
|
return raw_address;
|
|
}
|
|
}
|
|
|
|
// Extract CPU info string from ARM-specific MDRawSystemInfo structure.
|
|
// raw_info: pointer to source MDRawSystemInfo.
|
|
// cpu_info: address of target string, cpu info text will be appended to it.
|
|
static void GetARMCpuInfo(const MDRawSystemInfo* raw_info,
|
|
string* cpu_info) {
|
|
assert(raw_info != NULL && cpu_info != NULL);
|
|
|
|
// Write ARM architecture version.
|
|
char cpu_string[32];
|
|
snprintf(cpu_string, sizeof(cpu_string), "ARMv%d",
|
|
raw_info->processor_level);
|
|
cpu_info->append(cpu_string);
|
|
|
|
// There is no good list of implementer id values, but the following
|
|
// pages provide some help:
|
|
// http://comments.gmane.org/gmane.linux.linaro.devel/6903
|
|
// http://forum.xda-developers.com/archive/index.php/t-480226.html
|
|
const struct {
|
|
uint32_t id;
|
|
const char* name;
|
|
} vendors[] = {
|
|
{ 0x41, "ARM" },
|
|
{ 0x51, "Qualcomm" },
|
|
{ 0x56, "Marvell" },
|
|
{ 0x69, "Intel/Marvell" },
|
|
};
|
|
const struct {
|
|
uint32_t id;
|
|
const char* name;
|
|
} parts[] = {
|
|
{ 0x4100c050, "Cortex-A5" },
|
|
{ 0x4100c080, "Cortex-A8" },
|
|
{ 0x4100c090, "Cortex-A9" },
|
|
{ 0x4100c0f0, "Cortex-A15" },
|
|
{ 0x4100c140, "Cortex-R4" },
|
|
{ 0x4100c150, "Cortex-R5" },
|
|
{ 0x4100b360, "ARM1136" },
|
|
{ 0x4100b560, "ARM1156" },
|
|
{ 0x4100b760, "ARM1176" },
|
|
{ 0x4100b020, "ARM11-MPCore" },
|
|
{ 0x41009260, "ARM926" },
|
|
{ 0x41009460, "ARM946" },
|
|
{ 0x41009660, "ARM966" },
|
|
{ 0x510006f0, "Krait" },
|
|
{ 0x510000f0, "Scorpion" },
|
|
};
|
|
|
|
const struct {
|
|
uint32_t hwcap;
|
|
const char* name;
|
|
} features[] = {
|
|
{ MD_CPU_ARM_ELF_HWCAP_SWP, "swp" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_HALF, "half" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_THUMB, "thumb" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_26BIT, "26bit" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_FAST_MULT, "fastmult" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_FPA, "fpa" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_VFP, "vfpv2" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_EDSP, "edsp" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_JAVA, "java" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_IWMMXT, "iwmmxt" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_CRUNCH, "crunch" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_THUMBEE, "thumbee" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_NEON, "neon" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_VFPv3, "vfpv3" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_VFPv3D16, "vfpv3d16" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_TLS, "tls" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_VFPv4, "vfpv4" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_IDIVA, "idiva" },
|
|
{ MD_CPU_ARM_ELF_HWCAP_IDIVT, "idivt" },
|
|
};
|
|
|
|
uint32_t cpuid = raw_info->cpu.arm_cpu_info.cpuid;
|
|
if (cpuid != 0) {
|
|
// Extract vendor name from CPUID
|
|
const char* vendor = NULL;
|
|
uint32_t vendor_id = (cpuid >> 24) & 0xff;
|
|
for (size_t i = 0; i < sizeof(vendors)/sizeof(vendors[0]); ++i) {
|
|
if (vendors[i].id == vendor_id) {
|
|
vendor = vendors[i].name;
|
|
break;
|
|
}
|
|
}
|
|
cpu_info->append(" ");
|
|
if (vendor) {
|
|
cpu_info->append(vendor);
|
|
} else {
|
|
snprintf(cpu_string, sizeof(cpu_string), "vendor(0x%x)", vendor_id);
|
|
cpu_info->append(cpu_string);
|
|
}
|
|
|
|
// Extract part name from CPUID
|
|
uint32_t part_id = (cpuid & 0xff00fff0);
|
|
const char* part = NULL;
|
|
for (size_t i = 0; i < sizeof(parts)/sizeof(parts[0]); ++i) {
|
|
if (parts[i].id == part_id) {
|
|
part = parts[i].name;
|
|
break;
|
|
}
|
|
}
|
|
cpu_info->append(" ");
|
|
if (part != NULL) {
|
|
cpu_info->append(part);
|
|
} else {
|
|
snprintf(cpu_string, sizeof(cpu_string), "part(0x%x)", part_id);
|
|
cpu_info->append(cpu_string);
|
|
}
|
|
}
|
|
uint32_t elf_hwcaps = raw_info->cpu.arm_cpu_info.elf_hwcaps;
|
|
if (elf_hwcaps != 0) {
|
|
cpu_info->append(" features: ");
|
|
const char* comma = "";
|
|
for (size_t i = 0; i < sizeof(features)/sizeof(features[0]); ++i) {
|
|
if (elf_hwcaps & features[i].hwcap) {
|
|
cpu_info->append(comma);
|
|
cpu_info->append(features[i].name);
|
|
comma = ",";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// static
|
|
bool MinidumpProcessor::GetCPUInfo(Minidump* dump, SystemInfo* info) {
|
|
assert(dump);
|
|
assert(info);
|
|
|
|
info->cpu.clear();
|
|
info->cpu_info.clear();
|
|
|
|
MinidumpSystemInfo* system_info;
|
|
const MDRawSystemInfo* raw_system_info = GetSystemInfo(dump, &system_info);
|
|
if (!raw_system_info)
|
|
return false;
|
|
|
|
switch (raw_system_info->processor_architecture) {
|
|
case MD_CPU_ARCHITECTURE_X86:
|
|
case MD_CPU_ARCHITECTURE_AMD64: {
|
|
if (raw_system_info->processor_architecture ==
|
|
MD_CPU_ARCHITECTURE_X86)
|
|
info->cpu = "x86";
|
|
else
|
|
info->cpu = "amd64";
|
|
|
|
const string* cpu_vendor = system_info->GetCPUVendor();
|
|
if (cpu_vendor) {
|
|
info->cpu_info = *cpu_vendor;
|
|
info->cpu_info.append(" ");
|
|
}
|
|
|
|
char x86_info[36];
|
|
snprintf(x86_info, sizeof(x86_info), "family %u model %u stepping %u",
|
|
raw_system_info->processor_level,
|
|
raw_system_info->processor_revision >> 8,
|
|
raw_system_info->processor_revision & 0xff);
|
|
info->cpu_info.append(x86_info);
|
|
break;
|
|
}
|
|
|
|
case MD_CPU_ARCHITECTURE_PPC: {
|
|
info->cpu = "ppc";
|
|
break;
|
|
}
|
|
|
|
case MD_CPU_ARCHITECTURE_PPC64: {
|
|
info->cpu = "ppc64";
|
|
break;
|
|
}
|
|
|
|
case MD_CPU_ARCHITECTURE_SPARC: {
|
|
info->cpu = "sparc";
|
|
break;
|
|
}
|
|
|
|
case MD_CPU_ARCHITECTURE_ARM: {
|
|
info->cpu = "arm";
|
|
GetARMCpuInfo(raw_system_info, &info->cpu_info);
|
|
break;
|
|
}
|
|
|
|
case MD_CPU_ARCHITECTURE_ARM64:
|
|
case MD_CPU_ARCHITECTURE_ARM64_OLD: {
|
|
info->cpu = "arm64";
|
|
break;
|
|
}
|
|
|
|
case MD_CPU_ARCHITECTURE_MIPS: {
|
|
info->cpu = "mips";
|
|
break;
|
|
}
|
|
case MD_CPU_ARCHITECTURE_MIPS64: {
|
|
info->cpu = "mips64";
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
// Assign the numeric architecture ID into the CPU string.
|
|
char cpu_string[7];
|
|
snprintf(cpu_string, sizeof(cpu_string), "0x%04x",
|
|
raw_system_info->processor_architecture);
|
|
info->cpu = cpu_string;
|
|
break;
|
|
}
|
|
}
|
|
|
|
info->cpu_count = raw_system_info->number_of_processors;
|
|
|
|
return true;
|
|
}
|
|
|
|
// static
|
|
bool MinidumpProcessor::GetOSInfo(Minidump* dump, SystemInfo* info) {
|
|
assert(dump);
|
|
assert(info);
|
|
|
|
info->os.clear();
|
|
info->os_short.clear();
|
|
info->os_version.clear();
|
|
|
|
MinidumpSystemInfo* system_info;
|
|
const MDRawSystemInfo* raw_system_info = GetSystemInfo(dump, &system_info);
|
|
if (!raw_system_info)
|
|
return false;
|
|
|
|
info->os_short = system_info->GetOS();
|
|
|
|
switch (raw_system_info->platform_id) {
|
|
case MD_OS_WIN32_NT: {
|
|
info->os = "Windows NT";
|
|
break;
|
|
}
|
|
|
|
case MD_OS_WIN32_WINDOWS: {
|
|
info->os = "Windows";
|
|
break;
|
|
}
|
|
|
|
case MD_OS_MAC_OS_X: {
|
|
info->os = "Mac OS X";
|
|
break;
|
|
}
|
|
|
|
case MD_OS_IOS: {
|
|
info->os = "iOS";
|
|
break;
|
|
}
|
|
|
|
case MD_OS_LINUX: {
|
|
info->os = "Linux";
|
|
break;
|
|
}
|
|
|
|
case MD_OS_SOLARIS: {
|
|
info->os = "Solaris";
|
|
break;
|
|
}
|
|
|
|
case MD_OS_ANDROID: {
|
|
info->os = "Android";
|
|
break;
|
|
}
|
|
|
|
case MD_OS_PS3: {
|
|
info->os = "PS3";
|
|
break;
|
|
}
|
|
|
|
case MD_OS_NACL: {
|
|
info->os = "NaCl";
|
|
break;
|
|
}
|
|
|
|
case MD_OS_FUCHSIA: {
|
|
info->os = "Fuchsia";
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
// Assign the numeric platform ID into the OS string.
|
|
char os_string[11];
|
|
snprintf(os_string, sizeof(os_string), "0x%08x",
|
|
raw_system_info->platform_id);
|
|
info->os = os_string;
|
|
break;
|
|
}
|
|
}
|
|
|
|
char os_version_string[33];
|
|
snprintf(os_version_string, sizeof(os_version_string), "%u.%u.%u",
|
|
raw_system_info->major_version,
|
|
raw_system_info->minor_version,
|
|
raw_system_info->build_number);
|
|
info->os_version = os_version_string;
|
|
|
|
const string* csd_version = system_info->GetCSDVersion();
|
|
if (csd_version) {
|
|
info->os_version.append(" ");
|
|
info->os_version.append(*csd_version);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// static
|
|
bool MinidumpProcessor::GetProcessCreateTime(Minidump* dump,
|
|
uint32_t* process_create_time) {
|
|
assert(dump);
|
|
assert(process_create_time);
|
|
|
|
*process_create_time = 0;
|
|
|
|
MinidumpMiscInfo* minidump_misc_info = dump->GetMiscInfo();
|
|
if (!minidump_misc_info) {
|
|
return false;
|
|
}
|
|
|
|
const MDRawMiscInfo* md_raw_misc_info = minidump_misc_info->misc_info();
|
|
if (!md_raw_misc_info) {
|
|
return false;
|
|
}
|
|
|
|
if (!(md_raw_misc_info->flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES)) {
|
|
return false;
|
|
}
|
|
|
|
*process_create_time = md_raw_misc_info->process_create_time;
|
|
return true;
|
|
}
|
|
|
|
// static
|
|
string MinidumpProcessor::GetCrashReason(Minidump* dump, uint64_t* address) {
|
|
MinidumpException* exception = dump->GetException();
|
|
if (!exception)
|
|
return "";
|
|
|
|
const MDRawExceptionStream* raw_exception = exception->exception();
|
|
if (!raw_exception)
|
|
return "";
|
|
|
|
if (address)
|
|
*address = raw_exception->exception_record.exception_address;
|
|
|
|
// The reason value is OS-specific and possibly CPU-specific. Set up
|
|
// sensible numeric defaults for the reason string in case we can't
|
|
// map the codes to a string (because there's no system info, or because
|
|
// it's an unrecognized platform, or because it's an unrecognized code.)
|
|
char reason_string[24];
|
|
char flags_string[11];
|
|
uint32_t exception_code = raw_exception->exception_record.exception_code;
|
|
uint32_t exception_flags = raw_exception->exception_record.exception_flags;
|
|
snprintf(flags_string, sizeof(flags_string), "0x%08x", exception_flags);
|
|
snprintf(reason_string, sizeof(reason_string), "0x%08x / %s", exception_code,
|
|
flags_string);
|
|
string reason = reason_string;
|
|
|
|
const MDRawSystemInfo* raw_system_info = GetSystemInfo(dump, NULL);
|
|
if (!raw_system_info)
|
|
return reason;
|
|
|
|
switch (raw_system_info->platform_id) {
|
|
case MD_OS_FUCHSIA: {
|
|
switch (exception_code) {
|
|
case MD_EXCEPTION_CODE_FUCHSIA_GENERAL:
|
|
reason = "GENERAL / ";
|
|
reason.append(flags_string);
|
|
break;
|
|
case MD_EXCEPTION_CODE_FUCHSIA_FATAL_PAGE_FAULT:
|
|
reason = "FATAL_PAGE_FAULT / ";
|
|
reason.append(flags_string);
|
|
break;
|
|
case MD_EXCEPTION_CODE_FUCHSIA_UNDEFINED_INSTRUCTION:
|
|
reason = "UNDEFINED_INSTRUCTION / ";
|
|
reason.append(flags_string);
|
|
break;
|
|
case MD_EXCEPTION_CODE_FUCHSIA_SW_BREAKPOINT:
|
|
reason = "SW_BREAKPOINT / ";
|
|
reason.append(flags_string);
|
|
break;
|
|
case MD_EXCEPTION_CODE_FUCHSIA_HW_BREAKPOINT:
|
|
reason = "HW_BREAKPOINT / ";
|
|
reason.append(flags_string);
|
|
break;
|
|
case MD_EXCEPTION_CODE_FUCHSIA_UNALIGNED_ACCESS:
|
|
reason = "UNALIGNED_ACCESS / ";
|
|
reason.append(flags_string);
|
|
break;
|
|
case MD_EXCEPTION_CODE_FUCHSIA_THREAD_STARTING:
|
|
reason = "THREAD_STARTING / ";
|
|
reason.append(flags_string);
|
|
break;
|
|
case MD_EXCEPTION_CODE_FUCHSIA_THREAD_EXITING:
|
|
reason = "THREAD_EXITING / ";
|
|
reason.append(flags_string);
|
|
break;
|
|
case MD_EXCEPTION_CODE_FUCHSIA_POLICY_ERROR:
|
|
reason = "POLICY_ERROR / ";
|
|
reason.append(flags_string);
|
|
break;
|
|
case MD_EXCEPTION_CODE_FUCHSIA_PROCESS_STARTING:
|
|
reason = "PROCESS_STARTING / ";
|
|
reason.append(flags_string);
|
|
break;
|
|
default:
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MD_OS_MAC_OS_X:
|
|
case MD_OS_IOS: {
|
|
switch (exception_code) {
|
|
case MD_EXCEPTION_MAC_BAD_ACCESS:
|
|
reason = "EXC_BAD_ACCESS / ";
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS:
|
|
reason.append("KERN_INVALID_ADDRESS");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE:
|
|
reason.append("KERN_PROTECTION_FAILURE");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_NO_ACCESS:
|
|
reason.append("KERN_NO_ACCESS");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE:
|
|
reason.append("KERN_MEMORY_FAILURE");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_MEMORY_ERROR:
|
|
reason.append("KERN_MEMORY_ERROR");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_CODESIGN_ERROR:
|
|
reason.append("KERN_CODESIGN_ERROR");
|
|
break;
|
|
default:
|
|
// arm and ppc overlap
|
|
if (raw_system_info->processor_architecture ==
|
|
MD_CPU_ARCHITECTURE_ARM ||
|
|
raw_system_info->processor_architecture ==
|
|
MD_CPU_ARCHITECTURE_ARM64_OLD) {
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN:
|
|
reason.append("EXC_ARM_DA_ALIGN");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG:
|
|
reason.append("EXC_ARM_DA_DEBUG");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
} else if (raw_system_info->processor_architecture ==
|
|
MD_CPU_ARCHITECTURE_PPC) {
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ:
|
|
reason.append("EXC_PPC_VM_PROT_READ");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_BADSPACE:
|
|
reason.append("EXC_PPC_BADSPACE");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED:
|
|
reason.append("EXC_PPC_UNALIGNED");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
} else if (raw_system_info->processor_architecture ==
|
|
MD_CPU_ARCHITECTURE_X86 ||
|
|
raw_system_info->processor_architecture ==
|
|
MD_CPU_ARCHITECTURE_AMD64) {
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT:
|
|
reason.append("EXC_I386_GPFLT");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
} else {
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case MD_EXCEPTION_MAC_BAD_INSTRUCTION:
|
|
reason = "EXC_BAD_INSTRUCTION / ";
|
|
switch (raw_system_info->processor_architecture) {
|
|
case MD_CPU_ARCHITECTURE_ARM:
|
|
case MD_CPU_ARCHITECTURE_ARM64_OLD: {
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_CODE_MAC_ARM_UNDEFINED:
|
|
reason.append("EXC_ARM_UNDEFINED");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case MD_CPU_ARCHITECTURE_PPC: {
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL:
|
|
reason.append("EXC_PPC_INVALID_SYSCALL");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION:
|
|
reason.append("EXC_PPC_UNIPL_INST");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION:
|
|
reason.append("EXC_PPC_PRIVINST");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER:
|
|
reason.append("EXC_PPC_PRIVREG");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_TRACE:
|
|
reason.append("EXC_PPC_TRACE");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR:
|
|
reason.append("EXC_PPC_PERFMON");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case MD_CPU_ARCHITECTURE_AMD64:
|
|
case MD_CPU_ARCHITECTURE_X86: {
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION:
|
|
reason.append("EXC_I386_INVOP");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT:
|
|
reason.append("EXC_I386_INVTSSFLT");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT:
|
|
reason.append("EXC_I386_SEGNPFLT");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT:
|
|
reason.append("EXC_I386_STKFLT");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT:
|
|
reason.append("EXC_I386_GPFLT");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT:
|
|
reason.append("EXC_I386_ALIGNFLT");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
case MD_EXCEPTION_MAC_ARITHMETIC:
|
|
reason = "EXC_ARITHMETIC / ";
|
|
switch (raw_system_info->processor_architecture) {
|
|
case MD_CPU_ARCHITECTURE_PPC: {
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW:
|
|
reason.append("EXC_PPC_OVERFLOW");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE:
|
|
reason.append("EXC_PPC_ZERO_DIVIDE");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT:
|
|
reason.append("EXC_FLT_INEXACT");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE:
|
|
reason.append("EXC_PPC_FLT_ZERO_DIVIDE");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW:
|
|
reason.append("EXC_PPC_FLT_UNDERFLOW");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW:
|
|
reason.append("EXC_PPC_FLT_OVERFLOW");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER:
|
|
reason.append("EXC_PPC_FLT_NOT_A_NUMBER");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION:
|
|
reason.append("EXC_PPC_NOEMULATION");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST:
|
|
reason.append("EXC_PPC_ALTIVECASSIST");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case MD_CPU_ARCHITECTURE_AMD64:
|
|
case MD_CPU_ARCHITECTURE_X86: {
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_CODE_MAC_X86_DIV:
|
|
reason.append("EXC_I386_DIV");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_X86_INTO:
|
|
reason.append("EXC_I386_INTO");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_X86_NOEXT:
|
|
reason.append("EXC_I386_NOEXT");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_X86_EXTOVR:
|
|
reason.append("EXC_I386_EXTOVR");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_X86_EXTERR:
|
|
reason.append("EXC_I386_EXTERR");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_X86_EMERR:
|
|
reason.append("EXC_I386_EMERR");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_X86_BOUND:
|
|
reason.append("EXC_I386_BOUND");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR:
|
|
reason.append("EXC_I386_SSEEXTERR");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
case MD_EXCEPTION_MAC_EMULATION:
|
|
reason = "EXC_EMULATION / ";
|
|
reason.append(flags_string);
|
|
break;
|
|
case MD_EXCEPTION_MAC_SOFTWARE:
|
|
reason = "EXC_SOFTWARE / ";
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_CODE_MAC_ABORT:
|
|
reason.append("SIGABRT");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_NS_EXCEPTION:
|
|
reason.append("UNCAUGHT_NS_EXCEPTION");
|
|
break;
|
|
// These are ppc only but shouldn't be a problem as they're
|
|
// unused on x86
|
|
case MD_EXCEPTION_CODE_MAC_PPC_TRAP:
|
|
reason.append("EXC_PPC_TRAP");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_PPC_MIGRATE:
|
|
reason.append("EXC_PPC_MIGRATE");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
case MD_EXCEPTION_MAC_BREAKPOINT:
|
|
reason = "EXC_BREAKPOINT / ";
|
|
switch (raw_system_info->processor_architecture) {
|
|
case MD_CPU_ARCHITECTURE_ARM:
|
|
case MD_CPU_ARCHITECTURE_ARM64_OLD: {
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN:
|
|
reason.append("EXC_ARM_DA_ALIGN");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG:
|
|
reason.append("EXC_ARM_DA_DEBUG");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_ARM_BREAKPOINT:
|
|
reason.append("EXC_ARM_BREAKPOINT");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case MD_CPU_ARCHITECTURE_PPC: {
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT:
|
|
reason.append("EXC_PPC_BREAKPOINT");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case MD_CPU_ARCHITECTURE_AMD64:
|
|
case MD_CPU_ARCHITECTURE_X86: {
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_CODE_MAC_X86_SGL:
|
|
reason.append("EXC_I386_SGL");
|
|
break;
|
|
case MD_EXCEPTION_CODE_MAC_X86_BPT:
|
|
reason.append("EXC_I386_BPT");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
case MD_EXCEPTION_MAC_SYSCALL:
|
|
reason = "EXC_SYSCALL / ";
|
|
reason.append(flags_string);
|
|
break;
|
|
case MD_EXCEPTION_MAC_MACH_SYSCALL:
|
|
reason = "EXC_MACH_SYSCALL / ";
|
|
reason.append(flags_string);
|
|
break;
|
|
case MD_EXCEPTION_MAC_RPC_ALERT:
|
|
reason = "EXC_RPC_ALERT / ";
|
|
reason.append(flags_string);
|
|
break;
|
|
case MD_EXCEPTION_MAC_SIMULATED:
|
|
reason = "Simulated Exception";
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MD_OS_WIN32_NT:
|
|
case MD_OS_WIN32_WINDOWS: {
|
|
switch (exception_code) {
|
|
case MD_EXCEPTION_CODE_WIN_CONTROL_C:
|
|
reason = "DBG_CONTROL_C";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION:
|
|
reason = "EXCEPTION_GUARD_PAGE";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT:
|
|
reason = "EXCEPTION_DATATYPE_MISALIGNMENT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_BREAKPOINT:
|
|
reason = "EXCEPTION_BREAKPOINT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_SINGLE_STEP:
|
|
reason = "EXCEPTION_SINGLE_STEP";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION:
|
|
// For EXCEPTION_ACCESS_VIOLATION, Windows puts the address that
|
|
// caused the fault in exception_information[1].
|
|
// exception_information[0] is 0 if the violation was caused by
|
|
// an attempt to read data, 1 if it was an attempt to write data,
|
|
// and 8 if this was a data execution violation.
|
|
// This information is useful in addition to the code address, which
|
|
// will be present in the crash thread's instruction field anyway.
|
|
if (raw_exception->exception_record.number_parameters >= 1) {
|
|
MDAccessViolationTypeWin av_type =
|
|
static_cast<MDAccessViolationTypeWin>
|
|
(raw_exception->exception_record.exception_information[0]);
|
|
switch (av_type) {
|
|
case MD_ACCESS_VIOLATION_WIN_READ:
|
|
reason = "EXCEPTION_ACCESS_VIOLATION_READ";
|
|
break;
|
|
case MD_ACCESS_VIOLATION_WIN_WRITE:
|
|
reason = "EXCEPTION_ACCESS_VIOLATION_WRITE";
|
|
break;
|
|
case MD_ACCESS_VIOLATION_WIN_EXEC:
|
|
reason = "EXCEPTION_ACCESS_VIOLATION_EXEC";
|
|
break;
|
|
default:
|
|
reason = "EXCEPTION_ACCESS_VIOLATION";
|
|
break;
|
|
}
|
|
} else {
|
|
reason = "EXCEPTION_ACCESS_VIOLATION";
|
|
}
|
|
if (address &&
|
|
raw_exception->exception_record.number_parameters >= 2) {
|
|
*address =
|
|
raw_exception->exception_record.exception_information[1];
|
|
}
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR:
|
|
// For EXCEPTION_IN_PAGE_ERROR, Windows puts the address that
|
|
// caused the fault in exception_information[1].
|
|
// exception_information[0] is 0 if the violation was caused by
|
|
// an attempt to read data, 1 if it was an attempt to write data,
|
|
// and 8 if this was a data execution violation.
|
|
// exception_information[2] contains the underlying NTSTATUS code,
|
|
// which is the explanation for why this error occured.
|
|
// This information is useful in addition to the code address, which
|
|
// will be present in the crash thread's instruction field anyway.
|
|
if (raw_exception->exception_record.number_parameters >= 1) {
|
|
MDInPageErrorTypeWin av_type =
|
|
static_cast<MDInPageErrorTypeWin>
|
|
(raw_exception->exception_record.exception_information[0]);
|
|
switch (av_type) {
|
|
case MD_IN_PAGE_ERROR_WIN_READ:
|
|
reason = "EXCEPTION_IN_PAGE_ERROR_READ";
|
|
break;
|
|
case MD_IN_PAGE_ERROR_WIN_WRITE:
|
|
reason = "EXCEPTION_IN_PAGE_ERROR_WRITE";
|
|
break;
|
|
case MD_IN_PAGE_ERROR_WIN_EXEC:
|
|
reason = "EXCEPTION_IN_PAGE_ERROR_EXEC";
|
|
break;
|
|
default:
|
|
reason = "EXCEPTION_IN_PAGE_ERROR";
|
|
break;
|
|
}
|
|
} else {
|
|
reason = "EXCEPTION_IN_PAGE_ERROR";
|
|
}
|
|
if (address &&
|
|
raw_exception->exception_record.number_parameters >= 2) {
|
|
*address =
|
|
raw_exception->exception_record.exception_information[1];
|
|
}
|
|
if (raw_exception->exception_record.number_parameters >= 3) {
|
|
uint32_t ntstatus =
|
|
static_cast<uint32_t>
|
|
(raw_exception->exception_record.exception_information[2]);
|
|
reason.append(" / ");
|
|
reason.append(NTStatusToString(ntstatus));
|
|
}
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_INVALID_HANDLE:
|
|
reason = "EXCEPTION_INVALID_HANDLE";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION:
|
|
reason = "EXCEPTION_ILLEGAL_INSTRUCTION";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION:
|
|
reason = "EXCEPTION_NONCONTINUABLE_EXCEPTION";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION:
|
|
reason = "EXCEPTION_INVALID_DISPOSITION";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED:
|
|
reason = "EXCEPTION_BOUNDS_EXCEEDED";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND:
|
|
reason = "EXCEPTION_FLT_DENORMAL_OPERAND";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO:
|
|
reason = "EXCEPTION_FLT_DIVIDE_BY_ZERO";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT:
|
|
reason = "EXCEPTION_FLT_INEXACT_RESULT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION:
|
|
reason = "EXCEPTION_FLT_INVALID_OPERATION";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW:
|
|
reason = "EXCEPTION_FLT_OVERFLOW";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK:
|
|
reason = "EXCEPTION_FLT_STACK_CHECK";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW:
|
|
reason = "EXCEPTION_FLT_UNDERFLOW";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO:
|
|
reason = "EXCEPTION_INT_DIVIDE_BY_ZERO";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW:
|
|
reason = "EXCEPTION_INT_OVERFLOW";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION:
|
|
reason = "EXCEPTION_PRIV_INSTRUCTION";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW:
|
|
reason = "EXCEPTION_STACK_OVERFLOW";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_BAD_FUNCTION_TABLE:
|
|
reason = "EXCEPTION_BAD_FUNCTION_TABLE";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK:
|
|
reason = "EXCEPTION_POSSIBLE_DEADLOCK";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN:
|
|
reason = "EXCEPTION_STACK_BUFFER_OVERRUN";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION:
|
|
reason = "EXCEPTION_HEAP_CORRUPTION";
|
|
break;
|
|
case MD_EXCEPTION_OUT_OF_MEMORY:
|
|
reason = "Out of Memory";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION:
|
|
reason = "Unhandled C++ Exception";
|
|
break;
|
|
case MD_EXCEPTION_CODE_WIN_SIMULATED:
|
|
reason = "Simulated Exception";
|
|
break;
|
|
default:
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MD_OS_ANDROID:
|
|
case MD_OS_LINUX: {
|
|
switch (exception_code) {
|
|
case MD_EXCEPTION_CODE_LIN_SIGHUP:
|
|
reason = "SIGHUP";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGINT:
|
|
reason = "SIGINT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGQUIT:
|
|
reason = "SIGQUIT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGILL:
|
|
reason = "SIGILL / ";
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_FLAG_LIN_ILL_ILLOPC:
|
|
reason.append("ILL_ILLOPC");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_ILL_ILLOPN:
|
|
reason.append("ILL_ILLOPN");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_ILL_ILLADR:
|
|
reason.append("ILL_ILLADR");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_ILL_ILLTRP:
|
|
reason.append("ILL_ILLTRP");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_ILL_PRVOPC:
|
|
reason.append("ILL_PRVOPC");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_ILL_PRVREG:
|
|
reason.append("ILL_PRVREG");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_ILL_COPROC:
|
|
reason.append("ILL_COPROC");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_ILL_BADSTK:
|
|
reason.append("ILL_BADSTK");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGTRAP:
|
|
reason = "SIGTRAP";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGABRT:
|
|
reason = "SIGABRT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGBUS:
|
|
reason = "SIGBUS / ";
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_FLAG_LIN_BUS_ADRALN:
|
|
reason.append("BUS_ADRALN");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_BUS_ADRERR:
|
|
reason.append("BUS_ADRERR");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_BUS_OBJERR:
|
|
reason.append("BUS_OBJERR");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_BUS_MCEERR_AR:
|
|
reason.append("BUS_MCEERR_AR");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_BUS_MCEERR_AO:
|
|
reason.append("BUS_MCEERR_AO");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGFPE:
|
|
reason = "SIGFPE / ";
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_FLAG_LIN_FPE_INTDIV:
|
|
reason.append("FPE_INTDIV");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_FPE_INTOVF:
|
|
reason.append("FPE_INTOVF");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_FPE_FLTDIV:
|
|
reason.append("FPE_FLTDIV");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_FPE_FLTOVF:
|
|
reason.append("FPE_FLTOVF");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_FPE_FLTUND:
|
|
reason.append("FPE_FLTUND");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_FPE_FLTRES:
|
|
reason.append("FPE_FLTRES");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_FPE_FLTINV:
|
|
reason.append("FPE_FLTINV");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_FPE_FLTSUB:
|
|
reason.append("FPE_FLTSUB");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGKILL:
|
|
reason = "SIGKILL";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGUSR1:
|
|
reason = "SIGUSR1";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGSEGV:
|
|
reason = "SIGSEGV /";
|
|
switch (exception_flags) {
|
|
case MD_EXCEPTION_FLAG_LIN_SEGV_MAPERR:
|
|
reason.append("SEGV_MAPERR");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_SEGV_ACCERR:
|
|
reason.append("SEGV_ACCERR");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_SEGV_BNDERR:
|
|
reason.append("SEGV_BNDERR");
|
|
break;
|
|
case MD_EXCEPTION_FLAG_LIN_SEGV_PKUERR:
|
|
reason.append("SEGV_PKUERR");
|
|
break;
|
|
default:
|
|
reason.append(flags_string);
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGUSR2:
|
|
reason = "SIGUSR2";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGPIPE:
|
|
reason = "SIGPIPE";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGALRM:
|
|
reason = "SIGALRM";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGTERM:
|
|
reason = "SIGTERM";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGSTKFLT:
|
|
reason = "SIGSTKFLT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGCHLD:
|
|
reason = "SIGCHLD";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGCONT:
|
|
reason = "SIGCONT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGSTOP:
|
|
reason = "SIGSTOP";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGTSTP:
|
|
reason = "SIGTSTP";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGTTIN:
|
|
reason = "SIGTTIN";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGTTOU:
|
|
reason = "SIGTTOU";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGURG:
|
|
reason = "SIGURG";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGXCPU:
|
|
reason = "SIGXCPU";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGXFSZ:
|
|
reason = "SIGXFSZ";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGVTALRM:
|
|
reason = "SIGVTALRM";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGPROF:
|
|
reason = "SIGPROF";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGWINCH:
|
|
reason = "SIGWINCH";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGIO:
|
|
reason = "SIGIO";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGPWR:
|
|
reason = "SIGPWR";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_SIGSYS:
|
|
reason = "SIGSYS";
|
|
break;
|
|
case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED:
|
|
reason = "DUMP_REQUESTED";
|
|
break;
|
|
default:
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MD_OS_SOLARIS: {
|
|
switch (exception_code) {
|
|
case MD_EXCEPTION_CODE_SOL_SIGHUP:
|
|
reason = "SIGHUP";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGINT:
|
|
reason = "SIGINT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGQUIT:
|
|
reason = "SIGQUIT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGILL:
|
|
reason = "SIGILL";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGTRAP:
|
|
reason = "SIGTRAP";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGIOT:
|
|
reason = "SIGIOT | SIGABRT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGEMT:
|
|
reason = "SIGEMT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGFPE:
|
|
reason = "SIGFPE";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGKILL:
|
|
reason = "SIGKILL";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGBUS:
|
|
reason = "SIGBUS";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGSEGV:
|
|
reason = "SIGSEGV";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGSYS:
|
|
reason = "SIGSYS";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGPIPE:
|
|
reason = "SIGPIPE";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGALRM:
|
|
reason = "SIGALRM";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGTERM:
|
|
reason = "SIGTERM";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGUSR1:
|
|
reason = "SIGUSR1";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGUSR2:
|
|
reason = "SIGUSR2";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGCLD:
|
|
reason = "SIGCLD | SIGCHLD";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGPWR:
|
|
reason = "SIGPWR";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGWINCH:
|
|
reason = "SIGWINCH";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGURG:
|
|
reason = "SIGURG";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGPOLL:
|
|
reason = "SIGPOLL | SIGIO";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGSTOP:
|
|
reason = "SIGSTOP";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGTSTP:
|
|
reason = "SIGTSTP";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGCONT:
|
|
reason = "SIGCONT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGTTIN:
|
|
reason = "SIGTTIN";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGTTOU:
|
|
reason = "SIGTTOU";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGVTALRM:
|
|
reason = "SIGVTALRM";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGPROF:
|
|
reason = "SIGPROF";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGXCPU:
|
|
reason = "SIGXCPU";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGXFSZ:
|
|
reason = "SIGXFSZ";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGWAITING:
|
|
reason = "SIGWAITING";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGLWP:
|
|
reason = "SIGLWP";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGFREEZE:
|
|
reason = "SIGFREEZE";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGTHAW:
|
|
reason = "SIGTHAW";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGCANCEL:
|
|
reason = "SIGCANCEL";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGLOST:
|
|
reason = "SIGLOST";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGXRES:
|
|
reason = "SIGXRES";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGJVM1:
|
|
reason = "SIGJVM1";
|
|
break;
|
|
case MD_EXCEPTION_CODE_SOL_SIGJVM2:
|
|
reason = "SIGJVM2";
|
|
break;
|
|
default:
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MD_OS_PS3: {
|
|
switch (exception_code) {
|
|
case MD_EXCEPTION_CODE_PS3_UNKNOWN:
|
|
reason = "UNKNOWN";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_TRAP_EXCEP:
|
|
reason = "TRAP_EXCEP";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_PRIV_INSTR:
|
|
reason = "PRIV_INSTR";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_ILLEGAL_INSTR:
|
|
reason = "ILLEGAL_INSTR";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_INSTR_STORAGE:
|
|
reason = "INSTR_STORAGE";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_INSTR_SEGMENT:
|
|
reason = "INSTR_SEGMENT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_DATA_STORAGE:
|
|
reason = "DATA_STORAGE";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_DATA_SEGMENT:
|
|
reason = "DATA_SEGMENT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_FLOAT_POINT:
|
|
reason = "FLOAT_POINT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_DABR_MATCH:
|
|
reason = "DABR_MATCH";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_ALIGN_EXCEP:
|
|
reason = "ALIGN_EXCEP";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_MEMORY_ACCESS:
|
|
reason = "MEMORY_ACCESS";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_COPRO_ALIGN:
|
|
reason = "COPRO_ALIGN";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_COPRO_INVALID_COM:
|
|
reason = "COPRO_INVALID_COM";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_COPRO_ERR:
|
|
reason = "COPRO_ERR";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_COPRO_FIR:
|
|
reason = "COPRO_FIR";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_COPRO_DATA_SEGMENT:
|
|
reason = "COPRO_DATA_SEGMENT";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_COPRO_DATA_STORAGE:
|
|
reason = "COPRO_DATA_STORAGE";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_COPRO_STOP_INSTR:
|
|
reason = "COPRO_STOP_INSTR";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_COPRO_HALT_INSTR:
|
|
reason = "COPRO_HALT_INSTR";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_COPRO_HALTINST_UNKNOWN:
|
|
reason = "COPRO_HALTINSTR_UNKNOWN";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_COPRO_MEMORY_ACCESS:
|
|
reason = "COPRO_MEMORY_ACCESS";
|
|
break;
|
|
case MD_EXCEPTION_CODE_PS3_GRAPHIC:
|
|
reason = "GRAPHIC";
|
|
break;
|
|
default:
|
|
BPLOG(INFO) << "Unknown exception reason "<< reason;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
BPLOG(INFO) << "Unknown exception reason " << reason;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (address) {
|
|
*address = GetAddressForArchitecture(
|
|
static_cast<MDCPUArchitecture>(raw_system_info->processor_architecture),
|
|
*address);
|
|
}
|
|
|
|
return reason;
|
|
}
|
|
|
|
// static
|
|
string MinidumpProcessor::GetAssertion(Minidump* dump) {
|
|
MinidumpAssertion* assertion = dump->GetAssertion();
|
|
if (!assertion)
|
|
return "";
|
|
|
|
const MDRawAssertionInfo* raw_assertion = assertion->assertion();
|
|
if (!raw_assertion)
|
|
return "";
|
|
|
|
string assertion_string;
|
|
switch (raw_assertion->type) {
|
|
case MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER:
|
|
assertion_string = "Invalid parameter passed to library function";
|
|
break;
|
|
case MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL:
|
|
assertion_string = "Pure virtual function called";
|
|
break;
|
|
default: {
|
|
char assertion_type[32];
|
|
snprintf(assertion_type, sizeof(assertion_type),
|
|
"0x%08x", raw_assertion->type);
|
|
assertion_string = "Unknown assertion type ";
|
|
assertion_string += assertion_type;
|
|
break;
|
|
}
|
|
}
|
|
|
|
string expression = assertion->expression();
|
|
if (!expression.empty()) {
|
|
assertion_string.append(" " + expression);
|
|
}
|
|
|
|
string function = assertion->function();
|
|
if (!function.empty()) {
|
|
assertion_string.append(" in function " + function);
|
|
}
|
|
|
|
string file = assertion->file();
|
|
if (!file.empty()) {
|
|
assertion_string.append(", in file " + file);
|
|
}
|
|
|
|
if (raw_assertion->line != 0) {
|
|
char assertion_line[32];
|
|
snprintf(assertion_line, sizeof(assertion_line), "%u", raw_assertion->line);
|
|
assertion_string.append(" at line ");
|
|
assertion_string.append(assertion_line);
|
|
}
|
|
|
|
return assertion_string;
|
|
}
|
|
|
|
} // namespace google_breakpad
|