aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZaid Elkurdi <elkurdi@google.com>2023-01-25 15:56:36 -0800
committerJoshua Peraza <jperaza@chromium.org>2023-01-26 20:22:33 +0000
commita4f148b7a5003e2e6e76a92d8a5f65c8f7137b04 (patch)
treec8ac02ac57a472d92b2442b65b2ee98ea0431a78
parent2c86c995b4339751e6642e622e330eef86069a28 (diff)
downloadgoogle-breakpad-a4f148b7a5003e2e6e76a92d8a5f65c8f7137b04.tar.gz
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>
-rw-r--r--src/google_breakpad/common/minidump_format.h13
-rw-r--r--src/google_breakpad/processor/minidump.h18
-rw-r--r--src/processor/minidump.cc87
-rw-r--r--src/processor/minidump_unittest.cc37
-rw-r--r--src/processor/testdata/minidump_crashpad_annotation.dmpbin0 -> 332000 bytes
5 files changed, 155 insertions, 0 deletions
diff --git a/src/google_breakpad/common/minidump_format.h b/src/google_breakpad/common/minidump_format.h
index 42bfca94..1526afce 100644
--- a/src/google_breakpad/common/minidump_format.h
+++ b/src/google_breakpad/common/minidump_format.h
@@ -1097,9 +1097,22 @@ typedef struct {
} 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 {
diff --git a/src/google_breakpad/processor/minidump.h b/src/google_breakpad/processor/minidump.h
index 54d28817..934a0e3e 100644
--- a/src/google_breakpad/processor/minidump.h
+++ b/src/google_breakpad/processor/minidump.h
@@ -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();
@@ -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_;
};
@@ -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
diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc
index bfac6cb1..135770d5 100644
--- a/src/processor/minidump.cc
+++ b/src/processor/minidump.cc
@@ -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) {
diff --git a/src/processor/minidump_unittest.cc b/src/processor/minidump_unittest.cc
index 9936a7e4..53d44ae1 100644
--- a/src/processor/minidump_unittest.cc
+++ b/src/processor/minidump_unittest.cc
@@ -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();
diff --git a/src/processor/testdata/minidump_crashpad_annotation.dmp b/src/processor/testdata/minidump_crashpad_annotation.dmp
new file mode 100644
index 00000000..00cfc5a3
--- /dev/null
+++ b/src/processor/testdata/minidump_crashpad_annotation.dmp
Binary files differ