aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--Makefile.in12
-rw-r--r--src/google/call_stack.h3
-rw-r--r--src/google/minidump_processor.h34
-rw-r--r--src/google/process_state.h121
-rw-r--r--src/processor/call_stack.cc1
-rw-r--r--src/processor/minidump.cc52
-rw-r--r--src/processor/minidump.h14
-rw-r--r--src/processor/minidump_processor.cc316
-rw-r--r--src/processor/minidump_processor_unittest.cc17
-rw-r--r--src/processor/process_state.cc49
-rw-r--r--src/processor/testdata/minidump1.out1
12 files changed, 594 insertions, 29 deletions
diff --git a/Makefile.am b/Makefile.am
index 315a4610..a603771c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -53,6 +53,7 @@ src_libairbag_la_SOURCES = \
src/google/airbag_types.h \
src/google/call_stack.h \
src/google/minidump_processor.h \
+ src/google/process_state.h \
src/google/stack_frame.h \
src/google/stack_frame_cpu.h \
src/google/symbol_supplier.h \
@@ -69,6 +70,7 @@ src_libairbag_la_SOURCES = \
src/processor/minidump_processor.cc \
src/processor/postfix_evaluator.h \
src/processor/postfix_evaluator-inl.h \
+ src/processor/process_state.cc \
src/processor/range_map.h \
src/processor/range_map-inl.h \
src/processor/scoped_ptr.h \
@@ -122,6 +124,7 @@ src_processor_minidump_processor_unittest_LDADD = \
src/processor/call_stack.lo \
src/processor/minidump_processor.lo \
src/processor/minidump.lo \
+ src/processor/process_state.lo \
src/processor/stackwalker.lo \
src/processor/stackwalker_ppc.lo \
src/processor/stackwalker_x86.lo \
diff --git a/Makefile.in b/Makefile.in
index d693a496..c7589841 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -111,6 +111,7 @@ src_libairbag_la_LIBADD =
am__dirstamp = $(am__leading_dot)dirstamp
am_src_libairbag_la_OBJECTS = src/processor/call_stack.lo \
src/processor/minidump.lo src/processor/minidump_processor.lo \
+ src/processor/process_state.lo \
src/processor/source_line_resolver.lo \
src/processor/stackwalker.lo src/processor/stackwalker_ppc.lo \
src/processor/stackwalker_x86.lo
@@ -141,7 +142,8 @@ src_processor_minidump_processor_unittest_OBJECTS = \
src_processor_minidump_processor_unittest_DEPENDENCIES = \
src/processor/call_stack.lo \
src/processor/minidump_processor.lo src/processor/minidump.lo \
- src/processor/stackwalker.lo src/processor/stackwalker_ppc.lo \
+ src/processor/process_state.lo src/processor/stackwalker.lo \
+ src/processor/stackwalker_ppc.lo \
src/processor/stackwalker_x86.lo \
src/processor/source_line_resolver.lo
am_src_processor_minidump_stackwalk_OBJECTS = \
@@ -353,6 +355,7 @@ src_libairbag_la_SOURCES = \
src/google/airbag_types.h \
src/google/call_stack.h \
src/google/minidump_processor.h \
+ src/google/process_state.h \
src/google/stack_frame.h \
src/google/stack_frame_cpu.h \
src/google/symbol_supplier.h \
@@ -369,6 +372,7 @@ src_libairbag_la_SOURCES = \
src/processor/minidump_processor.cc \
src/processor/postfix_evaluator.h \
src/processor/postfix_evaluator-inl.h \
+ src/processor/process_state.cc \
src/processor/range_map.h \
src/processor/range_map-inl.h \
src/processor/scoped_ptr.h \
@@ -401,6 +405,7 @@ src_processor_minidump_processor_unittest_LDADD = \
src/processor/call_stack.lo \
src/processor/minidump_processor.lo \
src/processor/minidump.lo \
+ src/processor/process_state.lo \
src/processor/stackwalker.lo \
src/processor/stackwalker_ppc.lo \
src/processor/stackwalker_x86.lo \
@@ -551,6 +556,8 @@ src/processor/minidump.lo: src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
src/processor/minidump_processor.lo: src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
+src/processor/process_state.lo: src/processor/$(am__dirstamp) \
+ src/processor/$(DEPDIR)/$(am__dirstamp)
src/processor/source_line_resolver.lo: src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
src/processor/stackwalker.lo: src/processor/$(am__dirstamp) \
@@ -674,6 +681,8 @@ mostlyclean-compile:
-rm -f src/processor/minidump_processor_unittest.$(OBJEXT)
-rm -f src/processor/minidump_stackwalk.$(OBJEXT)
-rm -f src/processor/postfix_evaluator_unittest.$(OBJEXT)
+ -rm -f src/processor/process_state.$(OBJEXT)
+ -rm -f src/processor/process_state.lo
-rm -f src/processor/range_map_unittest.$(OBJEXT)
-rm -f src/processor/source_line_resolver.$(OBJEXT)
-rm -f src/processor/source_line_resolver.lo
@@ -698,6 +707,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump_processor_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump_stackwalk.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/postfix_evaluator_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/process_state.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/range_map_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/source_line_resolver.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/source_line_resolver_unittest.Po@am__quote@
diff --git a/src/google/call_stack.h b/src/google/call_stack.h
index 6e8f5f13..f51d0ca7 100644
--- a/src/google/call_stack.h
+++ b/src/google/call_stack.h
@@ -64,6 +64,9 @@ class CallStack {
// Stackwalker is responsible for building the frames_ vector.
friend class Stackwalker;
+ // Disallow instantiation other than by friends.
+ CallStack() : frames_() {}
+
// Storage for pushed frames.
vector<StackFrame*> frames_;
};
diff --git a/src/google/minidump_processor.h b/src/google/minidump_processor.h
index 6a126022..2a19ba1a 100644
--- a/src/google/minidump_processor.h
+++ b/src/google/minidump_processor.h
@@ -36,7 +36,8 @@ namespace google_airbag {
using std::string;
-class CallStack;
+class Minidump;
+class ProcessState;
class SymbolSupplier;
class MinidumpProcessor {
@@ -46,9 +47,34 @@ class MinidumpProcessor {
MinidumpProcessor(SymbolSupplier *supplier);
~MinidumpProcessor();
- // Returns a new CallStack produced by processing the minidump file. The
- // caller takes ownership of the CallStack. Returns NULL on failure.
- CallStack* Process(const string &minidump_file);
+ // Returns a new ProcessState object produced by processing the minidump
+ // file. The caller takes ownership of the ProcessState. Returns NULL on
+ // failure.
+ ProcessState* Process(const string &minidump_file);
+
+ // Returns a textual representation of the base CPU type that the minidump
+ // in dump was produced on. Returns an empty string if this information
+ // cannot be determined. If cpu_info is non-NULL, it will be set to
+ // contain additional identifying information about the CPU, or it will
+ // be set empty if additional information cannot be determined.
+ static string GetCPUInfo(Minidump *dump, string *cpu_info);
+
+ // Returns a textual representation of the operating system that the
+ // minidump in dump was produced on. Returns an empty string if this
+ // information cannot be determined. If os_version is non-NULL, it
+ // will be set to contain information about the specific version of the
+ // OS, or it will be set empty if version information cannot be determined.
+ static string GetOSInfo(Minidump *dump, string *os_version);
+
+ // Returns a textual representation of the reason that a crash occurred,
+ // if the minidump in dump was produced as a result of a crash. Returns
+ // an empty string if this information cannot be determined. If address
+ // is non-NULL, it will be set to contain the address that caused the
+ // exception, if this information is available. This will be a code
+ // address when the crash was caused by problems such as illegal
+ // instructions or divisions by zero, or a data address when the crash
+ // was caused by a memory access violation.
+ static string GetCrashReason(Minidump *dump, u_int64_t *address);
private:
SymbolSupplier *supplier_;
diff --git a/src/google/process_state.h b/src/google/process_state.h
new file mode 100644
index 00000000..b233b390
--- /dev/null
+++ b/src/google/process_state.h
@@ -0,0 +1,121 @@
+// 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.
+
+// process_state.h: A snapshot of a process, in a fully-digested state.
+//
+// Author: Mark Mentovai
+
+#ifndef GOOGLE_PROCESS_STATE_H__
+#define GOOGLE_PROCESS_STATE_H__
+
+#include <string>
+#include <vector>
+
+namespace google_airbag {
+
+using std::string;
+using std::vector;
+
+class CallStack;
+
+class ProcessState {
+ public:
+ ~ProcessState();
+
+ // Accessors. See the data declarations below.
+ bool crashed() const { return crashed_; }
+ string crash_reason() const { return crash_reason_; }
+ u_int64_t crash_address() const { return crash_address_; }
+ unsigned int crash_thread() const { return crash_thread_; }
+ const vector<CallStack*>* threads() const { return &threads_; }
+ string os() const { return os_; }
+ string os_version() const { return os_version_; }
+ string cpu() const { return cpu_; }
+ string cpu_info() const { return cpu_info_; }
+
+ private:
+ // MinidumpProcessor is responsible for building ProcessState objects.
+ friend class MinidumpProcessor;
+
+ // Disallow instantiation other than by friends.
+ ProcessState() : crashed_(false), crash_reason_(), crash_address_(0),
+ crash_thread_(0), threads_(), os_(), os_version_(),
+ cpu_(), cpu_info_() {}
+
+ // True if the process crashed, false if the dump was produced outside
+ // of an exception handler.
+ bool crashed_;
+
+ // If the process crashed, the type of crash. OS- and possibly CPU-
+ // specific. For example, "EXCEPTION_ACCESS_VIOLATION" (Windows),
+ // "EXC_BAD_ACCESS / KERN_INVALID_ADDRESS" (Mac OS X), "SIGSEGV"
+ // (other Unix).
+ string crash_reason_;
+
+ // If the process crashed, and if crash_reason implicates memory,
+ // the memory address that caused the crash. For data access errors,
+ // this will be the data address that caused the fault. For code errors,
+ // this will be the address of the instruction that caused the fault.
+ u_int64_t crash_address_;
+
+ // If the process crashed, the index of the crashed thread's stack
+ // in the threads vector.
+ unsigned int crash_thread_;
+
+ // Stacks for each thread (except possibly the exception handler
+ // thread) at the time of the crash.
+ vector<CallStack*> threads_;
+
+ // A string identifying the operating system, such as "Windows NT",
+ // "Mac OS X", or "Linux". If the information is present in the dump but
+ // its value is unknown, this field will contain a numeric value. If
+ // the information is not present in the dump, this field will be empty.
+ string os_;
+
+ // A string identifying the version of the operating system, such as
+ // "5.1.2600 Service Pack 2" or "10.4.8 8L2127". If the dump does not
+ // contain this information, this field will be empty.
+ string os_version_;
+
+ // A string identifying the basic CPU family, such as "x86" or "ppc".
+ // If this information is present in the dump but its value is unknown,
+ // this field will contain a numeric value. If the information is not
+ // present in the dump, this field will be empty.
+ string cpu_;
+
+ // A string further identifying the specific CPU, such as
+ // "GenuineIntel level 6 model 13 stepping 8". If the information is not
+ // present in the dump, or additional identifying information is not
+ // defined for the CPU family, this field will be empty.
+ string cpu_info_;
+};
+
+} // namespace google_airbag
+
+#endif // GOOGLE_CALL_STACK_H__
diff --git a/src/processor/call_stack.cc b/src/processor/call_stack.cc
index 27d62799..1c31b5a3 100644
--- a/src/processor/call_stack.cc
+++ b/src/processor/call_stack.cc
@@ -35,7 +35,6 @@
#include "google/call_stack.h"
#include "google/stack_frame.h"
-#include "processor/linked_ptr.h"
namespace google_airbag {
diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc
index 068f47d0..c99c432e 100644
--- a/src/processor/minidump.cc
+++ b/src/processor/minidump.cc
@@ -1779,12 +1779,14 @@ void MinidumpException::Print() {
MinidumpSystemInfo::MinidumpSystemInfo(Minidump* minidump)
: MinidumpStream(minidump),
system_info_(),
- csd_version_(NULL) {
+ csd_version_(NULL),
+ cpu_vendor_(NULL) {
}
MinidumpSystemInfo::~MinidumpSystemInfo() {
delete csd_version_;
+ delete cpu_vendor_;
}
@@ -1792,6 +1794,8 @@ bool MinidumpSystemInfo::Read(u_int32_t expected_size) {
// Invalidate cached data.
delete csd_version_;
csd_version_ = NULL;
+ delete cpu_vendor_;
+ cpu_vendor_ = NULL;
valid_ = false;
@@ -1844,6 +1848,36 @@ const string* MinidumpSystemInfo::GetCSDVersion() {
}
+const string* MinidumpSystemInfo::GetCPUVendor() {
+ if (!valid_)
+ return NULL;
+
+ // CPU vendor information can only be determined from x86 minidumps.
+ if (!cpu_vendor_ &&
+ (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
+ system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64)) {
+ char cpu_vendor_string[13];
+ snprintf(cpu_vendor_string, sizeof(cpu_vendor_string),
+ "%c%c%c%c%c%c%c%c%c%c%c%c",
+ system_info_.cpu.x86_cpu_info.vendor_id[0] & 0xff,
+ (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 8) & 0xff,
+ (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 16) & 0xff,
+ (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 24) & 0xff,
+ system_info_.cpu.x86_cpu_info.vendor_id[1] & 0xff,
+ (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 8) & 0xff,
+ (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 16) & 0xff,
+ (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 24) & 0xff,
+ system_info_.cpu.x86_cpu_info.vendor_id[2] & 0xff,
+ (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 8) & 0xff,
+ (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 16) & 0xff,
+ (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 24) & 0xff);
+ cpu_vendor_ = new string(cpu_vendor_string);
+ }
+
+ return cpu_vendor_;
+}
+
+
void MinidumpSystemInfo::Print() {
if (!valid_)
return;
@@ -1881,12 +1915,20 @@ void MinidumpSystemInfo::Print() {
system_info_.cpu.x86_cpu_info.feature_information);
printf(" cpu.x86_cpu_info.amd_extended_cpu_features = 0x%x\n",
system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
- const char* csd_version = GetCSDVersion()->c_str();
- if (csd_version)
+ const string* csd_version = GetCSDVersion();
+ if (csd_version) {
printf(" (csd_version) = \"%s\"\n",
- csd_version);
- else
+ csd_version->c_str());
+ } else {
printf(" (csd_version) = (null)\n");
+ }
+ const string* cpu_vendor = GetCPUVendor();
+ if (cpu_vendor) {
+ printf(" (cpu_vendor) = \"%s\"\n",
+ cpu_vendor->c_str());
+ } else {
+ printf(" (cpu_vendor) = (null)\n");
+ }
printf("\n");
}
diff --git a/src/processor/minidump.h b/src/processor/minidump.h
index 1861213d..f67cd35e 100644
--- a/src/processor/minidump.h
+++ b/src/processor/minidump.h
@@ -550,9 +550,16 @@ class MinidumpSystemInfo : public MinidumpStream {
return valid_ ? &system_info_ : 0; }
// I don't know what CSD stands for, but this field is documented as
- // returning a textual representation of the OS service pack.
+ // returning a textual representation of the OS service pack. On other
+ // platforms, this provides additional information about an OS version
+ // level beyond major.minor.micro. Returns NULL if unknown.
const string* GetCSDVersion();
+ // If a CPU vendor string can be determined, returns a pointer to it,
+ // otherwise, returns NULL. CPU vendor strings can be determined from
+ // x86 CPUs with CPUID 0.
+ const string* GetCPUVendor();
+
// Print a human-readable representation of the object to stdout.
void Print();
@@ -569,7 +576,10 @@ class MinidumpSystemInfo : public MinidumpStream {
// Textual representation of the OS service pack, for minidumps produced
// by MiniDumpWriteDump on Windows.
- const string* csd_version_;
+ const string* csd_version_;
+
+ // A string identifying the CPU vendor, if known.
+ const string* cpu_vendor_;
};
diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc
index 8f6497e2..62ad0092 100644
--- a/src/processor/minidump_processor.cc
+++ b/src/processor/minidump_processor.cc
@@ -28,6 +28,8 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "google/minidump_processor.h"
+#include "google/call_stack.h"
+#include "google/process_state.h"
#include "processor/minidump.h"
#include "processor/scoped_ptr.h"
#include "processor/stackwalker_x86.h"
@@ -41,15 +43,25 @@ MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier)
MinidumpProcessor::~MinidumpProcessor() {
}
-CallStack* MinidumpProcessor::Process(const string &minidump_file) {
+ProcessState* MinidumpProcessor::Process(const string &minidump_file) {
Minidump dump(minidump_file);
if (!dump.Read()) {
return NULL;
}
+ scoped_ptr<ProcessState> process_state(new ProcessState());
+
+ process_state->cpu_ = GetCPUInfo(&dump, &process_state->cpu_info_);
+ process_state->os_ = GetOSInfo(&dump, &process_state->os_version_);
+
+ u_int32_t exception_thread_id = 0;
MinidumpException *exception = dump.GetException();
- if (!exception) {
- return NULL;
+ if (exception) {
+ process_state->crashed_ = true;
+ exception_thread_id = exception->GetThreadID();
+
+ process_state->crash_reason_ = GetCrashReason(
+ &dump, &process_state->crash_address_);
}
MinidumpThreadList *threads = dump.GetThreadList();
@@ -57,25 +69,301 @@ CallStack* MinidumpProcessor::Process(const string &minidump_file) {
return NULL;
}
- // TODO(bryner): get all the threads
- MinidumpThread *thread = threads->GetThreadByID(exception->GetThreadID());
- if (!thread) {
- return NULL;
+ bool found_crash_thread = false;
+ unsigned int thread_count = threads->thread_count();
+ for (unsigned int thread_index = 0;
+ thread_index < thread_count;
+ ++thread_index) {
+ MinidumpThread *thread = threads->GetThreadAtIndex(thread_index);
+ if (!thread) {
+ return NULL;
+ }
+
+ if (process_state->crashed_ &&
+ thread->GetThreadID() == exception_thread_id) {
+ if (found_crash_thread) {
+ // There can't be more than one crash thread.
+ return NULL;
+ }
+
+ process_state->crash_thread_ = thread_index;
+ found_crash_thread = true;
+ }
+
+ MinidumpMemoryRegion *thread_memory = thread->GetMemory();
+ if (!thread_memory) {
+ return NULL;
+ }
+
+ scoped_ptr<Stackwalker> stackwalker(
+ Stackwalker::StackwalkerForCPU(exception->GetContext(),
+ thread_memory,
+ dump.GetModuleList(),
+ supplier_));
+ if (!stackwalker.get()) {
+ return NULL;
+ }
+
+ scoped_ptr<CallStack> stack(stackwalker->Walk());
+ if (!stack.get()) {
+ return NULL;
+ }
+
+ process_state->threads_.push_back(stack.release());
}
- MinidumpMemoryRegion *thread_memory = thread->GetMemory();
- if (!thread_memory) {
+ // If the process crashed, there must be a crash thread.
+ if (process_state->crashed_ && !found_crash_thread) {
return NULL;
}
- scoped_ptr<Stackwalker> walker(
- Stackwalker::StackwalkerForCPU(exception->GetContext(), thread_memory,
- dump.GetModuleList(), supplier_));
- if (!walker.get()) {
+ return process_state.release();
+}
+
+// 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
+string MinidumpProcessor::GetCPUInfo(Minidump *dump, string *cpu_info) {
+ if (cpu_info)
+ cpu_info->clear();
+
+ MinidumpSystemInfo *system_info;
+ const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info);
+ if (!raw_system_info)
+ return "";
+
+ string cpu;
+ switch (raw_system_info->processor_architecture) {
+ case MD_CPU_ARCHITECTURE_X86: {
+ cpu = "x86";
+ if (cpu_info) {
+ const string *cpu_vendor = system_info->GetCPUVendor();
+ if (cpu_vendor) {
+ cpu_info->assign(*cpu_vendor);
+ 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);
+ cpu_info->append(x86_info);
+ }
+ break;
+ }
+
+ case MD_CPU_ARCHITECTURE_PPC: {
+ cpu = "ppc";
+ 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);
+ cpu = cpu_string;
+ break;
+ }
+ }
+
+ return cpu;
+}
+
+// static
+string MinidumpProcessor::GetOSInfo(Minidump *dump, string *os_version) {
+ if (os_version)
+ os_version->clear();
+
+ MinidumpSystemInfo *system_info;
+ const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info);
+ if (!raw_system_info)
+ return "";
+
+ string os;
+ switch (raw_system_info->platform_id) {
+ case MD_OS_WIN32_NT: {
+ os = "Windows NT";
+ break;
+ }
+
+ case MD_OS_WIN32_WINDOWS: {
+ os = "Windows";
+ break;
+ }
+
+ case MD_OS_MAC_OS_X: {
+ os = "Mac OS X";
+ break;
+ }
+
+ case MD_OS_LINUX: {
+ os = "Linux";
+ 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);
+ os = os_string;
+ break;
+ }
+ }
+
+ if (os_version) {
+ 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);
+ os_version->assign(os_version_string);
+
+ const string *csd_version = system_info->GetCSDVersion();
+ if (csd_version) {
+ os_version->append(" ");
+ os_version->append(*csd_version);
+ }
+ }
+
+ return os;
+}
+
+// static
+string MinidumpProcessor::GetCrashReason(Minidump *dump, u_int64_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];
+ snprintf(reason_string, sizeof(reason_string), "0x%08x / 0x%08x",
+ raw_exception->exception_record.exception_code,
+ raw_exception->exception_record.exception_flags);
+ 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_WIN32_NT:
+ case MD_OS_WIN32_WINDOWS: {
+ switch (raw_exception->exception_record.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 and 1 if it was an attempt to write
+ // data.
+ // This information is useful in addition to the code address, which
+ // will be present in the crash thread's instruction field anyway.
+ 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:
+ reason = "EXCEPTION_IN_PAGE_ERROR";
+ 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_POSSIBLE_DEADLOCK:
+ reason = "EXCEPTION_POSSIBLE_DEADLOCK";
+ break;
+ }
+ }
}
- return walker->Walk();
+ return reason;
}
} // namespace google_airbag
diff --git a/src/processor/minidump_processor_unittest.cc b/src/processor/minidump_processor_unittest.cc
index 283b67ed..b3c69930 100644
--- a/src/processor/minidump_processor_unittest.cc
+++ b/src/processor/minidump_processor_unittest.cc
@@ -33,6 +33,7 @@
#include <string>
#include "google/call_stack.h"
#include "google/minidump_processor.h"
+#include "google/process_state.h"
#include "google/stack_frame.h"
#include "google/symbol_supplier.h"
#include "processor/minidump.h"
@@ -41,6 +42,7 @@
using std::string;
using google_airbag::CallStack;
using google_airbag::MinidumpProcessor;
+using google_airbag::ProcessState;
using google_airbag::scoped_ptr;
#define ASSERT_TRUE(cond) \
@@ -79,8 +81,19 @@ static bool RunTests() {
string minidump_file = string(getenv("srcdir") ? getenv("srcdir") : ".") +
"/src/processor/testdata/minidump2.dmp";
- scoped_ptr<CallStack> stack(processor.Process(minidump_file));
- ASSERT_TRUE(stack.get());
+ scoped_ptr<ProcessState> state(processor.Process(minidump_file));
+ ASSERT_TRUE(state.get());
+ ASSERT_EQ(state->cpu(), "x86");
+ ASSERT_EQ(state->cpu_info(), "GenuineIntel family 6 model 13 stepping 8");
+ ASSERT_EQ(state->os(), "Windows NT");
+ ASSERT_EQ(state->os_version(), "5.1.2600 Service Pack 2");
+ ASSERT_TRUE(state->crashed());
+ ASSERT_EQ(state->crash_reason(), "EXCEPTION_ACCESS_VIOLATION");
+ ASSERT_EQ(state->crash_address(), 0);
+ ASSERT_EQ(state->threads()->size(), 1);
+ ASSERT_EQ(state->crash_thread(), 0);
+ CallStack *stack = state->threads()->at(0);
+ ASSERT_TRUE(stack);
ASSERT_EQ(stack->frames()->size(), 4);
ASSERT_EQ(stack->frames()->at(0)->module_base, 0x400000);
diff --git a/src/processor/process_state.cc b/src/processor/process_state.cc
new file mode 100644
index 00000000..0099af15
--- /dev/null
+++ b/src/processor/process_state.cc
@@ -0,0 +1,49 @@
+// 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.
+
+// process_state.cc: A snapshot of a process, in a fully-digested state.
+//
+// See process_state.h for documentation.
+//
+// Author: Mark Mentovai
+
+#include "google/process_state.h"
+#include "google/call_stack.h"
+
+namespace google_airbag {
+
+ProcessState::~ProcessState() {
+ for (vector<CallStack *>::const_iterator iterator = threads_.begin();
+ iterator != threads_.end();
+ ++iterator) {
+ delete *iterator;
+ }
+}
+
+} // namespace google_airbag
diff --git a/src/processor/testdata/minidump1.out b/src/processor/testdata/minidump1.out
index bd9c29b2..bb96de00 100644
--- a/src/processor/testdata/minidump1.out
+++ b/src/processor/testdata/minidump1.out
@@ -3725,6 +3725,7 @@ MDRawSystemInfo
cpu.x86_cpu_info.feature_information = 0xafe9fbff
cpu.x86_cpu_info.amd_extended_cpu_features = 0xffffffff
(csd_version) = "Service Pack 2"
+ (cpu_vendor) = "GenuineIntel"
MDRawMiscInfo
size_of_info = 24
flags1 = 0x3