Populate stack frames with unloaded module info.

This CL hits lots of source files because:
 1. An update to the CodeModule virtual class. I added an is_loaded
  method to specify whether the module is loaded. There were several
  mocks/test classes that needed to be updated with an implementation.
  An alternative to this route would be to modify
  MinidumpUnloadedModule::code_file to prepend "Unloaded_" to the
  module name.

 2. Added an unloaded_modules parameter to
  StackFrameSymbolizer::FillSourceLineInfo.

BUG=

Change-Id: Ic9c7f7c7b7e932a154a5d4ccf292c1527d8da09f
Reviewed-on: https://chromium-review.googlesource.com/430241
Reviewed-by: Ivan Penkov <ivanpe@chromium.org>
This commit is contained in:
Joshua Peraza 2017-01-19 11:18:41 -08:00
parent e7dfafc16e
commit 0924d424e4
15 changed files with 161 additions and 13 deletions

View file

@ -71,9 +71,24 @@ class MockMinidump : public Minidump {
MOCK_METHOD0(GetException, MinidumpException*());
MOCK_METHOD0(GetAssertion, MinidumpAssertion*());
MOCK_METHOD0(GetModuleList, MinidumpModuleList*());
MOCK_METHOD0(GetUnloadedModuleList, MinidumpUnloadedModuleList*());
MOCK_METHOD0(GetMemoryList, MinidumpMemoryList*());
};
class MockMinidumpUnloadedModule : public MinidumpUnloadedModule {
public:
MockMinidumpUnloadedModule() : MinidumpUnloadedModule(NULL) {}
};
class MockMinidumpUnloadedModuleList : public MinidumpUnloadedModuleList {
public:
MockMinidumpUnloadedModuleList() : MinidumpUnloadedModuleList(NULL) {}
MOCK_CONST_METHOD0(Copy, CodeModules*());
MOCK_CONST_METHOD1(GetModuleForAddress,
const MinidumpUnloadedModule*(uint64_t));
};
class MockMinidumpThreadList : public MinidumpThreadList {
public:
MockMinidumpThreadList() : MinidumpThreadList(NULL) {}
@ -157,6 +172,8 @@ using google_breakpad::MockMinidumpMemoryList;
using google_breakpad::MockMinidumpMemoryRegion;
using google_breakpad::MockMinidumpThread;
using google_breakpad::MockMinidumpThreadList;
using google_breakpad::MockMinidumpUnloadedModule;
using google_breakpad::MockMinidumpUnloadedModuleList;
using google_breakpad::ProcessState;
using google_breakpad::scoped_ptr;
using google_breakpad::SymbolSupplier;
@ -320,6 +337,88 @@ class TestMinidumpContext : public MinidumpContext {
class MinidumpProcessorTest : public ::testing::Test {
};
TEST_F(MinidumpProcessorTest, TestUnloadedModules) {
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));
// No loaded modules
MockMinidumpUnloadedModuleList unloaded_module_list;
EXPECT_CALL(dump, GetUnloadedModuleList()).
WillOnce(Return(&unloaded_module_list));
MockMinidumpMemoryList memory_list;
EXPECT_CALL(dump, GetMemoryList()).
WillOnce(Return(&memory_list));
MockMinidumpThreadList thread_list;
EXPECT_CALL(dump, GetThreadList()).
WillOnce(Return(&thread_list));
EXPECT_CALL(thread_list, thread_count()).
WillRepeatedly(Return(1));
MockMinidumpThread thread;
EXPECT_CALL(thread_list, GetThreadAtIndex(0)).
WillOnce(Return(&thread));
EXPECT_CALL(thread, GetThreadID(_)).
WillRepeatedly(DoAll(SetArgumentPointee<0>(1),
Return(true)));
MDRawContextX86 thread_raw_context;
memset(&thread_raw_context, 0,
sizeof(thread_raw_context));
thread_raw_context.context_flags = MD_CONTEXT_X86_FULL;
const uint32_t kExpectedEIP = 0xabcd1234;
thread_raw_context.eip = kExpectedEIP;
TestMinidumpContext thread_context(thread_raw_context);
EXPECT_CALL(thread, GetContext()).
WillRepeatedly(Return(&thread_context));
// The memory contents don't really matter here, since it won't be used.
MockMinidumpMemoryRegion thread_memory(0x1234, "xxx");
EXPECT_CALL(thread, GetMemory()).
WillRepeatedly(Return(&thread_memory));
EXPECT_CALL(thread, GetStartOfStackMemoryRange()).
Times(0);
EXPECT_CALL(memory_list, GetMemoryRegionForAddress(_)).
Times(0);
EXPECT_CALL(unloaded_module_list, Copy()).
WillOnce(Return(&unloaded_module_list));
MockMinidumpUnloadedModule unloaded_module;
EXPECT_CALL(unloaded_module_list, GetModuleForAddress(kExpectedEIP)).
WillOnce(Return(&unloaded_module));
MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL);
ProcessState state;
EXPECT_EQ(processor.Process(&dump, &state),
google_breakpad::PROCESS_OK);
// The single frame should be populated with the unloaded module.
ASSERT_EQ(1U, state.threads()->size());
ASSERT_EQ(1U, state.threads()->at(0)->frames()->size());
ASSERT_EQ(kExpectedEIP, state.threads()->at(0)->frames()->at(0)->instruction);
ASSERT_EQ(&unloaded_module, state.threads()->at(0)->frames()->at(0)->module);
}
TEST_F(MinidumpProcessorTest, TestCorruptMinidumps) {
MockMinidump dump;
TestSymbolSupplier supplier;