mirror of
				https://github.com/yuzu-emu/breakpad.git
				synced 2025-11-04 16:04:58 +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