Skip to content

Commit

Permalink
Add support for reading annotation objects in Crashpad modules
Browse files Browse the repository at this point in the history
At the moment, the Minidump class only supports reading simple and
list annotations from Crashpad minidumps. This change adds support
for reading annotation objects stored in Crashpad modules
(MDRawModuleCrashpadInfo) and exposes them via a new getter in
MinidumpCrashpadInfo.

Change-Id: I033fc4a4fdff5901babc2472e0150f79af56b830
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/4195756
Reviewed-by: Joshua Peraza <[email protected]>
  • Loading branch information
Zaid Elkurdi authored and Joshua Peraza committed Jan 26, 2023
1 parent 2c86c99 commit a4f148b
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/google_breakpad/common/minidump_format.h
Original file line number Diff line number Diff line change
Expand Up @@ -1096,10 +1096,23 @@ typedef struct {
MDRawSimpleStringDictionaryEntry entries[0];
} MDRawSimpleStringDictionary;

typedef struct {
MDRVA name;
uint16_t type;
uint16_t reserved;
MDRVA value;
} MDRawCrashpadAnnotation;

typedef struct {
uint32_t count;
MDLocationDescriptor objects[0]; /* MDRawCrashpadAnnotation */
} MDRawCrashpadAnnotationList;

typedef struct {
uint32_t version;
MDLocationDescriptor list_annotations;
MDLocationDescriptor simple_annotations; /* MDRawSimpleStringDictionary */
MDLocationDescriptor annotation_objects; /* MDRawCrashpadAnnotationList */
} MDRawModuleCrashpadInfo;

