aboutsummaryrefslogtreecommitdiff
path: root/src/processor
diff options
context:
space:
mode:
authorMark Mentovai <mark@chromium.org>2017-09-27 17:13:47 -0400
committerMark Mentovai <mark@chromium.org>2017-09-27 21:27:17 +0000
commit6d0287851fabc21a90838ae068b11f2d777393d5 (patch)
tree03856988e14c91ebea985095ecdb2da66b478d5a /src/processor
parentOnly run GYP for Windows targets on Windows (diff)
downloadbreakpad-6d0287851fabc21a90838ae068b11f2d777393d5.tar.xz
Dump Crashpad extension structures in minidump_dump
This is currently mostly useful to expose the annotations that Crashpad stores in minidumps. Example output: MDRawCrashpadInfo version = 1 report_id = 01234567-89ab-cdef-0123-456789abcdef client_id = fedcba98-7654-3210-fedc-ba9876543210 simple_annotations["channel"] = canary simple_annotations["plat"] = OS X simple_annotations["prod"] = Chrome_Mac simple_annotations["ver"] = 59.0.3069.0 module_list[0].minidump_module_list_index = 0 module_list[0].version = 1 module_list[0].simple_annotations["ptype"] = crashpad-handler module_list[1].minidump_module_list_index = 28 module_list[1].version = 1 module_list[1].list_annotations[0] = abort() called Change-Id: I00ba291f93ea3a37fc3754c651b3ccc542e5b8b2 Reviewed-on: https://chromium-review.googlesource.com/688416 Reviewed-by: Robert Sesek <rsesek@chromium.org>
Diffstat (limited to 'src/processor')
-rw-r--r--src/processor/minidump.cc390
-rw-r--r--src/processor/minidump_dump.cc7
2 files changed, 381 insertions, 16 deletions
diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc
index a9c7d23a..0c8685d4 100644
--- a/src/processor/minidump.cc
+++ b/src/processor/minidump.cc
@@ -49,10 +49,8 @@
#include <algorithm>
#include <fstream>
-#include <iostream>
#include <limits>
-#include <map>
-#include <vector>
+#include <utility>
#include "processor/range_map-inl.h"
@@ -212,6 +210,11 @@ static inline void Swap(MDXStateConfigFeatureMscInfo* xstate_feature_info) {
}
}
+static inline void Swap(MDRawSimpleStringDictionaryEntry* entry) {
+ Swap(&entry->key);
+ Swap(&entry->value);
+}
+
static inline void Swap(uint16_t* data, size_t size_in_bytes) {
size_t data_length = size_in_bytes / sizeof(data[0]);
for (size_t i = 0; i < data_length; i++) {
@@ -371,7 +374,7 @@ static void PrintValueOrInvalid(bool valid,
}
// Converts a time_t to a string showing the time in UTC.
-string TimeTToUTCString(time_t tt) {
+static string TimeTToUTCString(time_t tt) {
struct tm timestruct;
#ifdef _WIN32
gmtime_s(&timestruct, &tt);
@@ -389,6 +392,24 @@ string TimeTToUTCString(time_t tt) {
}
+static string MDGUIDToString(const MDGUID& uuid) {
+ char buf[37];
+ snprintf(buf, sizeof(buf), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ uuid.data1,
+ uuid.data2,
+ uuid.data3,
+ uuid.data4[0],
+ uuid.data4[1],
+ uuid.data4[2],
+ uuid.data4[3],
+ uuid.data4[4],
+ uuid.data4[5],
+ uuid.data4[6],
+ uuid.data4[7]);
+ return std::string(buf);
+}
+
+
//
// MinidumpObject
//
@@ -2481,17 +2502,8 @@ void MinidumpModule::Print() {
printf(" (cv_record).cv_signature = 0x%x\n",
cv_record_70->cv_signature);
- printf(" (cv_record).signature = %08x-%04x-%04x-%02x%02x-",
- cv_record_70->signature.data1,
- cv_record_70->signature.data2,
- cv_record_70->signature.data3,
- cv_record_70->signature.data4[0],
- cv_record_70->signature.data4[1]);
- for (unsigned int guidIndex = 2;
- guidIndex < 8;
- ++guidIndex) {
- printf("%02x", cv_record_70->signature.data4[guidIndex]);
- }
+ printf(" (cv_record).signature = %s\n",
+ MDGUIDToString(cv_record_70->signature).c_str());
printf("\n");
printf(" (cv_record).age = %d\n",
cv_record_70->age);
@@ -4746,6 +4758,192 @@ void MinidumpLinuxMapsList::Print() const {
}
//
+// MinidumpCrashpadInfo
+//
+
+
+MinidumpCrashpadInfo::MinidumpCrashpadInfo(Minidump* minidump)
+ : MinidumpStream(minidump),
+ crashpad_info_(),
+ module_crashpad_info_links_(),
+ module_crashpad_info_(),
+ module_crashpad_info_list_annotations_(),
+ module_crashpad_info_simple_annotations_(),
+ simple_annotations_() {
+}
+
+
+bool MinidumpCrashpadInfo::Read(uint32_t expected_size) {
+ valid_ = false;
+
+ if (expected_size != sizeof(crashpad_info_)) {
+ BPLOG(ERROR) << "MinidumpCrashpadInfo size mismatch, " << expected_size <<
+ " != " << sizeof(crashpad_info_);
+ return false;
+ }
+
+ if (!minidump_->ReadBytes(&crashpad_info_, sizeof(crashpad_info_))) {
+ BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad info";
+ return false;
+ }
+
+ if (minidump_->swap()) {
+ Swap(&crashpad_info_.version);
+ Swap(&crashpad_info_.report_id);
+ Swap(&crashpad_info_.client_id);
+ Swap(&crashpad_info_.simple_annotations);
+ Swap(&crashpad_info_.module_list);
+ }
+
+ if (crashpad_info_.simple_annotations.data_size) {
+ if (!minidump_->ReadSimpleStringDictionary(
+ crashpad_info_.simple_annotations.rva,
+ &simple_annotations_)) {
+ BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read simple_annotations";
+ return false;
+ }
+ }
+
+ if (crashpad_info_.module_list.data_size) {
+ if (!minidump_->SeekSet(crashpad_info_.module_list.rva)) {
+ BPLOG(ERROR) << "MinidumpCrashpadInfo cannot seek to module_list";
+ return false;
+ }
+
+ uint32_t count;
+ if (!minidump_->ReadBytes(&count, sizeof(count))) {
+ BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read module_list count";
+ return false;
+ }
+
+ if (minidump_->swap()) {
+ Swap(&count);
+ }
+
+ scoped_array<MDRawModuleCrashpadInfoLink> module_crashpad_info_links(
+ new MDRawModuleCrashpadInfoLink[count]);
+
+ // Read the entire array in one fell swoop, instead of reading one entry
+ // at a time in the loop.
+ if (!minidump_->ReadBytes(
+ &module_crashpad_info_links[0],
+ sizeof(MDRawModuleCrashpadInfoLink) * count)) {
+ BPLOG(ERROR)
+ << "MinidumpCrashpadInfo could not read Crashpad module links";
+ return false;
+ }
+
+ for (uint32_t index = 0; index < count; ++index) {
+ if (minidump_->swap()) {
+ Swap(&module_crashpad_info_links[index].minidump_module_list_index);
+ Swap(&module_crashpad_info_links[index].location);
+ }
+
+ if (!minidump_->SeekSet(module_crashpad_info_links[index].location.rva)) {
+ BPLOG(ERROR)
+ << "MinidumpCrashpadInfo cannot seek to Crashpad module info";
+ return false;
+ }
+
+ MDRawModuleCrashpadInfo module_crashpad_info;
+ if (!minidump_->ReadBytes(&module_crashpad_info,
+ sizeof(module_crashpad_info))) {
+ BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad module info";
+ return false;
+ }
+
+ if (minidump_->swap()) {
+ Swap(&module_crashpad_info.version);
+ Swap(&module_crashpad_info.list_annotations);
+ Swap(&module_crashpad_info.simple_annotations);
+ }
+
+ std::vector<std::string> list_annotations;
+ if (module_crashpad_info.list_annotations.data_size) {
+ if (!minidump_->ReadStringList(
+ module_crashpad_info.list_annotations.rva,
+ &list_annotations)) {
+ BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad module "
+ "info list annotations";
+ return false;
+ }
+ }
+
+ std::map<std::string, std::string> simple_annotations;
+ if (module_crashpad_info.simple_annotations.data_size) {
+ if (!minidump_->ReadSimpleStringDictionary(
+ module_crashpad_info.simple_annotations.rva,
+ &simple_annotations)) {
+ BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad module "
+ "info simple annotations";
+ return false;
+ }
+ }
+
+ module_crashpad_info_links_.push_back(
+ module_crashpad_info_links[index].minidump_module_list_index);
+ module_crashpad_info_.push_back(module_crashpad_info);
+ module_crashpad_info_list_annotations_.push_back(list_annotations);
+ module_crashpad_info_simple_annotations_.push_back(simple_annotations);
+ }
+ }
+
+ valid_ = true;
+ return true;
+}
+
+
+void MinidumpCrashpadInfo::Print() {
+ if (!valid_) {
+ BPLOG(ERROR) << "MinidumpCrashpadInfo cannot print invalid data";
+ return;
+ }
+
+ printf("MDRawCrashpadInfo\n");
+ printf(" version = %d\n", crashpad_info_.version);
+ printf(" report_id = %s\n",
+ MDGUIDToString(crashpad_info_.report_id).c_str());
+ printf(" client_id = %s\n",
+ MDGUIDToString(crashpad_info_.client_id).c_str());
+ for (std::map<string, string>::const_iterator iterator =
+ simple_annotations_.begin();
+ iterator != simple_annotations_.end();
+ ++iterator) {
+ printf(" simple_annotations[\"%s\"] = %s\n",
+ iterator->first.c_str(), iterator->second.c_str());
+ }
+ for (uint32_t module_index = 0;
+ module_index < module_crashpad_info_links_.size();
+ ++module_index) {
+ printf(" module_list[%d].minidump_module_list_index = %d\n",
+ module_index, module_crashpad_info_links_[module_index]);
+ printf(" module_list[%d].version = %d\n",
+ module_index, module_crashpad_info_[module_index].version);
+ for (uint32_t annotation_index = 0;
+ annotation_index <
+ module_crashpad_info_list_annotations_[module_index].size();
+ ++annotation_index) {
+ printf(" module_list[%d].list_annotations[%d] = %s\n",
+ module_index,
+ annotation_index,
+ module_crashpad_info_list_annotations_
+ [module_index][annotation_index].c_str());
+ }
+ for (std::map<string, string>::const_iterator iterator =
+ module_crashpad_info_simple_annotations_[module_index].begin();
+ iterator !=
+ module_crashpad_info_simple_annotations_[module_index].end();
+ ++iterator) {
+ printf(" module_list[%d].simple_annotations[\"%s\"] = %s\n",
+ module_index, iterator->first.c_str(), iterator->second.c_str());
+ }
+ }
+
+ printf("\n");
+}
+
+
+//
// Minidump
//
@@ -4993,7 +5191,8 @@ bool Minidump::Read() {
case MD_EXCEPTION_STREAM:
case MD_SYSTEM_INFO_STREAM:
case MD_MISC_INFO_STREAM:
- case MD_BREAKPAD_INFO_STREAM: {
+ case MD_BREAKPAD_INFO_STREAM:
+ case MD_CRASHPAD_INFO_STREAM: {
if (stream_map_->find(stream_type) != stream_map_->end()) {
// Another stream with this type was already found. A minidump
// file should contain at most one of each of these stream types.
@@ -5100,6 +5299,11 @@ bool Minidump::IsAndroid() {
return system_info && system_info->platform_id == MD_OS_ANDROID;
}
+MinidumpCrashpadInfo* Minidump::GetCrashpadInfo() {
+ MinidumpCrashpadInfo* crashpad_info;
+ return GetStream(&crashpad_info);
+}
+
static const char* get_stream_name(uint32_t stream_type) {
switch (stream_type) {
case MD_UNUSED_STREAM:
@@ -5170,6 +5374,8 @@ static const char* get_stream_name(uint32_t stream_type) {
return "MD_LINUX_MAPS";
case MD_LINUX_DSO_DEBUG:
return "MD_LINUX_DSO_DEBUG";
+ case MD_CRASHPAD_INFO_STREAM:
+ return "MD_CRASHPAD_INFO_STREAM";
default:
return "unknown";
}
@@ -5351,6 +5557,158 @@ string* Minidump::ReadString(off_t offset) {
}
+bool Minidump::ReadUTF8String(off_t offset, string* string_utf8) {
+ if (!valid_) {
+ BPLOG(ERROR) << "Invalid Minidump for ReadString";
+ return false;
+ }
+ if (!SeekSet(offset)) {
+ BPLOG(ERROR) << "ReadUTF8String could not seek to string at offset "
+ << offset;
+ return false;
+ }
+
+ uint32_t bytes;
+ if (!ReadBytes(&bytes, sizeof(bytes))) {
+ BPLOG(ERROR) << "ReadUTF8String could not read string size at offset " <<
+ offset;
+ return false;
+ }
+
+ if (swap_) {
+ Swap(&bytes);
+ }
+
+ if (bytes > max_string_length_) {
+ BPLOG(ERROR) << "ReadUTF8String string length " << bytes <<
+ " exceeds maximum " << max_string_length_ <<
+ " at offset " << offset;
+ return false;
+ }
+
+ string_utf8->resize(bytes);
+
+ if (!ReadBytes(&(*string_utf8)[0], bytes)) {
+ BPLOG(ERROR) << "ReadUTF8String could not read " << bytes <<
+ "-byte string at offset " << offset;
+ return false;
+ }
+
+ return true;
+}
+
+
+bool Minidump::ReadStringList(
+ off_t offset,
+ std::vector<std::string>* string_list) {
+ string_list->clear();
+
+ if (!SeekSet(offset)) {
+ BPLOG(ERROR) << "Minidump cannot seek to string_list";
+ return false;
+ }
+
+ uint32_t count;
+ if (!ReadBytes(&count, sizeof(count))) {
+ BPLOG(ERROR) << "Minidump cannot read string_list count";
+ return false;
+ }
+
+ if (swap_) {
+ Swap(&count);
+ }
+
+ scoped_array<MDRVA> rvas(new MDRVA[count]);
+
+ // Read the entire array in one fell swoop, instead of reading one entry
+ // at a time in the loop.
+ if (!ReadBytes(&rvas[0], sizeof(MDRVA) * count)) {
+ BPLOG(ERROR) << "Minidump could not read string_list";
+ return false;
+ }
+
+ for (uint32_t index = 0; index < count; ++index) {
+ if (swap()) {
+ Swap(&rvas[index]);
+ }
+
+ string entry;
+ if (!ReadUTF8String(rvas[index], &entry)) {
+ BPLOG(ERROR) << "Minidump could not read string_list entry";
+ return false;
+ }
+
+ string_list->push_back(entry);
+ }
+
+ return true;
+}
+
+
+bool Minidump::ReadSimpleStringDictionary(
+ off_t offset,
+ std::map<std::string, std::string>* simple_string_dictionary) {
+ simple_string_dictionary->clear();
+
+ if (!SeekSet(offset)) {
+ BPLOG(ERROR) << "Minidump cannot seek to simple_string_dictionary";
+ return false;
+ }
+
+ uint32_t count;
+ if (!ReadBytes(&count, sizeof(count))) {
+ BPLOG(ERROR)
+ << "Minidump cannot read simple_string_dictionary count";
+ return false;
+ }
+
+ if (swap()) {
+ Swap(&count);
+ }
+
+ scoped_array<MDRawSimpleStringDictionaryEntry> entries(
+ new MDRawSimpleStringDictionaryEntry[count]);
+
+ // Read the entire array in one fell swoop, instead of reading one entry
+ // at a time in the loop.
+ if (!ReadBytes(
+ &entries[0],
+ sizeof(MDRawSimpleStringDictionaryEntry) * count)) {
+ BPLOG(ERROR) << "Minidump could not read simple_string_dictionary";
+ return false;
+ }
+
+ for (uint32_t index = 0; index < count; ++index) {
+ if (swap()) {
+ Swap(&entries[index]);
+ }
+
+ string key;
+ if (!ReadUTF8String(entries[index].key, &key)) {
+ BPLOG(ERROR) << "Minidump could not read simple_string_dictionary key";
+ return false;
+ }
+
+ string value;
+ if (!ReadUTF8String(entries[index].value, &value)) {
+ BPLOG(ERROR) << "Minidump could not read simple_string_dictionary value";
+ return false;
+ }
+
+ if (simple_string_dictionary->find(key) !=
+ simple_string_dictionary->end()) {
+ BPLOG(ERROR)
+ << "Minidump: discarding duplicate simple_string_dictionary value "
+ << value << " for key " << key;
+ } else {
+ simple_string_dictionary->insert(std::make_pair(key, value));
+ }
+ }
+
+ return true;
+}
+
+
bool Minidump::SeekToStreamType(uint32_t stream_type,
uint32_t* stream_length) {
BPLOG_IF(ERROR, !stream_length) << "Minidump::SeekToStreamType requires "
diff --git a/src/processor/minidump_dump.cc b/src/processor/minidump_dump.cc
index b9b7555e..867f47b5 100644
--- a/src/processor/minidump_dump.cc
+++ b/src/processor/minidump_dump.cc
@@ -52,6 +52,7 @@ using google_breakpad::MinidumpAssertion;
using google_breakpad::MinidumpSystemInfo;
using google_breakpad::MinidumpMiscInfo;
using google_breakpad::MinidumpBreakpadInfo;
+using google_breakpad::MinidumpCrashpadInfo;
struct Options {
Options()
@@ -182,6 +183,12 @@ static bool PrintMinidumpDump(const Options& options) {
memory_info_list->Print();
}
+ MinidumpCrashpadInfo *crashpad_info = minidump.GetCrashpadInfo();
+ if (crashpad_info) {
+ // Crashpad info is optional, so don't treat absence as an error.
+ crashpad_info->Print();
+ }
+
DumpRawStream(&minidump,
MD_LINUX_CMD_LINE,
"MD_LINUX_CMD_LINE",