aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/google_breakpad/processor/minidump.h13
-rw-r--r--src/google_breakpad/processor/minidump_processor.h6
-rw-r--r--src/google_breakpad/processor/process_state.h4
-rw-r--r--src/processor/minidump_processor.cc46
-rw-r--r--src/processor/minidump_processor_unittest.cc49
-rw-r--r--src/processor/process_state.cc1
-rw-r--r--src/processor/proto/process_state.proto5
-rw-r--r--src/processor/stackwalk_common.cc12
-rw-r--r--src/processor/testdata/microdump.stackwalk.out1
-rw-r--r--src/processor/testdata/minidump2.stackwalk.out1
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]