diff options
author | ted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2009-12-02 17:43:57 +0000 |
---|---|---|
committer | ted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2009-12-02 17:43:57 +0000 |
commit | 0314e487e46a45229e275eb78b09f0538a5a7769 (patch) | |
tree | e8703a4ed915335696767a5ae3362effd5940f45 /src/processor | |
parent | Upstreaming several patches from Chrome: (diff) | |
download | breakpad-0314e487e46a45229e275eb78b09f0538a5a7769.tar.xz |
issue 170 - Report assertion type in minidump_stackwalk output. r=mark at http://breakpad.appspot.com/45001
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@433 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/processor')
-rw-r--r-- | src/processor/minidump.cc | 117 | ||||
-rw-r--r-- | src/processor/minidump_dump.cc | 8 | ||||
-rw-r--r-- | src/processor/minidump_processor.cc | 56 | ||||
-rw-r--r-- | src/processor/minidump_stackwalk.cc | 15 | ||||
-rw-r--r-- | src/processor/process_state.cc | 1 |
5 files changed, 196 insertions, 1 deletions
diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc index cd6da170..ab4e4286 100644 --- a/src/processor/minidump.cc +++ b/src/processor/minidump.cc @@ -243,6 +243,15 @@ static string* UTF16ToUTF8(const vector<u_int16_t>& in, return out.release(); } +// Return the smaller of the number of code units in the UTF-16 string, +// not including the terminating null word, or maxlen. +static size_t UTF16codeunits(const u_int16_t *string, size_t maxlen) { + size_t count = 0; + while (count < maxlen && string[count] != 0) + count++; + return count; +} + // // MinidumpObject @@ -2768,6 +2777,109 @@ void MinidumpException::Print() { } } +// +// MinidumpAssertion +// + + +MinidumpAssertion::MinidumpAssertion(Minidump* minidump) + : MinidumpStream(minidump), + assertion_(), + expression_(), + function_(), + file_() { +} + + +MinidumpAssertion::~MinidumpAssertion() { +} + + +bool MinidumpAssertion::Read(u_int32_t expected_size) { + // Invalidate cached data. + valid_ = false; + + if (expected_size != sizeof(assertion_)) { + BPLOG(ERROR) << "MinidumpAssertion size mismatch, " << expected_size << + " != " << sizeof(assertion_); + return false; + } + + if (!minidump_->ReadBytes(&assertion_, sizeof(assertion_))) { + BPLOG(ERROR) << "MinidumpAssertion cannot read assertion"; + return false; + } + + // Each of {expression, function, file} is a UTF-16 string, + // we'll convert them to UTF-8 for ease of use. + // expression + // Since we don't have an explicit byte length for each string, + // we use UTF16codeunits to calculate word length, then derive byte + // length from that. + u_int32_t word_length = UTF16codeunits(assertion_.expression, + sizeof(assertion_.expression)); + if (word_length > 0) { + u_int32_t byte_length = word_length * 2; + vector<u_int16_t> expression_utf16(word_length); + memcpy(&expression_utf16[0], &assertion_.expression[0], byte_length); + + scoped_ptr<string> new_expression(UTF16ToUTF8(expression_utf16, + minidump_->swap())); + expression_ = *new_expression; + } + + // assertion + word_length = UTF16codeunits(assertion_.function, + sizeof(assertion_.function)); + if (word_length) { + u_int32_t byte_length = word_length * 2; + vector<u_int16_t> function_utf16(word_length); + memcpy(&function_utf16[0], &assertion_.function[0], byte_length); + scoped_ptr<string> new_function(UTF16ToUTF8(function_utf16, + minidump_->swap())); + function_ = *new_function; + } + + // file + word_length = UTF16codeunits(assertion_.file, + sizeof(assertion_.file)); + if (word_length > 0) { + u_int32_t byte_length = word_length * 2; + vector<u_int16_t> file_utf16(word_length); + memcpy(&file_utf16[0], &assertion_.file[0], byte_length); + scoped_ptr<string> new_file(UTF16ToUTF8(file_utf16, + minidump_->swap())); + file_ = *new_file; + } + + if (minidump_->swap()) { + Swap(&assertion_.line); + Swap(&assertion_.type); + } + + valid_ = true; + return true; +} + +void MinidumpAssertion::Print() { + if (!valid_) { + BPLOG(ERROR) << "MinidumpAssertion cannot print invalid data"; + return; + } + + printf("MDAssertion\n"); + printf(" expression = %s\n", + expression_.c_str()); + printf(" function = %s\n", + function_.c_str()); + printf(" file = %s\n", + file_.c_str()); + printf(" line = %u\n", + assertion_.line); + printf(" type = %u\n", + assertion_.type); + printf("\n"); +} // // MinidumpSystemInfo @@ -3415,6 +3527,11 @@ MinidumpException* Minidump::GetException() { return GetStream(&exception); } +MinidumpAssertion* Minidump::GetAssertion() { + MinidumpAssertion* assertion; + return GetStream(&assertion); +} + MinidumpSystemInfo* Minidump::GetSystemInfo() { MinidumpSystemInfo* system_info; diff --git a/src/processor/minidump_dump.cc b/src/processor/minidump_dump.cc index 12a699de..b586252f 100644 --- a/src/processor/minidump_dump.cc +++ b/src/processor/minidump_dump.cc @@ -44,6 +44,7 @@ using google_breakpad::MinidumpThreadList; using google_breakpad::MinidumpModuleList; using google_breakpad::MinidumpMemoryList; using google_breakpad::MinidumpException; +using google_breakpad::MinidumpAssertion; using google_breakpad::MinidumpSystemInfo; using google_breakpad::MinidumpMiscInfo; using google_breakpad::MinidumpBreakpadInfo; @@ -89,6 +90,13 @@ static bool PrintMinidumpDump(const char *minidump_file) { exception->Print(); } + MinidumpAssertion *assertion = minidump.GetAssertion(); + if (!assertion) { + BPLOG(INFO) << "minidump.GetAssertion() failed"; + } else { + assertion->Print(); + } + MinidumpSystemInfo *system_info = minidump.GetSystemInfo(); if (!system_info) { ++errors; diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc index 0ce19e38..24b03e9d 100644 --- a/src/processor/minidump_processor.cc +++ b/src/processor/minidump_processor.cc @@ -86,6 +86,9 @@ ProcessResult MinidumpProcessor::Process( dump, &process_state->crash_address_); } + // This will just return an empty string if it doesn't exist. + process_state->assertion_ = GetAssertion(dump); + MinidumpModuleList *module_list = dump->GetModuleList(); // Put a copy of the module list into ProcessState object. This is not @@ -1006,4 +1009,57 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, u_int64_t *address) { return reason; } +// static +string MinidumpProcessor::GetAssertion(Minidump *dump) +{ + MinidumpAssertion *assertion = dump->GetAssertion(); + if (!assertion) + return ""; + + const MDRawAssertionInfo *raw_assertion = assertion->assertion(); + if (!raw_assertion) + return ""; + + string assertion_string; + switch (raw_assertion->type) { + case MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER: + assertion_string = "Invalid parameter passed to library function"; + break; + case MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL: + assertion_string = "Pure virtual function called"; + break; + default: { + char assertion_type[32]; + sprintf(assertion_type, "0x%08x", raw_assertion->type); + assertion_string = "Unknown assertion type "; + assertion_string += assertion_type; + break; + } + } + + string expression = assertion->expression(); + if (!expression.empty()) { + assertion_string.append(" " + expression); + } + + string function = assertion->function(); + if (!function.empty()) { + assertion_string.append(" in function " + function); + } + + string file = assertion->file(); + if (!file.empty()) { + assertion_string.append(", in file " + file); + } + + if (raw_assertion->line != 0) { + char assertion_line[32]; + sprintf(assertion_line, "%u", raw_assertion->line); + assertion_string.append(" at line "); + assertion_string.append(assertion_line); + } + + return assertion_string; +} + } // namespace google_breakpad diff --git a/src/processor/minidump_stackwalk.cc b/src/processor/minidump_stackwalk.cc index 01f0c0c6..3701c466 100644 --- a/src/processor/minidump_stackwalk.cc +++ b/src/processor/minidump_stackwalk.cc @@ -361,6 +361,11 @@ static void PrintProcessState(const ProcessState& process_state) { printf("No crash\n"); } + string assertion = process_state.assertion(); + if (!assertion.empty()) { + printf("Assertion: %s\n", assertion.c_str()); + } + // If the thread that requested the dump is known, print it first. int requesting_thread = process_state.requesting_thread(); if (requesting_thread != -1) { @@ -413,7 +418,15 @@ static void PrintProcessStateMachineReadable(const ProcessState& process_state) StripSeparator(process_state.crash_reason()).c_str(), kOutputSeparator, process_state.crash_address(), kOutputSeparator); } else { - printf("No crash%c%c", kOutputSeparator, kOutputSeparator); + // print assertion info, if available, in place of crash reason, + // instead of the unhelpful "No crash" + string assertion = process_state.assertion(); + if (!assertion.empty()) { + printf("%s%c%c", StripSeparator(assertion).c_str(), + kOutputSeparator, kOutputSeparator); + } else { + printf("No crash%c%c", kOutputSeparator, kOutputSeparator); + } } if (requesting_thread != -1) { diff --git a/src/processor/process_state.cc b/src/processor/process_state.cc index 934792b3..1d970bad 100644 --- a/src/processor/process_state.cc +++ b/src/processor/process_state.cc @@ -48,6 +48,7 @@ void ProcessState::Clear() { crashed_ = false; crash_reason_.clear(); crash_address_ = 0; + assertion_.clear(); requesting_thread_ = -1; for (vector<CallStack *>::const_iterator iterator = threads_.begin(); iterator != threads_.end(); |