aboutsummaryrefslogtreecommitdiff
path: root/src/processor
diff options
context:
space:
mode:
authorted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e>2009-12-02 17:43:57 +0000
committerted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e>2009-12-02 17:43:57 +0000
commit0314e487e46a45229e275eb78b09f0538a5a7769 (patch)
treee8703a4ed915335696767a5ae3362effd5940f45 /src/processor
parentUpstreaming several patches from Chrome: (diff)
downloadbreakpad-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.cc117
-rw-r--r--src/processor/minidump_dump.cc8
-rw-r--r--src/processor/minidump_processor.cc56
-rw-r--r--src/processor/minidump_stackwalk.cc15
-rw-r--r--src/processor/process_state.cc1
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();