Add support for reading annotation objects in Crashpad modules

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 <jperaza@chromium.org>
This commit is contained in:
Zaid Elkurdi
2023-01-25 15:56:36 -08:00
committed by Joshua Peraza
parent 2c86c995b4
commit a4f148b7a5
5 changed files with 155 additions and 0 deletions

View File

@@ -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++) {
@@ -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_() {
}
@@ -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;
@@ -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);
}
}
@@ -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) {

View File

@@ -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;
@@ -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();

Binary file not shown.