diff options
Diffstat (limited to 'src/processor/minidump_processor_unittest.cc')
-rw-r--r-- | src/processor/minidump_processor_unittest.cc | 209 |
1 files changed, 192 insertions, 17 deletions
diff --git a/src/processor/minidump_processor_unittest.cc b/src/processor/minidump_processor_unittest.cc index a8e1208e..db96efb7 100644 --- a/src/processor/minidump_processor_unittest.cc +++ b/src/processor/minidump_processor_unittest.cc @@ -51,6 +51,7 @@ #include "google_breakpad/processor/symbol_supplier.h" #include "processor/logging.h" #include "processor/scoped_ptr.h" +#include "processor/stackwalker_unittest_utils.h" using std::map; @@ -64,27 +65,86 @@ class MockMinidump : public Minidump { MOCK_CONST_METHOD0(path, string()); MOCK_CONST_METHOD0(header, const MDRawHeader*()); MOCK_METHOD0(GetThreadList, MinidumpThreadList*()); + MOCK_METHOD0(GetSystemInfo, MinidumpSystemInfo*()); + MOCK_METHOD0(GetBreakpadInfo, MinidumpBreakpadInfo*()); + MOCK_METHOD0(GetException, MinidumpException*()); + MOCK_METHOD0(GetAssertion, MinidumpAssertion*()); + MOCK_METHOD0(GetModuleList, MinidumpModuleList*()); }; -} + +class MockMinidumpThreadList : public MinidumpThreadList { + public: + MockMinidumpThreadList() : MinidumpThreadList(NULL) {} + + MOCK_CONST_METHOD0(thread_count, unsigned int()); + MOCK_CONST_METHOD1(GetThreadAtIndex, MinidumpThread*(unsigned int)); +}; + +class MockMinidumpThread : public MinidumpThread { + public: + MockMinidumpThread() : MinidumpThread(NULL) {} + + MOCK_CONST_METHOD1(GetThreadID, bool(u_int32_t*)); + MOCK_METHOD0(GetContext, MinidumpContext*()); + MOCK_METHOD0(GetMemory, MinidumpMemoryRegion*()); +}; + +// This is crappy, but MinidumpProcessor really does want a +// MinidumpMemoryRegion. +class MockMinidumpMemoryRegion : public MinidumpMemoryRegion { + public: + MockMinidumpMemoryRegion(u_int64_t base, const string& contents) : + MinidumpMemoryRegion(NULL) { + region_.Init(base, contents); + } + + u_int64_t GetBase() const { return region_.GetBase(); } + u_int32_t GetSize() const { return region_.GetSize(); } + + bool GetMemoryAtAddress(u_int64_t address, u_int8_t *value) const { + return region_.GetMemoryAtAddress(address, value); + } + bool GetMemoryAtAddress(u_int64_t address, u_int16_t *value) const { + return region_.GetMemoryAtAddress(address, value); + } + bool GetMemoryAtAddress(u_int64_t address, u_int32_t *value) const { + return region_.GetMemoryAtAddress(address, value); + } + bool GetMemoryAtAddress(u_int64_t address, u_int64_t *value) const { + return region_.GetMemoryAtAddress(address, value); + } + + MockMemoryRegion region_; +}; + +} // namespace google_breakpad namespace { using google_breakpad::BasicSourceLineResolver; using google_breakpad::CallStack; using google_breakpad::CodeModule; +using google_breakpad::MinidumpContext; +using google_breakpad::MinidumpMemoryRegion; using google_breakpad::MinidumpProcessor; +using google_breakpad::MinidumpSystemInfo; using google_breakpad::MinidumpThreadList; using google_breakpad::MinidumpThread; using google_breakpad::MockMinidump; +using google_breakpad::MockMinidumpMemoryRegion; +using google_breakpad::MockMinidumpThread; +using google_breakpad::MockMinidumpThreadList; using google_breakpad::ProcessState; using google_breakpad::scoped_ptr; using google_breakpad::SymbolSupplier; using google_breakpad::SystemInfo; using ::testing::_; +using ::testing::DoAll; using ::testing::Mock; using ::testing::Ne; using ::testing::Property; using ::testing::Return; +using ::testing::SetArgumentPointee; static const char *kSystemInfoOS = "Windows NT"; static const char *kSystemInfoOSShort = "windows"; @@ -206,23 +266,27 @@ void TestSymbolSupplier::FreeSymbolData(const CodeModule *module) { } } -// A mock symbol supplier that always returns NOT_FOUND; one current -// use for testing the processor's caching of symbol lookups. -class MockSymbolSupplier : public SymbolSupplier { +// A test system info stream, just returns values from the +// MDRawSystemInfo fed to it. +class TestMinidumpSystemInfo : public MinidumpSystemInfo { public: - MockSymbolSupplier() { } - MOCK_METHOD3(GetSymbolFile, SymbolResult(const CodeModule*, - const SystemInfo*, - string*)); - MOCK_METHOD4(GetSymbolFile, SymbolResult(const CodeModule*, - const SystemInfo*, - string*, - string*)); - MOCK_METHOD4(GetCStringSymbolData, SymbolResult(const CodeModule*, - const SystemInfo*, - string*, - char**)); - MOCK_METHOD1(FreeSymbolData, void(const CodeModule*)); + TestMinidumpSystemInfo(MDRawSystemInfo info) : + MinidumpSystemInfo(NULL) { + valid_ = true; + system_info_ = info; + csd_version_ = new string(""); + } +}; + +// A test minidump context, just returns the MDRawContextX86 +// fed to it. +class TestMinidumpContext : public MinidumpContext { +public: + TestMinidumpContext(const MDRawContextX86& context) : MinidumpContext(NULL) { + valid_ = true; + context_.x86 = new MDRawContextX86(context); + context_flags_ = MD_CONTEXT_X86; + } }; class MinidumpProcessorTest : public ::testing::Test { @@ -245,11 +309,15 @@ TEST_F(MinidumpProcessorTest, TestCorruptMinidumps) { fakeHeader.time_date_stamp = 0; EXPECT_CALL(dump, header()).WillOnce(Return((MDRawHeader*)NULL)). WillRepeatedly(Return(&fakeHeader)); + EXPECT_EQ(processor.Process(&dump, &state), google_breakpad::PROCESS_ERROR_NO_MINIDUMP_HEADER); EXPECT_CALL(dump, GetThreadList()). WillOnce(Return((MinidumpThreadList*)NULL)); + EXPECT_CALL(dump, GetSystemInfo()). + WillRepeatedly(Return((MinidumpSystemInfo*)NULL)); + EXPECT_EQ(processor.Process(&dump, &state), google_breakpad::PROCESS_ERROR_NO_THREAD_LIST); } @@ -372,6 +440,113 @@ TEST_F(MinidumpProcessorTest, TestBasicProcessing) { ASSERT_EQ(processor.Process(minidump_file, &state), google_breakpad::PROCESS_SYMBOL_SUPPLIER_INTERRUPTED); } + +TEST_F(MinidumpProcessorTest, TestThreadMissingMemory) { + MockMinidump dump; + EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); + EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); + + MDRawHeader fake_header; + fake_header.time_date_stamp = 0; + EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header)); + + MDRawSystemInfo raw_system_info; + memset(&raw_system_info, 0, sizeof(raw_system_info)); + raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86; + raw_system_info.platform_id = MD_OS_WIN32_NT; + TestMinidumpSystemInfo dump_system_info(raw_system_info); + + EXPECT_CALL(dump, GetSystemInfo()). + WillRepeatedly(Return(&dump_system_info)); + + MockMinidumpThreadList thread_list; + EXPECT_CALL(dump, GetThreadList()). + WillOnce(Return(&thread_list)); + + // Return a thread missing stack memory. + MockMinidumpThread no_memory_thread; + EXPECT_CALL(no_memory_thread, GetThreadID(_)). + WillRepeatedly(DoAll(SetArgumentPointee<0>(1), + Return(true))); + EXPECT_CALL(no_memory_thread, GetMemory()). + WillRepeatedly(Return((MinidumpMemoryRegion*)NULL)); + + MDRawContextX86 no_memory_thread_raw_context; + memset(&no_memory_thread_raw_context, 0, + sizeof(no_memory_thread_raw_context)); + no_memory_thread_raw_context.context_flags = MD_CONTEXT_X86_FULL; + const u_int32_t kExpectedEIP = 0xabcd1234; + no_memory_thread_raw_context.eip = kExpectedEIP; + TestMinidumpContext no_memory_thread_context(no_memory_thread_raw_context); + EXPECT_CALL(no_memory_thread, GetContext()). + WillRepeatedly(Return(&no_memory_thread_context)); + + EXPECT_CALL(thread_list, thread_count()). + WillRepeatedly(Return(1)); + EXPECT_CALL(thread_list, GetThreadAtIndex(0)). + WillOnce(Return(&no_memory_thread)); + + MinidumpProcessor processor((SymbolSupplier*)NULL, NULL); + ProcessState state; + EXPECT_EQ(processor.Process(&dump, &state), + google_breakpad::PROCESS_OK); + + // Should have a single thread with a single frame in it. + ASSERT_EQ(1, state.threads()->size()); + ASSERT_EQ(1, state.threads()->at(0)->frames()->size()); + ASSERT_EQ(kExpectedEIP, state.threads()->at(0)->frames()->at(0)->instruction); +} + +TEST_F(MinidumpProcessorTest, TestThreadMissingContext) { + MockMinidump dump; + EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); + EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); + + MDRawHeader fake_header; + fake_header.time_date_stamp = 0; + EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header)); + + MDRawSystemInfo raw_system_info; + memset(&raw_system_info, 0, sizeof(raw_system_info)); + raw_system_info.processor_architecture = MD_CPU_ARCHITECTURE_X86; + raw_system_info.platform_id = MD_OS_WIN32_NT; + TestMinidumpSystemInfo dump_system_info(raw_system_info); + + EXPECT_CALL(dump, GetSystemInfo()). + WillRepeatedly(Return(&dump_system_info)); + + MockMinidumpThreadList thread_list; + EXPECT_CALL(dump, GetThreadList()). + WillOnce(Return(&thread_list)); + + // Return a thread missing a thread context. + MockMinidumpThread no_context_thread; + EXPECT_CALL(no_context_thread, GetThreadID(_)). + WillRepeatedly(DoAll(SetArgumentPointee<0>(1), + Return(true))); + EXPECT_CALL(no_context_thread, GetContext()). + WillRepeatedly(Return((MinidumpContext*)NULL)); + + // The memory contents don't really matter here, since it won't be used. + MockMinidumpMemoryRegion no_context_thread_memory(0x1234, "xxx"); + EXPECT_CALL(no_context_thread, GetMemory()). + WillRepeatedly(Return(&no_context_thread_memory)); + + EXPECT_CALL(thread_list, thread_count()). + WillRepeatedly(Return(1)); + EXPECT_CALL(thread_list, GetThreadAtIndex(0)). + WillOnce(Return(&no_context_thread)); + + MinidumpProcessor processor((SymbolSupplier*)NULL, NULL); + ProcessState state; + EXPECT_EQ(processor.Process(&dump, &state), + google_breakpad::PROCESS_OK); + + // Should have a single thread with zero frames. + ASSERT_EQ(1, state.threads()->size()); + ASSERT_EQ(0, state.threads()->at(0)->frames()->size()); +} + } // namespace int main(int argc, char *argv[]) { |