typedef struct {
Expand Down
18 changes: 18 additions & 0 deletions src/google_breakpad/processor/minidump.h
Original file line number Diff line number Diff line change
Expand Up @@ -1189,10 +1189,21 @@ class MinidumpLinuxMapsList : public MinidumpStream {
// at the time the minidump was generated.
class MinidumpCrashpadInfo : public MinidumpStream {
public:
struct AnnotationObject {
uint16_t type;
std::string name;
std::vector<uint8_t> value;
};

const MDRawCrashpadInfo* crashpad_info() const {
return valid_ ? &crashpad_info_ : NULL;
}

const std::vector<std::vector<AnnotationObject>>*
GetModuleCrashpadInfoAnnotationObjects() const {
return valid_ ? &module_crashpad_info_annotation_objects_ : NULL;
}

// Print a human-readable representation of the object to stdout.
void Print();

Expand All @@ -1211,6 +1222,9 @@ class MinidumpCrashpadInfo : public MinidumpStream {
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::vector<std::vector<AnnotationObject>>
module_crashpad_info_annotation_objects_;

std::map<std::string, std::string> simple_annotations_;
};

Expand Down Expand Up @@ -1320,6 +1334,10 @@ class Minidump {
off_t offset,
std::map<std::string, std::string>* simple_string_dictionary);

bool ReadCrashpadAnnotationsList(
off_t offset,
std::vector<MinidumpCrashpadInfo::AnnotationObject>* annotations_list);

// 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
Expand Down
87 changes: 87 additions & 0 deletions src/processor/minidump.cc
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,12 @@ inline void Swap(MDRawSimpleStringDictionaryEntry* entry) {
Swap(&entry->value);
}

inline void Swap(MDRawCrashpadAnnotation* annotation) {
Swap(&annotation->name);
Swap(&annotation->type);
Swap(&annotation->value);
}

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++) {
Expand Down Expand Up @@ -5261,6 +5267,7 @@ MinidumpCrashpadInfo::MinidumpCrashpadInfo(Minidump* minidump)
module_crashpad_info_(),
module_crashpad_info_list_annotations_(),
module_crashpad_info_simple_annotations_(),
module_crashpad_info_annotation_objects_(),
simple_annotations_() {
}

Expand Down Expand Up @@ -5386,6 +5393,7 @@ bool MinidumpCrashpadInfo::Read(uint32_t expected_size) {
Swap(&module_crashpad_info.version);
Swap(&module_crashpad_info.list_annotations);
Swap(&module_crashpad_info.simple_annotations);
Swap(&module_crashpad_info.annotation_objects);
}

std::vector<std::string> list_annotations;
Expand All @@ -5410,11 +5418,23 @@ bool MinidumpCrashpadInfo::Read(uint32_t expected_size) {
}
}

std::vector<MinidumpCrashpadInfo::AnnotationObject> annotation_objects;
if (module_crashpad_info.annotation_objects.data_size) {
if (!minidump_->ReadCrashpadAnnotationsList(
module_crashpad_info.annotation_objects.rva,
&annotation_objects)) {
BPLOG(ERROR)
<< "MinidumpCrashpadInfo cannot read Crashpad annotations list";
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);
module_crashpad_info_annotation_objects_.push_back(annotation_objects);
}
}

Expand Down Expand Up @@ -6265,6 +6285,73 @@ bool Minidump::ReadSimpleStringDictionary(
return true;
}

bool Minidump::ReadCrashpadAnnotationsList(
off_t offset,
std::vector<MinidumpCrashpadInfo::AnnotationObject>* annotations_list) {
annotations_list->clear();

if (!SeekSet(offset)) {
BPLOG(ERROR) << "Minidump cannot seek to annotations_list";
return false;
}

uint32_t count;
if (!ReadBytes(&count, sizeof(count))) {
BPLOG(ERROR) << "Minidump cannot read annotations_list count";
return false;
}

if (swap_) {
Swap(&count);
}

scoped_array<MDRawCrashpadAnnotation> objects(
new MDRawCrashpadAnnotation[count]);

// Read the entire array in one fell swoop, instead of reading one entry
// at a time in the loop.
if (!ReadBytes(&objects[0], sizeof(MDRawCrashpadAnnotation) * count)) {
BPLOG(ERROR) << "Minidump could not read annotations_list";
return false;
}

for (uint32_t index = 0; index < count; ++index) {
MDRawCrashpadAnnotation annotation = objects[index];

if (swap_) {
Swap(&annotation);
}

string name;
if (!ReadUTF8String(annotation.name, &name)) {
BPLOG(ERROR) << "Minidump could not read annotation name";
return false;
}

if (!SeekSet(annotation.value)) {
BPLOG(ERROR) << "Minidump cannot seek to annotations value";
return false;
}

uint32_t value_length;
if (!ReadBytes(&value_length, sizeof(value_length))) {
BPLOG(ERROR) << "Minidump could not read annotation value length";
return false;
}

std::vector<uint8_t> value_data(value_length);
if (!ReadBytes(value_data.data(), value_length)) {
BPLOG(ERROR) << "Minidump could not read annotation value";
return false;
}

MinidumpCrashpadInfo::AnnotationObject object = {annotation.type, name,
value_data};
annotations_list->push_back(object);
}

return true;
}

bool Minidump::SeekToStreamType(uint32_t stream_type,
uint32_t* stream_length) {
Expand Down
37 changes: 37 additions & 0 deletions src/processor/minidump_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ namespace {

using google_breakpad::Minidump;
using google_breakpad::MinidumpContext;
using google_breakpad::MinidumpCrashpadInfo;
using google_breakpad::MinidumpException;
using google_breakpad::MinidumpMemoryInfo;
using google_breakpad::MinidumpMemoryInfoList;
Expand Down Expand Up @@ -130,6 +131,42 @@ TEST_F(MinidumpTest, TestMinidumpFromStream) {
//TODO: add more checks here
}

TEST_F(MinidumpTest, TestMinidumpWithCrashpadAnnotations) {
string crashpad_minidump_file =
string(getenv("srcdir") ? getenv("srcdir") : ".") +
"/src/processor/testdata/minidump_crashpad_annotation.dmp";

Minidump minidump(crashpad_minidump_file);
ASSERT_EQ(minidump.path(), crashpad_minidump_file);
ASSERT_TRUE(minidump.Read());

MinidumpCrashpadInfo* crashpad_info = minidump.GetCrashpadInfo();
ASSERT_TRUE(crashpad_info != NULL);

const std::vector<std::vector<MinidumpCrashpadInfo::AnnotationObject>>*
annotation_objects_list =
crashpad_info->GetModuleCrashpadInfoAnnotationObjects();
ASSERT_EQ(2U, annotation_objects_list->size());

std::vector<MinidumpCrashpadInfo::AnnotationObject> annotation_objects =
annotation_objects_list->at(0);
ASSERT_EQ(5U, annotation_objects.size());

std::vector<std::string> annotation_names;
for (size_t i = 0; i < annotation_objects.size(); i++) {
MinidumpCrashpadInfo::AnnotationObject annotation_object =
annotation_objects.at(i);
annotation_names.push_back(annotation_object.name);
ASSERT_TRUE(annotation_object.type > 0);
ASSERT_TRUE(annotation_object.value.size() > 0);
}

std::vector<std::string> expected_strings{
"exceptionReason", "exceptionName", "firstexception_bt", "firstexception",
"CounterAnnotation"};
ASSERT_EQ(annotation_names, expected_strings);
}

TEST(Dump, ReadBackEmpty) {
Dump dump(0);
dump.Finish();
Expand Down
Binary file not shown.

0 comments on commit a4f148b

Please sign in to comment.