diff options
-rw-r--r-- | src/google_breakpad/processor/minidump.h | 13 | ||||
-rw-r--r-- | src/google_breakpad/processor/minidump_processor.h | 6 | ||||
-rw-r--r-- | src/google_breakpad/processor/process_state.h | 4 | ||||
-rw-r--r-- | src/processor/minidump_processor.cc | 46 | ||||
-rw-r--r-- | src/processor/minidump_processor_unittest.cc | 49 | ||||
-rw-r--r-- | src/processor/process_state.cc | 1 | ||||
-rw-r--r-- | src/processor/proto/process_state.proto | 5 | ||||
-rw-r--r-- | src/processor/stackwalk_common.cc | 12 | ||||
-rw-r--r-- | src/processor/testdata/microdump.stackwalk.out | 1 | ||||
-rw-r--r-- | src/processor/testdata/minidump2.stackwalk.out | 1 |
10 files changed, 123 insertions, 15 deletions
diff --git a/src/google_breakpad/processor/minidump.h b/src/google_breakpad/processor/minidump.h index 34e28312..51f15025 100644 --- a/src/google_breakpad/processor/minidump.h +++ b/src/google_breakpad/processor/minidump.h @@ -732,6 +732,7 @@ class MinidumpMiscInfo : public MinidumpStream { private: friend class Minidump; + friend class TestMinidumpMiscInfo; static const uint32_t kStreamType = MD_MISC_INFO_STREAM; @@ -902,14 +903,14 @@ class Minidump { // to avoid exposing an ugly API (GetStream needs to accept a garbage // parameter). virtual MinidumpThreadList* GetThreadList(); - MinidumpModuleList* GetModuleList(); + virtual MinidumpModuleList* GetModuleList(); virtual MinidumpMemoryList* GetMemoryList(); - MinidumpException* GetException(); - MinidumpAssertion* GetAssertion(); + virtual MinidumpException* GetException(); + virtual MinidumpAssertion* GetAssertion(); virtual MinidumpSystemInfo* GetSystemInfo(); - MinidumpMiscInfo* GetMiscInfo(); - MinidumpBreakpadInfo* GetBreakpadInfo(); - MinidumpMemoryInfoList* GetMemoryInfoList(); + virtual MinidumpMiscInfo* GetMiscInfo(); + virtual MinidumpBreakpadInfo* GetBreakpadInfo(); + virtual MinidumpMemoryInfoList* GetMemoryInfoList(); // The next set of methods are provided for users who wish to access // data in minidump files directly, while leveraging the rest of diff --git a/src/google_breakpad/processor/minidump_processor.h b/src/google_breakpad/processor/minidump_processor.h index 20277f9a..d2c94e2b 100644 --- a/src/google_breakpad/processor/minidump_processor.h +++ b/src/google_breakpad/processor/minidump_processor.h @@ -89,6 +89,12 @@ class MinidumpProcessor { // the minidump. static bool GetOSInfo(Minidump* dump, SystemInfo* info); + // Populates the |process_create_time| parameter with the create time of the + // crashed process. Returns false if this information is not available in + // the minidump |dump|. + static bool GetProcessCreateTime(Minidump* dump, + uint32_t* process_create_time); + // 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 diff --git a/src/google_breakpad/processor/process_state.h b/src/google_breakpad/processor/process_state.h index a33b2123..ac3b6039 100644 --- a/src/google_breakpad/processor/process_state.h +++ b/src/google_breakpad/processor/process_state.h @@ -97,6 +97,7 @@ class ProcessState { // Accessors. See the data declarations below. uint32_t time_date_stamp() const { return time_date_stamp_; } + uint32_t process_create_time() const { return process_create_time_; } bool crashed() const { return crashed_; } string crash_reason() const { return crash_reason_; } uint64_t crash_address() const { return crash_address_; } @@ -125,6 +126,9 @@ class ProcessState { // The time-date stamp of the minidump (time_t format) uint32_t time_date_stamp_; + // The time-date stamp when the process was created (time_t format) + uint32_t process_create_time_; + // True if the process crashed, false if the dump was produced outside // of an exception handler. bool crashed_; diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc index 84c5889b..0c0a1e9d 100644 --- a/src/processor/minidump_processor.cc +++ b/src/processor/minidump_processor.cc @@ -87,6 +87,9 @@ ProcessResult MinidumpProcessor::Process( } process_state->time_date_stamp_ = header->time_date_stamp; + bool has_process_create_time = + GetProcessCreateTime(dump, &process_state->process_create_time_); + bool has_cpu_info = GetCPUInfo(dump, &process_state->system_info_); bool has_os_info = GetOSInfo(dump, &process_state->system_info_); @@ -135,14 +138,15 @@ ProcessResult MinidumpProcessor::Process( } BPLOG(INFO) << "Minidump " << dump->path() << " has " << - (has_cpu_info ? "" : "no ") << "CPU info, " << - (has_os_info ? "" : "no ") << "OS info, " << - (breakpad_info != NULL ? "" : "no ") << "Breakpad info, " << - (exception != NULL ? "" : "no ") << "exception, " << - (module_list != NULL ? "" : "no ") << "module list, " << - (threads != NULL ? "" : "no ") << "thread list, " << - (has_dump_thread ? "" : "no ") << "dump thread, and " << - (has_requesting_thread ? "" : "no ") << "requesting thread"; + (has_cpu_info ? "" : "no ") << "CPU info, " << + (has_os_info ? "" : "no ") << "OS info, " << + (breakpad_info != NULL ? "" : "no ") << "Breakpad info, " << + (exception != NULL ? "" : "no ") << "exception, " << + (module_list != NULL ? "" : "no ") << "module list, " << + (threads != NULL ? "" : "no ") << "thread list, " << + (has_dump_thread ? "" : "no ") << "dump thread, " << + (has_requesting_thread ? "" : "no ") << "requesting thread, and " << + (has_process_create_time ? "" : "no ") << "process create time"; bool interrupted = false; bool found_requesting_thread = false; @@ -619,6 +623,32 @@ bool MinidumpProcessor::GetOSInfo(Minidump *dump, SystemInfo *info) { } // static +bool MinidumpProcessor::GetProcessCreateTime(Minidump* dump, + uint32_t* process_create_time) { + assert(dump); + assert(process_create_time); + + *process_create_time = 0; + + MinidumpMiscInfo* minidump_misc_info = dump->GetMiscInfo(); + if (!minidump_misc_info) { + return false; + } + + const MDRawMiscInfo* md_raw_misc_info = minidump_misc_info->misc_info(); + if (!md_raw_misc_info) { + return false; + } + + if (!(md_raw_misc_info->flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES)) { + return false; + } + + *process_create_time = md_raw_misc_info->process_create_time; + return true; +} + +// static string MinidumpProcessor::GetCrashReason(Minidump *dump, uint64_t *address) { MinidumpException *exception = dump->GetException(); if (!exception) diff --git a/src/processor/minidump_processor_unittest.cc b/src/processor/minidump_processor_unittest.cc index abf28376..69e1f42e 100644 --- a/src/processor/minidump_processor_unittest.cc +++ b/src/processor/minidump_processor_unittest.cc @@ -66,6 +66,7 @@ class MockMinidump : public Minidump { MOCK_CONST_METHOD0(header, const MDRawHeader*()); MOCK_METHOD0(GetThreadList, MinidumpThreadList*()); MOCK_METHOD0(GetSystemInfo, MinidumpSystemInfo*()); + MOCK_METHOD0(GetMiscInfo, MinidumpMiscInfo*()); MOCK_METHOD0(GetBreakpadInfo, MinidumpBreakpadInfo*()); MOCK_METHOD0(GetException, MinidumpException*()); MOCK_METHOD0(GetAssertion, MinidumpAssertion*()); @@ -126,6 +127,17 @@ class MockMinidumpMemoryRegion : public MinidumpMemoryRegion { MockMemoryRegion region_; }; +// A test miscelaneous info stream, just returns values from the +// MDRawMiscInfo fed to it. +class TestMinidumpMiscInfo : public MinidumpMiscInfo { + public: + explicit TestMinidumpMiscInfo(const MDRawMiscInfo& misc_info) : + MinidumpMiscInfo(NULL) { + valid_ = true; + misc_info_ = misc_info; + } +}; + } // namespace google_breakpad namespace { @@ -135,6 +147,7 @@ using google_breakpad::CallStack; using google_breakpad::CodeModule; using google_breakpad::MinidumpContext; using google_breakpad::MinidumpMemoryRegion; +using google_breakpad::MinidumpMiscInfo; using google_breakpad::MinidumpProcessor; using google_breakpad::MinidumpSystemInfo; using google_breakpad::MinidumpThreadList; @@ -402,6 +415,8 @@ TEST_F(MinidumpProcessorTest, TestBasicProcessing) { ASSERT_EQ(state.crash_address(), 0x45U); ASSERT_EQ(state.threads()->size(), size_t(1)); ASSERT_EQ(state.requesting_thread(), 0); + EXPECT_EQ(1171480435U, state.time_date_stamp()); + EXPECT_EQ(1171480435U, state.process_create_time()); CallStack *stack = state.threads()->at(0); ASSERT_TRUE(stack); @@ -529,6 +544,40 @@ TEST_F(MinidumpProcessorTest, TestThreadMissingMemory) { ASSERT_EQ(kExpectedEIP, state.threads()->at(0)->frames()->at(0)->instruction); } +TEST_F(MinidumpProcessorTest, GetProcessCreateTime) { + const uint32_t kProcessCreateTime = 2000; + const uint32_t kTimeDateStamp = 5000; + MockMinidump dump; + EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); + EXPECT_CALL(dump, Read()).WillRepeatedly(Return(true)); + + // Set time of crash. + MDRawHeader fake_header; + fake_header.time_date_stamp = kTimeDateStamp; + EXPECT_CALL(dump, header()).WillRepeatedly(Return(&fake_header)); + + // Set process create time. + MDRawMiscInfo raw_misc_info; + memset(&raw_misc_info, 0, sizeof(raw_misc_info)); + raw_misc_info.process_create_time = kProcessCreateTime; + raw_misc_info.flags1 |= MD_MISCINFO_FLAGS1_PROCESS_TIMES; + google_breakpad::TestMinidumpMiscInfo dump_misc_info(raw_misc_info); + EXPECT_CALL(dump, GetMiscInfo()).WillRepeatedly(Return(&dump_misc_info)); + + // No threads + MockMinidumpThreadList thread_list; + EXPECT_CALL(dump, GetThreadList()).WillOnce(Return(&thread_list)); + EXPECT_CALL(thread_list, thread_count()).WillRepeatedly(Return(0)); + + MinidumpProcessor processor(reinterpret_cast<SymbolSupplier*>(NULL), NULL); + ProcessState state; + EXPECT_EQ(google_breakpad::PROCESS_OK, processor.Process(&dump, &state)); + + // Verify the time stamps. + ASSERT_EQ(kTimeDateStamp, state.time_date_stamp()); + ASSERT_EQ(kProcessCreateTime, state.process_create_time()); +} + TEST_F(MinidumpProcessorTest, TestThreadMissingContext) { MockMinidump dump; EXPECT_CALL(dump, path()).WillRepeatedly(Return("mock minidump")); diff --git a/src/processor/process_state.cc b/src/processor/process_state.cc index fae66776..5a5cd7f6 100644 --- a/src/processor/process_state.cc +++ b/src/processor/process_state.cc @@ -45,6 +45,7 @@ ProcessState::~ProcessState() { void ProcessState::Clear() { time_date_stamp_ = 0; + process_create_time_ = 0; crashed_ = false; crash_reason_.clear(); crash_address_ = 0; diff --git a/src/processor/proto/process_state.proto b/src/processor/proto/process_state.proto index 5ff6194c..d3e02dc3 100644 --- a/src/processor/proto/process_state.proto +++ b/src/processor/proto/process_state.proto @@ -46,11 +46,14 @@ package google_breakpad; // A proto representation of a process, in a fully-digested state. // See src/google_breakpad/processor/process_state.h message ProcessStateProto { - // Next value: 13 + // Next value: 14 // The time-date stamp of the original minidump (time_t format) optional int64 time_date_stamp = 1; + // The time-date stamp when the process was created (time_t format) + optional int64 process_create_time = 13; + message Crash { // The type of crash. OS- and possibly CPU- specific. For example, // "EXCEPTION_ACCESS_VIOLATION" (Windows), "EXC_BAD_ACCESS / diff --git a/src/processor/stackwalk_common.cc b/src/processor/stackwalk_common.cc index 72398700..0a1707e2 100644 --- a/src/processor/stackwalk_common.cc +++ b/src/processor/stackwalk_common.cc @@ -672,6 +672,18 @@ void PrintProcessState(const ProcessState& process_state) { printf("Assertion: %s\n", assertion.c_str()); } + // Compute process uptime if the process creation and crash times are + // available in the dump. + if (process_state.time_date_stamp() != 0 && + process_state.process_create_time() != 0 && + process_state.time_date_stamp() >= process_state.process_create_time()) { + printf("Process uptime: %d seconds\n", + process_state.time_date_stamp() - + process_state.process_create_time()); + } else { + printf("Process uptime: not available\n"); + } + // If the thread that requested the dump is known, print it first. int requesting_thread = process_state.requesting_thread(); if (requesting_thread != -1) { diff --git a/src/processor/testdata/microdump.stackwalk.out b/src/processor/testdata/microdump.stackwalk.out index c596e769..fffab8a9 100644 --- a/src/processor/testdata/microdump.stackwalk.out +++ b/src/processor/testdata/microdump.stackwalk.out @@ -5,6 +5,7 @@ CPU: Crash reason: Crash address: 0x0 +Process uptime: not available Thread 0 (crashed) 0 libchromeshell.so!content::::CrashIntentionally [render_frame_impl.cc : 267 + 0x2] diff --git a/src/processor/testdata/minidump2.stackwalk.out b/src/processor/testdata/minidump2.stackwalk.out index 20d1c4d8..784c7e57 100644 --- a/src/processor/testdata/minidump2.stackwalk.out +++ b/src/processor/testdata/minidump2.stackwalk.out @@ -6,6 +6,7 @@ CPU: x86 Crash reason: EXCEPTION_ACCESS_VIOLATION_WRITE Crash address: 0x45 +Process uptime: 0 seconds Thread 0 (crashed) 0 test_app.exe!`anonymous namespace'::CrashFunction [test_app.cc : 58 + 0x3] |