From cce3492afc263be86236600d41dca40be7224ee7 Mon Sep 17 00:00:00 2001 From: bryner Date: Tue, 19 Sep 2006 21:58:41 +0000 Subject: Get rid of CrashReport, and rename CrashReportProcessor to MinidumpProcessor (#26) r=mmentovai. git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@26 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/google/crash_report.h | 89 ----------------- src/google/crash_report_processor.h | 44 --------- src/google/minidump_processor.h | 46 +++++++++ src/google/symbol_supplier.h | 5 +- src/processor/crash_report_processor.cc | 64 ------------ src/processor/crash_report_processor_unittest.cc | 107 -------------------- src/processor/minidump_processor.cc | 64 ++++++++++++ src/processor/minidump_processor_unittest.cc | 118 +++++++++++++++++++++++ src/processor/stackwalker.cc | 7 +- src/processor/stackwalker.h | 9 +- src/processor/stackwalker_x86.cc | 4 +- src/processor/stackwalker_x86.h | 2 +- 12 files changed, 241 insertions(+), 318 deletions(-) delete mode 100644 src/google/crash_report.h delete mode 100644 src/google/crash_report_processor.h create mode 100644 src/google/minidump_processor.h delete mode 100644 src/processor/crash_report_processor.cc delete mode 100644 src/processor/crash_report_processor_unittest.cc create mode 100644 src/processor/minidump_processor.cc create mode 100644 src/processor/minidump_processor_unittest.cc (limited to 'src') diff --git a/src/google/crash_report.h b/src/google/crash_report.h deleted file mode 100644 index 22937538..00000000 --- a/src/google/crash_report.h +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (C) 2006 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// CrashReport encapsulates all of the information for a single report, -// including data sent with the report and data derived by the minidump -// processor (stack trace, etc.). - -#ifndef GOOGLE_CRASH_REPORT_H__ -#define GOOGLE_CRASH_REPORT_H__ - -#include -#include -#include "google/airbag_types.h" -#include "google/stack_frame.h" - -namespace google_airbag { - -using std::vector; -using std::string; - -struct CrashReport { - // An optional id for the report. This is supplied by the caller - // and is not used by airbag. - string report_id; - - // An optional id which identifies the client that generated the report. - string client_id; - - // The time that the report was uploaded (milliseconds since the epoch) - airbag_time_t report_time; - - // The uptime of the process before it crashed - airbag_time_t process_uptime; - - // The cumulative uptime of the application for this user - airbag_time_t cumulative_product_uptime; - - // The user's email address, if they provided it - string user_email; - - // Extra comments the user provided, e.g. steps to reproduce the crash - string user_comments; - - // The product which sent this report - struct Product { - string name; - string version; - }; - Product product; - - // The user's operating system - struct OS { - string name; - string version; - }; - OS os; - - // The user's CPU architecture (x86, PowerPC, x86_64, ...) - string cpu_arch; - - // Extra product-specific key/value pairs - struct ProductData { - string key; - string value; - }; - vector product_data; - - // The stack frames for the crashed thread, top-first.m - // TODO(bryner): accommodate multiple threads - StackFrames stack_frames; - - // The stack trace "signature", which can be used for matching up reports - string stack_signature; -}; - -} // namespace google_airbag - -#endif // GOOGLE_CRASH_REPORT_H__ diff --git a/src/google/crash_report_processor.h b/src/google/crash_report_processor.h deleted file mode 100644 index 161bc8cc..00000000 --- a/src/google/crash_report_processor.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (C) 2006 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef GOOGLE_CRASH_REPORT_PROCESSOR_H__ -#define GOOGLE_CRASH_REPORT_PROCESSOR_H__ - -#include - -namespace google_airbag { - -using std::string; - -struct CrashReport; -class SymbolSupplier; - -class CrashReportProcessor { - public: - // Initializes this CrashReportProcessor. supplier should be an - // implementation of the SymbolSupplier abstract base class. - CrashReportProcessor(SymbolSupplier *supplier); - ~CrashReportProcessor(); - - // Fills in the stack and other derived data for the CrashReport, - // using the supplied minidump file. Returns true on success. - bool ProcessReport(CrashReport *report, const string &minidump_file); - - private: - SymbolSupplier *supplier_; -}; - -} // namespace google_airbag - -#endif // GOOGLE_CRASH_REPORT_PROCESSOR_H__ diff --git a/src/google/minidump_processor.h b/src/google/minidump_processor.h new file mode 100644 index 00000000..9c80ee4e --- /dev/null +++ b/src/google/minidump_processor.h @@ -0,0 +1,46 @@ +// Copyright (C) 2006 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef GOOGLE_MINIDUMP_PROCESSOR_H__ +#define GOOGLE_MINIDUMP_PROCESSOR_H__ + +#include +#include "google/stack_frame.h" + +namespace google_airbag { + +using std::string; + +class SymbolSupplier; + +class MinidumpProcessor { + public: + // Initializes this MinidumpProcessor. supplier should be an + // implementation of the SymbolSupplier abstract base class. + MinidumpProcessor(SymbolSupplier *supplier); + ~MinidumpProcessor(); + + // Fills in the given StackFrames vector by processing the minidump file. + // supplier_data is an opaque pointer which is passed to + // SymbolSupplier::GetSymbolFile(). Returns true on success. + bool Process(const string &minidump_file, void *supplier_data, + StackFrames *stack_frames); + + private: + SymbolSupplier *supplier_; +}; + +} // namespace google_airbag + +#endif // GOOGLE_MINIDUMP_PROCESSOR_H__ diff --git a/src/google/symbol_supplier.h b/src/google/symbol_supplier.h index 279e99f2..f0a6e39c 100644 --- a/src/google/symbol_supplier.h +++ b/src/google/symbol_supplier.h @@ -24,16 +24,15 @@ namespace google_airbag { using std::string; class MinidumpModule; -struct CrashReport; class SymbolSupplier { public: virtual ~SymbolSupplier() {} // Returns the path to the symbol file for the given module. - // report will be the pointer supplied to ProcessReport(). + // supplier_data is passed through from MinidumpProcessor::Process(). virtual string GetSymbolFile(MinidumpModule *module, - const CrashReport *report) = 0; + void *supplier_data) = 0; }; } // namespace google_airbag diff --git a/src/processor/crash_report_processor.cc b/src/processor/crash_report_processor.cc deleted file mode 100644 index 672ca7f0..00000000 --- a/src/processor/crash_report_processor.cc +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (C) 2006 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "google/crash_report.h" -#include "google/crash_report_processor.h" -#include "processor/minidump.h" -#include "processor/stackwalker_x86.h" - -namespace google_airbag { - -CrashReportProcessor::CrashReportProcessor(SymbolSupplier *supplier) - : supplier_(supplier) { -} - -CrashReportProcessor::~CrashReportProcessor() { -} - -bool CrashReportProcessor::ProcessReport(CrashReport *report, - const string &minidump_file) { - Minidump dump(minidump_file); - if (!dump.Read()) { - return false; - } - - MinidumpException *exception = dump.GetException(); - if (!exception) { - return false; - } - - MinidumpThreadList *threads = dump.GetThreadList(); - if (!threads) { - return false; - } - - // TODO(bryner): get all the threads - MinidumpThread *thread = threads->GetThreadByID(exception->GetThreadID()); - if (!thread) { - return false; - } - - MinidumpMemoryRegion *thread_memory = thread->GetMemory(); - if (!thread_memory) { - return false; - } - - // TODO(bryner): figure out which StackWalker we want - StackwalkerX86 walker(exception->GetContext(), thread_memory, - dump.GetModuleList(), supplier_, report); - walker.Walk(&report->stack_frames); - return true; -} - -} // namespace google_airbag diff --git a/src/processor/crash_report_processor_unittest.cc b/src/processor/crash_report_processor_unittest.cc deleted file mode 100644 index 66694a21..00000000 --- a/src/processor/crash_report_processor_unittest.cc +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (C) 2006 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Unit test for CrashReporter. Uses a pre-generated minidump and -// corresponding symbol file, and checks the contents of the CrashReport. - -#include -#include "google/crash_report.h" -#include "google/crash_report_processor.h" -#include "google/symbol_supplier.h" -#include "processor/minidump.h" - -using std::string; -using google_airbag::CrashReportProcessor; -using google_airbag::CrashReport; - -#define ASSERT_TRUE(cond) \ - if (!(cond)) { \ - fprintf(stderr, "FAILED: %s at %s:%d\n", #cond, __FILE__, __LINE__); \ - return false; \ - } - -#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2)) - -namespace google_airbag { - -class TestSymbolSupplier : public SymbolSupplier { - public: - virtual string GetSymbolFile(MinidumpModule *module, - const CrashReport *report); -}; - -string TestSymbolSupplier::GetSymbolFile(MinidumpModule *module, - const CrashReport *report) { - if (*(module->GetName()) == "c:\\test_app.exe") { - return string(getenv("srcdir") ? getenv("srcdir") : ".") + - "/src/processor/testdata/minidump2.sym"; - } - - return ""; -} - -} // namespace google_airbag - -using google_airbag::TestSymbolSupplier; - -static bool RunTests() { - - TestSymbolSupplier supplier; - CrashReportProcessor processor(&supplier); - - CrashReport report; - string minidump_file = string(getenv("srcdir") ? getenv("srcdir") : ".") + - "/src/processor/testdata/minidump2.dmp"; - - ASSERT_TRUE(processor.ProcessReport(&report, minidump_file)); - ASSERT_EQ(report.stack_frames.size(), 4); - - ASSERT_EQ(report.stack_frames[0].module_base, 0x400000); - ASSERT_EQ(report.stack_frames[0].module_name, "c:\\test_app.exe"); - ASSERT_EQ(report.stack_frames[0].function_name, "CrashFunction"); - ASSERT_EQ(report.stack_frames[0].source_file_name, "c:\\test_app.cc"); - ASSERT_EQ(report.stack_frames[0].source_line, 36); - - ASSERT_EQ(report.stack_frames[1].module_base, 0x400000); - ASSERT_EQ(report.stack_frames[1].module_name, "c:\\test_app.exe"); - ASSERT_EQ(report.stack_frames[1].function_name, "main"); - ASSERT_EQ(report.stack_frames[1].source_file_name, "c:\\test_app.cc"); - ASSERT_EQ(report.stack_frames[1].source_line, 42); - - // This comes from the CRT - ASSERT_EQ(report.stack_frames[2].module_base, 0x400000); - ASSERT_EQ(report.stack_frames[2].module_name, "c:\\test_app.exe"); - ASSERT_EQ(report.stack_frames[2].function_name, "__tmainCRTStartup"); - ASSERT_EQ(report.stack_frames[2].source_file_name, - "f:\\rtm\\vctools\\crt_bld\\self_x86\\crt\\src\\crt0.c"); - ASSERT_EQ(report.stack_frames[2].source_line, 318); - - // No debug info available for kernel32.dll - ASSERT_EQ(report.stack_frames[3].module_base, 0x7c800000); - ASSERT_EQ(report.stack_frames[3].module_name, - "C:\\WINDOWS\\system32\\kernel32.dll"); - ASSERT_TRUE(report.stack_frames[3].function_name.empty()); - ASSERT_TRUE(report.stack_frames[3].source_file_name.empty()); - ASSERT_EQ(report.stack_frames[3].source_line, 0); - - return true; -} - -int main(int argc, char *argv[]) { - if (!RunTests()) { - return 1; - } - - return 0; -} diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc new file mode 100644 index 00000000..74e478a6 --- /dev/null +++ b/src/processor/minidump_processor.cc @@ -0,0 +1,64 @@ +// Copyright (C) 2006 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "google/minidump_processor.h" +#include "processor/minidump.h" +#include "processor/stackwalker_x86.h" + +namespace google_airbag { + +MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier) + : supplier_(supplier) { +} + +MinidumpProcessor::~MinidumpProcessor() { +} + +bool MinidumpProcessor::Process(const string &minidump_file, + void *supplier_data, + StackFrames *stack_frames) { + Minidump dump(minidump_file); + if (!dump.Read()) { + return false; + } + + MinidumpException *exception = dump.GetException(); + if (!exception) { + return false; + } + + MinidumpThreadList *threads = dump.GetThreadList(); + if (!threads) { + return false; + } + + // TODO(bryner): get all the threads + MinidumpThread *thread = threads->GetThreadByID(exception->GetThreadID()); + if (!thread) { + return false; + } + + MinidumpMemoryRegion *thread_memory = thread->GetMemory(); + if (!thread_memory) { + return false; + } + + // TODO(bryner): figure out which StackWalker we want + StackwalkerX86 walker(exception->GetContext(), thread_memory, + dump.GetModuleList(), supplier_, supplier_data); + walker.Walk(stack_frames); + return true; +} + +} // namespace google_airbag diff --git a/src/processor/minidump_processor_unittest.cc b/src/processor/minidump_processor_unittest.cc new file mode 100644 index 00000000..b73469b5 --- /dev/null +++ b/src/processor/minidump_processor_unittest.cc @@ -0,0 +1,118 @@ +// Copyright (C) 2006 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Unit test for MinidumpProcessor. Uses a pre-generated minidump and +// corresponding symbol file, and checks the stack frames for correctness. + +#include +#include "google/minidump_processor.h" +#include "google/symbol_supplier.h" +#include "processor/minidump.h" + +using std::string; +using google_airbag::MinidumpProcessor; +using google_airbag::StackFrames; + +#define ASSERT_TRUE(cond) \ + if (!(cond)) { \ + fprintf(stderr, "FAILED: %s at %s:%d\n", #cond, __FILE__, __LINE__); \ + return false; \ + } + +#define ASSERT_EQ(e1, e2) ASSERT_TRUE((e1) == (e2)) + +namespace google_airbag { + +class TestSymbolSupplier : public SymbolSupplier { + public: + TestSymbolSupplier() : has_supplier_data_(false) {} + virtual ~TestSymbolSupplier() {} + + virtual string GetSymbolFile(MinidumpModule *module, void *supplier_data); + + // This member is used to test the data argument to GetSymbolFile. + // If the argument is correct, it's set to true. + bool has_supplier_data_; +}; + +string TestSymbolSupplier::GetSymbolFile(MinidumpModule *module, + void *supplier_data) { + if (supplier_data == &has_supplier_data_) { + has_supplier_data_ = true; + } + + if (*(module->GetName()) == "c:\\test_app.exe") { + return string(getenv("srcdir") ? getenv("srcdir") : ".") + + "/src/processor/testdata/minidump2.sym"; + } + + return ""; +} + +} // namespace google_airbag + +using google_airbag::TestSymbolSupplier; + +static bool RunTests() { + + TestSymbolSupplier supplier; + MinidumpProcessor processor(&supplier); + + StackFrames stack_frames; + string minidump_file = string(getenv("srcdir") ? getenv("srcdir") : ".") + + "/src/processor/testdata/minidump2.dmp"; + + ASSERT_TRUE(processor.Process(minidump_file, + &supplier.has_supplier_data_, &stack_frames)); + ASSERT_TRUE(supplier.has_supplier_data_); + ASSERT_EQ(stack_frames.size(), 4); + + ASSERT_EQ(stack_frames[0].module_base, 0x400000); + ASSERT_EQ(stack_frames[0].module_name, "c:\\test_app.exe"); + ASSERT_EQ(stack_frames[0].function_name, "CrashFunction"); + ASSERT_EQ(stack_frames[0].source_file_name, "c:\\test_app.cc"); + ASSERT_EQ(stack_frames[0].source_line, 36); + + ASSERT_EQ(stack_frames[1].module_base, 0x400000); + ASSERT_EQ(stack_frames[1].module_name, "c:\\test_app.exe"); + ASSERT_EQ(stack_frames[1].function_name, "main"); + ASSERT_EQ(stack_frames[1].source_file_name, "c:\\test_app.cc"); + ASSERT_EQ(stack_frames[1].source_line, 42); + + // This comes from the CRT + ASSERT_EQ(stack_frames[2].module_base, 0x400000); + ASSERT_EQ(stack_frames[2].module_name, "c:\\test_app.exe"); + ASSERT_EQ(stack_frames[2].function_name, "__tmainCRTStartup"); + ASSERT_EQ(stack_frames[2].source_file_name, + "f:\\rtm\\vctools\\crt_bld\\self_x86\\crt\\src\\crt0.c"); + ASSERT_EQ(stack_frames[2].source_line, 318); + + // No debug info available for kernel32.dll + ASSERT_EQ(stack_frames[3].module_base, 0x7c800000); + ASSERT_EQ(stack_frames[3].module_name, + "C:\\WINDOWS\\system32\\kernel32.dll"); + ASSERT_TRUE(stack_frames[3].function_name.empty()); + ASSERT_TRUE(stack_frames[3].source_file_name.empty()); + ASSERT_EQ(stack_frames[3].source_line, 0); + + return true; +} + +int main(int argc, char *argv[]) { + if (!RunTests()) { + return 1; + } + + return 0; +} diff --git a/src/processor/stackwalker.cc b/src/processor/stackwalker.cc index 0103e850..62386b83 100644 --- a/src/processor/stackwalker.cc +++ b/src/processor/stackwalker.cc @@ -34,11 +34,11 @@ using std::auto_ptr; Stackwalker::Stackwalker(MemoryRegion* memory, MinidumpModuleList* modules, - SymbolSupplier *supplier, const CrashReport *report) + SymbolSupplier* supplier, void* supplier_data) : memory_(memory), modules_(modules), supplier_(supplier), - report_(report) { + supplier_data_(supplier_data) { } @@ -64,7 +64,8 @@ void Stackwalker::Walk(StackFrames *frames) { frame->module_name = *(module->GetName()); frame->module_base = module->base_address(); if (modules_ && supplier_) { - string symbol_file = supplier_->GetSymbolFile(module, report_); + string symbol_file = + supplier_->GetSymbolFile(module, supplier_data_); if (!symbol_file.empty()) { resolver.LoadModule(*(module->GetName()), symbol_file); resolver.FillSourceLineInfo(frame.get()); diff --git a/src/processor/stackwalker.h b/src/processor/stackwalker.h index 07a78ca2..bfcb783a 100644 --- a/src/processor/stackwalker.h +++ b/src/processor/stackwalker.h @@ -37,7 +37,6 @@ namespace google_airbag { class MinidumpModuleList; class SymbolSupplier; -struct CrashReport; class Stackwalker { @@ -55,12 +54,12 @@ class Stackwalker { // that is used to look up which code module each stack frame is // associated with. supplier is an optional caller-supplied SymbolSupplier // implementation. If supplier is NULL, source line info will not be - // resolved. The CrashReport object will be passed to the SymbolSupplier's + // resolved. supplier_data will be passed to the SymbolSupplier's // GetSymbolFile method. Stackwalker(MemoryRegion* memory, MinidumpModuleList* modules, SymbolSupplier* supplier, - const CrashReport* report); + void* supplier_data); // The stack memory to walk. Subclasses will require this region to // get information from the stack. @@ -85,8 +84,8 @@ class Stackwalker { // The optional SymbolSupplier for resolving source line info. SymbolSupplier* supplier_; - // The CrashReport object which is passed to the SymbolSupplier. May be null. - const CrashReport* report_; + // Caller-supplied data to be passed to the symbol supplier + void* supplier_data_; }; diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc index b7adfaf9..654cb17e 100644 --- a/src/processor/stackwalker_x86.cc +++ b/src/processor/stackwalker_x86.cc @@ -30,8 +30,8 @@ StackwalkerX86::StackwalkerX86(MinidumpContext* context, MemoryRegion* memory, MinidumpModuleList* modules, SymbolSupplier* supplier, - const CrashReport* report) - : Stackwalker(memory, modules, supplier, report), + void* supplier_data) + : Stackwalker(memory, modules, supplier, supplier_data), last_frame_pointer_(0) { 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 8f175004..34be57eb 100644 --- a/src/processor/stackwalker_x86.h +++ b/src/processor/stackwalker_x86.h @@ -46,7 +46,7 @@ class StackwalkerX86 : public Stackwalker { MemoryRegion* memory, MinidumpModuleList* modules, SymbolSupplier* supplier, - const CrashReport* report); + void* supplier_data); private: // Implementation of Stackwalker, using x86 context (%ebp, %eip) and -- cgit v1.2.1