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>
This commit is contained in:
parent
cbd7bb4cd2
commit
6d0287851f
4 changed files with 463 additions and 18 deletions
|
@ -346,7 +346,11 @@ typedef enum {
|
|||
MD_LINUX_ENVIRON = 0x47670007, /* /proc/$x/environ */
|
||||
MD_LINUX_AUXV = 0x47670008, /* /proc/$x/auxv */
|
||||
MD_LINUX_MAPS = 0x47670009, /* /proc/$x/maps */
|
||||
MD_LINUX_DSO_DEBUG = 0x4767000A /* MDRawDebug{32,64} */
|
||||
MD_LINUX_DSO_DEBUG = 0x4767000A, /* MDRawDebug{32,64} */
|
||||
|
||||
/* Crashpad extension types. 0x4350 = "CP"
|
||||
* See Crashpad's minidump/minidump_extensions.h. */
|
||||
MD_CRASHPAD_INFO_STREAM = 0x43500001, /* MDRawCrashpadInfo */
|
||||
} MDStreamType; /* MINIDUMP_STREAM_TYPE */
|
||||
|
||||
|
||||
|
@ -1051,6 +1055,42 @@ typedef struct {
|
|||
uint64_t dynamic;
|
||||
} MDRawDebug64;
|
||||
|
||||
/* Crashpad extension types. See Crashpad's minidump/minidump_extensions.h. */
|
||||
|
||||
typedef struct {
|
||||
MDRVA key;
|
||||
MDRVA value;
|
||||
} MDRawSimpleStringDictionaryEntry;
|
||||
|
||||
typedef struct {
|
||||
uint32_t count;
|
||||
MDRawSimpleStringDictionaryEntry entries[0];
|
||||
} MDRawSimpleStringDictionary;
|
||||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
MDLocationDescriptor list_annotations;
|
||||
MDLocationDescriptor simple_annotations; /* MDRawSimpleStringDictionary */
|
||||
} MDRawModuleCrashpadInfo;
|
||||
|
||||
typedef struct {
|
||||
uint32_t minidump_module_list_index;
|
||||
MDLocationDescriptor location; /* MDRawModuleCrashpadInfo */
|
||||
} MDRawModuleCrashpadInfoLink;
|
||||
|
||||
typedef struct {
|
||||
uint32_t count;
|
||||
MDLocationDescriptor modules[0]; /* MDRawModuleCrashpadInfoLink */
|
||||
} MDRawModuleCrashpadInfoList;
|
||||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
MDGUID report_id;
|
||||
MDGUID client_id;
|
||||
MDLocationDescriptor simple_annotations; /* MDRawSimpleStringDictionary */
|
||||
MDLocationDescriptor module_list; /* MDRawModuleCrashpadInfoList */
|
||||
} MDRawCrashpadInfo;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif /* _MSC_VER */
|
||||
|
|
|
@ -1103,6 +1103,37 @@ class MinidumpLinuxMapsList : public MinidumpStream {
|
|||
DISALLOW_COPY_AND_ASSIGN(MinidumpLinuxMapsList);
|
||||
};
|
||||
|
||||
// MinidumpCrashpadInfo wraps MDRawCrashpadInfo, which is an optional stream in
|
||||
// a minidump that provides additional information about the process state
|
||||
// at the time the minidump was generated.
|
||||
class MinidumpCrashpadInfo : public MinidumpStream {
|
||||
public:
|
||||
const MDRawCrashpadInfo* crashpad_info() const {
|
||||
return valid_ ? &crashpad_info_ : NULL;
|
||||
}
|
||||
|
||||
// Print a human-readable representation of the object to stdout.
|
||||
void Print();
|
||||
|
||||
private:
|
||||
friend class Minidump;
|
||||
|
||||
static const uint32_t kStreamType = MD_CRASHPAD_INFO_STREAM;
|
||||
|
||||
explicit MinidumpCrashpadInfo(Minidump* minidump_);
|
||||
|
||||
bool Read(uint32_t expected_size);
|
||||
|
||||
MDRawCrashpadInfo crashpad_info_;
|
||||
std::vector<uint32_t> module_crashpad_info_links_;
|
||||
std::vector<MDRawModuleCrashpadInfo> module_crashpad_info_;
|
||||
std::vector<std::vector<std::string>> module_crashpad_info_list_annotations_;
|
||||
std::vector<std::map<std::string, std::string>>
|
||||
module_crashpad_info_simple_annotations_;
|
||||
std::map<std::string, std::string> simple_annotations_;
|
||||
};
|
||||
|
||||
|
||||
// Minidump is the user's interface to a minidump file. It wraps MDRawHeader
|
||||
// and provides access to the minidump's top-level stream directory.
|
||||
class Minidump {
|
||||
|
@ -1164,6 +1195,7 @@ class Minidump {
|
|||
virtual MinidumpMiscInfo* GetMiscInfo();
|
||||
virtual MinidumpBreakpadInfo* GetBreakpadInfo();
|
||||
virtual MinidumpMemoryInfoList* GetMemoryInfoList();
|
||||
MinidumpCrashpadInfo* GetCrashpadInfo();
|
||||
|
||||
// The next method also calls GetStream, but is exclusive for Linux dumps.
|
||||
virtual MinidumpLinuxMapsList *GetLinuxMapsList();
|
||||
|
@ -1191,13 +1223,21 @@ class Minidump {
|
|||
// Returns the current position of the minidump file.
|
||||
off_t Tell();
|
||||
|
||||
// The next 2 methods are medium-level I/O routines.
|
||||
// Medium-level I/O routines.
|
||||
|
||||
// ReadString returns a string which is owned by the caller! offset
|
||||
// specifies the offset that a length-encoded string is stored at in the
|
||||
// minidump file.
|
||||
string* ReadString(off_t offset);
|
||||
|
||||
bool ReadUTF8String(off_t offset, string* string_utf8);
|
||||
|
||||
bool ReadStringList(off_t offset, std::vector<std::string>* string_list);
|
||||
|
||||
bool ReadSimpleStringDictionary(
|
||||
off_t offset,
|
||||
std::map<std::string, std::string>* simple_string_dictionary);
|
||||
|
||||
// SeekToStreamType positions the file at the beginning of a stream
|
||||
// identified by stream_type, and informs the caller of the stream's
|
||||
// length by setting *stream_length. Because stream_map maps each stream
|
||||
|
|
|
@ -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(×truct, &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);
|
||||
|
@ -4745,6 +4757,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 "
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue