mirror of
https://git.suyu.dev/suyu/breakpad.git
synced 2026-01-01 20:24:40 +01:00
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
This commit is contained in:
parent
096992fac7
commit
0314e487e4
8 changed files with 248 additions and 1 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue