mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2024-12-23 07:55:38 +00: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
|
@ -639,6 +639,46 @@ class MinidumpException : public MinidumpStream {
|
|||
MinidumpContext* context_;
|
||||
};
|
||||
|
||||
// MinidumpAssertion wraps MDRawAssertionInfo, which contains information
|
||||
// about an assertion that caused the minidump to be generated.
|
||||
class MinidumpAssertion : public MinidumpStream {
|
||||
public:
|
||||
virtual ~MinidumpAssertion();
|
||||
|
||||
const MDRawAssertionInfo* assertion() const {
|
||||
return valid_ ? &assertion_ : NULL;
|
||||
}
|
||||
|
||||
string expression() const {
|
||||
return valid_ ? expression_ : "";
|
||||
}
|
||||
|
||||
string function() const {
|
||||
return valid_ ? function_ : "";
|
||||
}
|
||||
|
||||
string file() const {
|
||||
return valid_ ? file_ : "";
|
||||
}
|
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print();
|
||||
|
||||
private:
|
||||
friend class Minidump;
|
||||
|
||||
static const u_int32_t kStreamType = MD_ASSERTION_INFO_STREAM;
|
||||
|
||||
explicit MinidumpAssertion(Minidump* minidump);
|
||||
|
||||
bool Read(u_int32_t expected_size);
|
||||
|
||||
MDRawAssertionInfo assertion_;
|
||||
string expression_;
|
||||
string function_;
|
||||
string file_;
|
||||
};
|
||||
|
||||
|
||||
// MinidumpSystemInfo wraps MDRawSystemInfo and provides information about
|
||||
// the system on which the minidump was generated. See also MinidumpMiscInfo.
|
||||
|
@ -788,6 +828,7 @@ class Minidump {
|
|||
MinidumpModuleList* GetModuleList();
|
||||
MinidumpMemoryList* GetMemoryList();
|
||||
MinidumpException* GetException();
|
||||
MinidumpAssertion* GetAssertion();
|
||||
MinidumpSystemInfo* GetSystemInfo();
|
||||
MinidumpMiscInfo* GetMiscInfo();
|
||||
MinidumpBreakpadInfo* GetBreakpadInfo();
|
||||
|
|
|
@ -141,6 +141,11 @@ class MinidumpProcessor {
|
|||
return (p != PROCESS_SYMBOL_SUPPLIER_INTERRUPTED);
|
||||
}
|
||||
|
||||
// Returns a textual representation of an assertion included
|
||||
// in the minidump. Returns an empty string if this information
|
||||
// does not exist or cannot be determined.
|
||||
static string GetAssertion(Minidump *dump);
|
||||
|
||||
private:
|
||||
SymbolSupplier *supplier_;
|
||||
SourceLineResolverInterface *resolver_;
|
||||
|
|
|
@ -61,6 +61,7 @@ class ProcessState {
|
|||
bool crashed() const { return crashed_; }
|
||||
string crash_reason() const { return crash_reason_; }
|
||||
u_int64_t crash_address() const { return crash_address_; }
|
||||
string assertion() const { return assertion_; }
|
||||
int requesting_thread() const { return requesting_thread_; }
|
||||
const vector<CallStack*>* threads() const { return &threads_; }
|
||||
const vector<MinidumpMemoryRegion*>* thread_memory_regions() const {
|
||||
|
@ -92,6 +93,11 @@ class ProcessState {
|
|||
// this will be the address of the instruction that caused the fault.
|
||||
u_int64_t crash_address_;
|
||||
|
||||
// If there was an assertion that was hit, a textual representation
|
||||
// of that assertion, possibly including the file and line at which
|
||||
// it occurred.
|
||||
string assertion_;
|
||||
|
||||
// The index of the thread that requested a dump be written in the
|
||||
// threads vector. If a dump was produced as a result of a crash, this
|
||||
// will point to the thread that crashed. If the dump was produced as
|
||||
|
|
|
@ -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…
Reference in a new issue