diff --git a/Makefile.am b/Makefile.am index ff45f10a..b0d1c864 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,6 +64,7 @@ src_libairbag_la_SOURCES = \ src/google_airbag/processor/stack_frame_cpu.h \ src/google_airbag/processor/stackwalker.h \ src/google_airbag/processor/symbol_supplier.h \ + src/google_airbag/processor/system_info.h \ src/processor/address_map.h \ src/processor/address_map-inl.h \ src/processor/basic_code_module.h \ diff --git a/Makefile.in b/Makefile.in index 5ffd7550..826f7a2b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -282,6 +282,7 @@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ +GREP = @GREP@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -309,12 +310,9 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ -ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ -ac_ct_RANLIB = @ac_ct_RANLIB@ -ac_ct_STRIP = @ac_ct_STRIP@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ @@ -331,23 +329,30 @@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION) +dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ +htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ +localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ +psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ @@ -355,7 +360,6 @@ target_alias = @target_alias@ # This allows #includes to be relative to src/ AM_CPPFLAGS = -I$(top_srcdir)/src -docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION) dist_doc_DATA = \ AUTHORS \ COPYING \ @@ -380,6 +384,7 @@ src_libairbag_la_SOURCES = \ src/google_airbag/processor/stack_frame_cpu.h \ src/google_airbag/processor/stackwalker.h \ src/google_airbag/processor/symbol_supplier.h \ + src/google_airbag/processor/system_info.h \ src/processor/address_map.h \ src/processor/address_map-inl.h \ src/processor/basic_code_module.h \ diff --git a/src/google_airbag/processor/minidump.h b/src/google_airbag/processor/minidump.h index d9392655..f2700119 100644 --- a/src/google_airbag/processor/minidump.h +++ b/src/google_airbag/processor/minidump.h @@ -569,6 +569,15 @@ class MinidumpSystemInfo : public MinidumpStream { return valid_ ? &system_info_ : NULL; } + // GetOS and GetCPU return textual representations of the operating system + // and CPU that produced the minidump. Unlike most other Minidump* methods, + // they return string objects, not weak pointers. Defined values for + // GetOS() are "mac", "windows", and "linux". Defined values for GetCPU + // are "x86" and "ppc". These methods return an empty string when their + // values are unknown. + string GetOS(); + string GetCPU(); + // I don't know what CSD stands for, but this field is documented as // returning a textual representation of the OS service pack. On other // platforms, this provides additional information about an OS version diff --git a/src/google_airbag/processor/minidump_processor.h b/src/google_airbag/processor/minidump_processor.h index a50d8a79..b1ee5392 100644 --- a/src/google_airbag/processor/minidump_processor.h +++ b/src/google_airbag/processor/minidump_processor.h @@ -40,6 +40,7 @@ class Minidump; class ProcessState; class SourceLineResolverInterface; class SymbolSupplier; +class SystemInfo; class MinidumpProcessor { public: @@ -60,19 +61,15 @@ class MinidumpProcessor { ProcessResult Process(const string &minidump_file, ProcessState *process_state); - // 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); + // Populates the cpu_* fields of the |info| parameter with textual + // representations of the CPU type that the minidump in |dump| was + // produced on. + static void GetCPUInfo(Minidump *dump, SystemInfo *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); + // Populates the os_* fields of the |info| parameter with textual + // representations of the operating system that the minidump in |dump| + // was produced on. + static void GetOSInfo(Minidump *dump, SystemInfo *info); // 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 diff --git a/src/google_airbag/processor/process_state.h b/src/google_airbag/processor/process_state.h index 6fe12155..5ef8047f 100644 --- a/src/google_airbag/processor/process_state.h +++ b/src/google_airbag/processor/process_state.h @@ -36,6 +36,7 @@ #include #include +#include "google_airbag/processor/system_info.h" namespace google_airbag { @@ -60,10 +61,7 @@ class ProcessState { u_int64_t crash_address() const { return crash_address_; } int requesting_thread() const { return requesting_thread_; } const vector* 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_; } + const SystemInfo* system_info() const { return &system_info_; } const CodeModules* modules() const { return modules_; } private: @@ -103,28 +101,8 @@ class ProcessState { // thread) at the time of the crash. vector 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_; + // OS and CPU information. + SystemInfo system_info_; // The modules that were loaded into the process represented by the // ProcessState. @@ -133,4 +111,4 @@ class ProcessState { } // namespace google_airbag -#endif // GOOGLE_AIRBAG_PROCESSOR_CALL_STACK_H__ +#endif // GOOGLE_AIRBAG_PROCESSOR_PROCESS_STATE_H__ diff --git a/src/google_airbag/processor/stackwalker.h b/src/google_airbag/processor/stackwalker.h index 381b9e29..c058f09a 100644 --- a/src/google_airbag/processor/stackwalker.h +++ b/src/google_airbag/processor/stackwalker.h @@ -54,6 +54,7 @@ class SourceLineResolverInterface; struct StackFrame; struct StackFrameInfo; class SymbolSupplier; +class SystemInfo; using std::vector; @@ -71,13 +72,15 @@ class Stackwalker { // Returns a new concrete subclass suitable for the CPU that a stack was // generated on, according to the CPU type indicated by the context // argument. If no suitable concrete subclass exists, returns NULL. - static Stackwalker* StackwalkerForCPU(MinidumpContext *context, + static Stackwalker* StackwalkerForCPU(const SystemInfo *system_info, + MinidumpContext *context, MemoryRegion *memory, const CodeModules *modules, SymbolSupplier *supplier, SourceLineResolverInterface *resolver); protected: + // system_info identifies the operating system, NULL or empty if unknown. // memory identifies a MemoryRegion that provides the stack memory // for the stack to walk. modules, if non-NULL, is a CodeModules // object that is used to look up which code module each stack frame is @@ -86,11 +89,16 @@ class Stackwalker { // resolved. resolver is an instance of SourceLineResolverInterface // (see source_line_resolver_interface.h and basic_source_line_resolver.h). // If resolver is NULL, source line info will not be resolved. - Stackwalker(MemoryRegion *memory, + Stackwalker(const SystemInfo *system_info, + MemoryRegion *memory, const CodeModules *modules, SymbolSupplier *supplier, SourceLineResolverInterface *resolver); + // Information about the system that produced the minidump. Subclasses + // and the SymbolSupplier may find this information useful. + const SystemInfo *system_info_; + // The stack memory to walk. Subclasses will require this region to // get information from the stack. MemoryRegion *memory_; diff --git a/src/google_airbag/processor/symbol_supplier.h b/src/google_airbag/processor/symbol_supplier.h index d456174b..b5ced8ca 100644 --- a/src/google_airbag/processor/symbol_supplier.h +++ b/src/google_airbag/processor/symbol_supplier.h @@ -39,6 +39,7 @@ namespace google_airbag { using std::string; class CodeModule; +class SystemInfo; class SymbolSupplier { public: @@ -57,8 +58,12 @@ class SymbolSupplier { virtual ~SymbolSupplier() {} // Retrieves the symbol file for the given CodeModule, placing the - // path in symbol_file if successful. + // path in symbol_file if successful. system_info contains strings + // identifying the operating system and CPU; SymbolSupplier may use to help + // locate the symbol file. system_info may be NULL or its fields may be + // empty if these values are unknown. virtual SymbolResult GetSymbolFile(const CodeModule *module, + const SystemInfo *system_info, string *symbol_file) = 0; }; diff --git a/src/google_airbag/processor/system_info.h b/src/google_airbag/processor/system_info.h new file mode 100644 index 00000000..faa4502c --- /dev/null +++ b/src/google_airbag/processor/system_info.h @@ -0,0 +1,89 @@ +// 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. + +// system_info.h: Information about the system that was running a program +// when a crash report was produced. +// +// Author: Mark Mentovai + +#ifndef GOOGLE_AIRBAG_PROCESSOR_SYSTEM_INFO_H__ +#define GOOGLE_AIRBAG_PROCESSOR_SYSTEM_INFO_H__ + +#include + +namespace google_airbag { + +using std::string; + +struct SystemInfo { + public: + // Resets the SystemInfo object to its default values. + void Clear() { + os.clear(); + os_short.clear(); + os_version.clear(); + cpu.clear(); + cpu_info.clear(); + } + + // 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 short form of the os string, using lowercase letters and no spaces, + // suitable for use in a filesystem. Possible values are "windows", + // "mac", and "linux". Empty if the information is not present in the dump + // or if the OS given by the dump is unknown. The values stored in this + // field should match those used by MinidumpSystemInfo::GetOS. + string os_short; + + // 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. The values stored in + // this field should match those used by MinidumpSystemInfo::GetCPU. + 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_AIRBAG_PROCESSOR_SYSTEM_INFO_H__ diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc index 34796d19..d27e14b3 100644 --- a/src/processor/minidump.cc +++ b/src/processor/minidump.cc @@ -2047,6 +2047,52 @@ bool MinidumpSystemInfo::Read(u_int32_t expected_size) { } +string MinidumpSystemInfo::GetOS() { + if (!valid_) + return NULL; + + string os; + + switch (system_info_.platform_id) { + case MD_OS_WIN32_NT: + case MD_OS_WIN32_WINDOWS: + os = "windows"; + break; + + case MD_OS_MAC_OS_X: + os = "mac"; + break; + + case MD_OS_LINUX: + os = "linux"; + break; + } + + return os; +} + + +string MinidumpSystemInfo::GetCPU() { + if (!valid_) + return ""; + + string cpu; + + switch (system_info_.processor_architecture) { + case MD_CPU_ARCHITECTURE_X86: + case MD_CPU_ARCHITECTURE_X86_WIN64: + cpu = "x86"; + break; + + case MD_CPU_ARCHITECTURE_PPC: + cpu = "ppc"; + break; + } + + return cpu; +} + + const string* MinidumpSystemInfo::GetCSDVersion() { if (!valid_) return NULL; diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc index dd4c7156..e1dd5e1c 100644 --- a/src/processor/minidump_processor.cc +++ b/src/processor/minidump_processor.cc @@ -59,8 +59,8 @@ MinidumpProcessor::ProcessResult MinidumpProcessor::Process( assert(header); process_state->time_date_stamp_ = header->time_date_stamp; - process_state->cpu_ = GetCPUInfo(&dump, &process_state->cpu_info_); - process_state->os_ = GetOSInfo(&dump, &process_state->os_version_); + GetCPUInfo(&dump, &process_state->system_info_); + GetOSInfo(&dump, &process_state->system_info_); u_int32_t dump_thread_id = 0; bool has_dump_thread = false; @@ -162,7 +162,8 @@ MinidumpProcessor::ProcessResult MinidumpProcessor::Process( // (just like the StackFrame objects), and is much more suitable for this // task. scoped_ptr stackwalker( - Stackwalker::StackwalkerForCPU(context, + Stackwalker::StackwalkerForCPU(process_state->system_info(), + context, thread_memory, process_state->modules_, supplier_, @@ -202,38 +203,38 @@ static const MDRawSystemInfo* GetSystemInfo(Minidump *dump, } // static -string MinidumpProcessor::GetCPUInfo(Minidump *dump, string *cpu_info) { - if (cpu_info) - cpu_info->clear(); +void 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 ""; + 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); + info->cpu = "x86"; + 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: { - cpu = "ppc"; + info->cpu = "ppc"; break; } @@ -242,43 +243,46 @@ string MinidumpProcessor::GetCPUInfo(Minidump *dump, string *cpu_info) { char cpu_string[7]; snprintf(cpu_string, sizeof(cpu_string), "0x%04x", raw_system_info->processor_architecture); - cpu = cpu_string; + info->cpu = cpu_string; break; } } - - return cpu; } // static -string MinidumpProcessor::GetOSInfo(Minidump *dump, string *os_version) { - if (os_version) - os_version->clear(); +void 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 ""; + return; + + info->os_short = system_info->GetOS(); - string os; switch (raw_system_info->platform_id) { case MD_OS_WIN32_NT: { - os = "Windows NT"; + info->os = "Windows NT"; break; } case MD_OS_WIN32_WINDOWS: { - os = "Windows"; + info->os = "Windows"; break; } case MD_OS_MAC_OS_X: { - os = "Mac OS X"; + info->os = "Mac OS X"; break; } case MD_OS_LINUX: { - os = "Linux"; + info->os = "Linux"; break; } @@ -287,27 +291,23 @@ string MinidumpProcessor::GetOSInfo(Minidump *dump, string *os_version) { char os_string[11]; snprintf(os_string, sizeof(os_string), "0x%08x", raw_system_info->platform_id); - os = os_string; + info->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); + 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) { - os_version->append(" "); - os_version->append(*csd_version); - } + const string *csd_version = system_info->GetCSDVersion(); + if (csd_version) { + info->os_version.append(" "); + info->os_version.append(*csd_version); } - - return os; } // static diff --git a/src/processor/minidump_processor_unittest.cc b/src/processor/minidump_processor_unittest.cc index 69a29965..d7381ae1 100644 --- a/src/processor/minidump_processor_unittest.cc +++ b/src/processor/minidump_processor_unittest.cc @@ -30,6 +30,7 @@ // Unit test for MinidumpProcessor. Uses a pre-generated minidump and // corresponding symbol file, and checks the stack frames for correctness. +#include #include #include "google_airbag/processor/basic_source_line_resolver.h" #include "google_airbag/processor/call_stack.h" @@ -51,6 +52,14 @@ using google_airbag::MinidumpProcessor; using google_airbag::ProcessState; using google_airbag::scoped_ptr; using google_airbag::SymbolSupplier; +using google_airbag::SystemInfo; + +static const char *kSystemInfoOS = "Windows NT"; +static const char *kSystemInfoOSShort = "windows"; +static const char *kSystemInfoOSVersion = "5.1.2600 Service Pack 2"; +static const char *kSystemInfoCPU = "x86"; +static const char *kSystemInfoCPUInfo = + "GenuineIntel family 6 model 13 stepping 8"; #define ASSERT_TRUE(cond) \ if (!(cond)) { \ @@ -62,11 +71,21 @@ using google_airbag::SymbolSupplier; #define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2)) +// Use ASSERT_*_ABORT in functions that can't return a boolean. +#define ASSERT_TRUE_ABORT(cond) \ + if (!(cond)) { \ + fprintf(stderr, "FAILED: %s at %s:%d\n", #cond, __FILE__, __LINE__); \ + abort(); \ + } + +#define ASSERT_EQ_ABORT(e1, e2) ASSERT_TRUE_ABORT((e1) == (e2)) + class TestSymbolSupplier : public SymbolSupplier { public: TestSymbolSupplier() : interrupt_(false) {} virtual SymbolResult GetSymbolFile(const CodeModule *module, + const SystemInfo *system_info, string *symbol_file); // When set to true, causes the SymbolSupplier to return INTERRUPT @@ -77,7 +96,17 @@ class TestSymbolSupplier : public SymbolSupplier { }; SymbolSupplier::SymbolResult TestSymbolSupplier::GetSymbolFile( - const CodeModule *module, string *symbol_file) { + const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file) { + ASSERT_TRUE_ABORT(module); + ASSERT_TRUE_ABORT(system_info); + ASSERT_EQ_ABORT(system_info->cpu, kSystemInfoCPU); + ASSERT_EQ_ABORT(system_info->cpu_info, kSystemInfoCPUInfo); + ASSERT_EQ_ABORT(system_info->os, kSystemInfoOS); + ASSERT_EQ_ABORT(system_info->os_short, kSystemInfoOSShort); + ASSERT_EQ_ABORT(system_info->os_version, kSystemInfoOSVersion); + if (interrupt_) { return INTERRUPT; } @@ -104,10 +133,11 @@ static bool RunTests() { ProcessState state; ASSERT_EQ(processor.Process(minidump_file, &state), MinidumpProcessor::PROCESS_OK); - 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_EQ(state.system_info()->os, kSystemInfoOS); + ASSERT_EQ(state.system_info()->os_short, kSystemInfoOSShort); + ASSERT_EQ(state.system_info()->os_version, kSystemInfoOSVersion); + ASSERT_EQ(state.system_info()->cpu, kSystemInfoCPU); + ASSERT_EQ(state.system_info()->cpu_info, kSystemInfoCPUInfo); ASSERT_TRUE(state.crashed()); ASSERT_EQ(state.crash_reason(), "EXCEPTION_ACCESS_VIOLATION"); ASSERT_EQ(state.crash_address(), 0x45); @@ -121,7 +151,8 @@ static bool RunTests() { ASSERT_TRUE(stack->frames()->at(0)->module); ASSERT_EQ(stack->frames()->at(0)->module->base_address(), 0x400000); ASSERT_EQ(stack->frames()->at(0)->module->code_file(), "C:\\test_app.exe"); - ASSERT_EQ(stack->frames()->at(0)->function_name, "`anonymous namespace'::CrashFunction"); + ASSERT_EQ(stack->frames()->at(0)->function_name, + "`anonymous namespace'::CrashFunction"); ASSERT_EQ(stack->frames()->at(0)->source_file_name, "c:\\test_app.cc"); ASSERT_EQ(stack->frames()->at(0)->source_line, 56); diff --git a/src/processor/minidump_stackwalk.cc b/src/processor/minidump_stackwalk.cc index 2bd32d7a..e86fbdf6 100644 --- a/src/processor/minidump_stackwalk.cc +++ b/src/processor/minidump_stackwalk.cc @@ -206,10 +206,11 @@ static bool PrintMinidumpProcess(const string &minidump_file, } // Print OS and CPU information. - string cpu = process_state.cpu(); - string cpu_info = process_state.cpu_info(); - printf("Operating system: %s\n", process_state.os().c_str()); - printf(" %s\n", process_state.os_version().c_str()); + string cpu = process_state.system_info()->cpu; + string cpu_info = process_state.system_info()->cpu_info; + printf("Operating system: %s\n", process_state.system_info()->os.c_str()); + printf(" %s\n", + process_state.system_info()->os_version.c_str()); printf("CPU: %s\n", cpu.c_str()); if (!cpu_info.empty()) { // This field is optional. diff --git a/src/processor/process_state.cc b/src/processor/process_state.cc index d1e21cb8..3e90a79b 100644 --- a/src/processor/process_state.cc +++ b/src/processor/process_state.cc @@ -55,10 +55,7 @@ void ProcessState::Clear() { delete *iterator; } threads_.clear(); - os_.clear(); - os_version_.clear(); - cpu_.clear(); - cpu_info_.clear(); + system_info_.Clear(); delete modules_; modules_ = NULL; } diff --git a/src/processor/simple_symbol_supplier.cc b/src/processor/simple_symbol_supplier.cc index e2bd9184..fb16818d 100644 --- a/src/processor/simple_symbol_supplier.cc +++ b/src/processor/simple_symbol_supplier.cc @@ -37,12 +37,14 @@ #include "processor/simple_symbol_supplier.h" #include "google_airbag/processor/code_module.h" +#include "google_airbag/processor/system_info.h" #include "processor/pathname_stripper.h" namespace google_airbag { SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFileAtPath( - const CodeModule *module, const string &root_path, string *symbol_file) { + const CodeModule *module, const SystemInfo *system_info, + const string &root_path, string *symbol_file) { assert(symbol_file); if (!module) return NOT_FOUND; diff --git a/src/processor/simple_symbol_supplier.h b/src/processor/simple_symbol_supplier.h index 9995161e..6359da2a 100644 --- a/src/processor/simple_symbol_supplier.h +++ b/src/processor/simple_symbol_supplier.h @@ -94,12 +94,14 @@ class SimpleSymbolSupplier : public SymbolSupplier { // Returns the path to the symbol file for the given module. See the // description above. virtual SymbolResult GetSymbolFile(const CodeModule *module, + const SystemInfo *system_info, string *symbol_file) { - return GetSymbolFileAtPath(module, path_, symbol_file); + return GetSymbolFileAtPath(module, system_info, path_, symbol_file); } protected: SymbolResult GetSymbolFileAtPath(const CodeModule *module, + const SystemInfo *system_info, const string &root_path, string *symbol_file); diff --git a/src/processor/stackwalker.cc b/src/processor/stackwalker.cc index e6a26bb9..d9ca045b 100644 --- a/src/processor/stackwalker.cc +++ b/src/processor/stackwalker.cc @@ -53,10 +53,13 @@ namespace google_airbag { -Stackwalker::Stackwalker(MemoryRegion *memory, const CodeModules *modules, +Stackwalker::Stackwalker(const SystemInfo *system_info, + MemoryRegion *memory, + const CodeModules *modules, SymbolSupplier *supplier, SourceLineResolverInterface *resolver) - : memory_(memory), + : system_info_(system_info), + memory_(memory), modules_(modules), supplier_(supplier), resolver_(resolver) { @@ -96,7 +99,7 @@ bool Stackwalker::Walk(CallStack *stack) { supplier_) { string symbol_file; SymbolSupplier::SymbolResult symbol_result = - supplier_->GetSymbolFile(module, &symbol_file); + supplier_->GetSymbolFile(module, system_info_, &symbol_file); switch (symbol_result) { case SymbolSupplier::FOUND: @@ -130,6 +133,7 @@ bool Stackwalker::Walk(CallStack *stack) { // static Stackwalker* Stackwalker::StackwalkerForCPU( + const SystemInfo *system_info, MinidumpContext *context, MemoryRegion *memory, const CodeModules *modules, @@ -140,13 +144,15 @@ Stackwalker* Stackwalker::StackwalkerForCPU( u_int32_t cpu = context->GetContextCPU(); switch (cpu) { case MD_CONTEXT_X86: - cpu_stackwalker = new StackwalkerX86(context->GetContextX86(), + cpu_stackwalker = new StackwalkerX86(system_info, + context->GetContextX86(), memory, modules, supplier, resolver); break; case MD_CONTEXT_PPC: - cpu_stackwalker = new StackwalkerPPC(context->GetContextPPC(), + cpu_stackwalker = new StackwalkerPPC(system_info, + context->GetContextPPC(), memory, modules, supplier, resolver); break; diff --git a/src/processor/stackwalker_ppc.cc b/src/processor/stackwalker_ppc.cc index ff5243c6..5a8e6002 100644 --- a/src/processor/stackwalker_ppc.cc +++ b/src/processor/stackwalker_ppc.cc @@ -42,12 +42,13 @@ namespace google_airbag { -StackwalkerPPC::StackwalkerPPC(const MDRawContextPPC *context, +StackwalkerPPC::StackwalkerPPC(const SystemInfo *system_info, + const MDRawContextPPC *context, MemoryRegion *memory, const CodeModules *modules, SymbolSupplier *supplier, SourceLineResolverInterface *resolver) - : Stackwalker(memory, modules, supplier, resolver), + : Stackwalker(system_info, memory, modules, supplier, resolver), context_(context) { if (memory_->GetBase() + memory_->GetSize() - 1 > 0xffffffff) { // This implementation only covers 32-bit ppc CPUs. The limits of the diff --git a/src/processor/stackwalker_ppc.h b/src/processor/stackwalker_ppc.h index 9901f673..68b57f10 100644 --- a/src/processor/stackwalker_ppc.h +++ b/src/processor/stackwalker_ppc.h @@ -53,7 +53,8 @@ class StackwalkerPPC : public Stackwalker { // register state corresponding to the innermost called frame to be // included in the stack. The other arguments are passed directly through // to the base Stackwalker constructor. - StackwalkerPPC(const MDRawContextPPC *context, + StackwalkerPPC(const SystemInfo *system_info, + const MDRawContextPPC *context, MemoryRegion *memory, const CodeModules *modules, SymbolSupplier *supplier, diff --git a/src/processor/stackwalker_selftest.cc b/src/processor/stackwalker_selftest.cc index af76a8e8..d3b88a6b 100644 --- a/src/processor/stackwalker_selftest.cc +++ b/src/processor/stackwalker_selftest.cc @@ -227,15 +227,15 @@ static unsigned int CountCallerFrames() { context.ebp = GetEBP(); context.esp = GetESP(); - StackwalkerX86 stackwalker = StackwalkerX86(&context, &memory, NULL, NULL, - &resolver); + StackwalkerX86 stackwalker = StackwalkerX86(NULL, &context, &memory, NULL, + NULL, &resolver); #elif defined(__ppc__) MDRawContextPPC context = MDRawContextPPC(); context.srr0 = GetPC(); context.gpr[1] = GetSP(); - StackwalkerPPC stackwalker = StackwalkerPPC(&context, &memory, NULL, NULL, - &resolver); + StackwalkerPPC stackwalker = StackwalkerPPC(NULL, &context, &memory, NULL, + NULL, &resolver); #endif // __i386__ || __ppc__ CallStack stack; diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc index 0ee2fbd2..444746cd 100644 --- a/src/processor/stackwalker_x86.cc +++ b/src/processor/stackwalker_x86.cc @@ -46,12 +46,13 @@ namespace google_airbag { -StackwalkerX86::StackwalkerX86(const MDRawContextX86 *context, +StackwalkerX86::StackwalkerX86(const SystemInfo *system_info, + const MDRawContextX86 *context, MemoryRegion *memory, const CodeModules *modules, SymbolSupplier *supplier, SourceLineResolverInterface *resolver) - : Stackwalker(memory, modules, supplier, resolver), + : Stackwalker(system_info, memory, modules, supplier, resolver), context_(context) { if (memory_->GetBase() + memory_->GetSize() - 1 > 0xffffffff) { // The x86 is a 32-bit CPU, the limits of the supplied stack are invalid. diff --git a/src/processor/stackwalker_x86.h b/src/processor/stackwalker_x86.h index f53fc5f7..7f034c01 100644 --- a/src/processor/stackwalker_x86.h +++ b/src/processor/stackwalker_x86.h @@ -54,7 +54,8 @@ class StackwalkerX86 : public Stackwalker { // register state corresponding to the innermost called frame to be // included in the stack. The other arguments are passed directly through // to the base Stackwalker constructor. - StackwalkerX86(const MDRawContextX86 *context, + StackwalkerX86(const SystemInfo *system_info, + const MDRawContextX86 *context, MemoryRegion *memory, const CodeModules *modules, SymbolSupplier *supplier,