Add support for reading annotation objects in ModuleSnapshotMinidump.
This will be used to include the annotations as form-post data when uploading reports. Bug: crashpad:192 Change-Id: I85ba9afd3cae7c96c0f8fe4f31a2460c97ed42d3 Reviewed-on: https://chromium-review.googlesource.com/747514 Commit-Queue: Robert Sesek <rsesek@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Родитель
e38c57a9c6
Коммит
620a29dbf3
|
@ -0,0 +1,119 @@
|
|||
// Copyright 2017 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "snapshot/minidump/minidump_annotation_reader.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "minidump/minidump_extensions.h"
|
||||
#include "snapshot/minidump/minidump_string_reader.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
bool ReadMinidumpByteArray(FileReaderInterface* file_reader,
|
||||
RVA rva,
|
||||
std::vector<uint8_t>* data) {
|
||||
if (rva == 0) {
|
||||
data->clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!file_reader->SeekSet(rva)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t length;
|
||||
if (!file_reader->ReadExactly(&length, sizeof(length))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> local_data(length);
|
||||
if (!file_reader->ReadExactly(local_data.data(), length)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data->swap(local_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool ReadMinidumpAnnotationList(FileReaderInterface* file_reader,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location,
|
||||
std::vector<AnnotationSnapshot>* list) {
|
||||
if (location.Rva == 0) {
|
||||
list->clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (location.DataSize < sizeof(MinidumpAnnotationList)) {
|
||||
LOG(ERROR) << "annotation list size mismatch";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file_reader->SeekSet(location.Rva)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t count;
|
||||
if (!file_reader->ReadExactly(&count, sizeof(count))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (location.DataSize !=
|
||||
sizeof(MinidumpAnnotationList) + count * sizeof(MinidumpAnnotation)) {
|
||||
LOG(ERROR) << "annotation object size mismatch";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<MinidumpAnnotation> minidump_annotations(count);
|
||||
if (!file_reader->ReadExactly(minidump_annotations.data(),
|
||||
count * sizeof(MinidumpAnnotation))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<AnnotationSnapshot> annotations;
|
||||
annotations.reserve(count);
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
const MinidumpAnnotation* minidump_annotation = &minidump_annotations[i];
|
||||
|
||||
AnnotationSnapshot annotation;
|
||||
// The client-exposed size of this field is 16-bit, but the minidump field
|
||||
// is 32-bit for padding. Take just the lower part.
|
||||
annotation.type = static_cast<uint16_t>(minidump_annotation->type);
|
||||
|
||||
if (!ReadMinidumpUTF8String(
|
||||
file_reader, minidump_annotation->name, &annotation.name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ReadMinidumpByteArray(
|
||||
file_reader, minidump_annotation->value, &annotation.value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
annotations.push_back(std::move(annotation));
|
||||
}
|
||||
|
||||
list->swap(annotations);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2017 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SNAPSHOT_MINIDUMP_MINIDUMP_ANNOTATION_READER_H_
|
||||
#define SNAPSHOT_MINIDUMP_MINIDUMP_ANNOTATION_READER_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "snapshot/annotation_snapshot.h"
|
||||
#include "util/file/file_reader.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
//! \brief Reads a MinidumpAnnotationList from a minidump file at \a location
|
||||
//! in \a file_reader, and returns it in \a list.
|
||||
//!
|
||||
//! \return `true` on success, with \a list set by replacing its contents.
|
||||
//! `false` on failure, with a message logged.
|
||||
bool ReadMinidumpAnnotationList(FileReaderInterface* file_reader,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location,
|
||||
std::vector<AnnotationSnapshot>* list);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // SNAPSHOT_MINIDUMP_MINIDUMP_ANNOTATION_READER_H_
|
|
@ -15,6 +15,7 @@
|
|||
#include "snapshot/minidump/module_snapshot_minidump.h"
|
||||
|
||||
#include "minidump/minidump_extensions.h"
|
||||
#include "snapshot/minidump/minidump_annotation_reader.h"
|
||||
#include "snapshot/minidump/minidump_simple_string_dictionary_reader.h"
|
||||
#include "snapshot/minidump/minidump_string_list_reader.h"
|
||||
|
||||
|
@ -138,8 +139,7 @@ ModuleSnapshotMinidump::AnnotationsSimpleMap() const {
|
|||
std::vector<AnnotationSnapshot> ModuleSnapshotMinidump::AnnotationObjects()
|
||||
const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
NOTREACHED();
|
||||
return {};
|
||||
return annotation_objects_;
|
||||
}
|
||||
|
||||
std::set<CheckedRange<uint64_t>> ModuleSnapshotMinidump::ExtraMemoryRanges()
|
||||
|
@ -193,10 +193,21 @@ bool ModuleSnapshotMinidump::InitializeModuleCrashpadInfo(
|
|||
return false;
|
||||
}
|
||||
|
||||
return ReadMinidumpSimpleStringDictionary(
|
||||
file_reader,
|
||||
minidump_module_crashpad_info.simple_annotations,
|
||||
&annotations_simple_map_);
|
||||
if (!ReadMinidumpSimpleStringDictionary(
|
||||
file_reader,
|
||||
minidump_module_crashpad_info.simple_annotations,
|
||||
&annotations_simple_map_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ReadMinidumpAnnotationList(
|
||||
file_reader,
|
||||
minidump_module_crashpad_info.annotation_objects,
|
||||
&annotation_objects_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "snapshot/annotation_snapshot.h"
|
||||
#include "snapshot/module_snapshot.h"
|
||||
#include "util/file/file_reader.h"
|
||||
#include "util/misc/initialization_state_dcheck.h"
|
||||
|
@ -90,6 +91,7 @@ class ModuleSnapshotMinidump final : public ModuleSnapshot {
|
|||
MINIDUMP_MODULE minidump_module_;
|
||||
std::vector<std::string> annotations_vector_;
|
||||
std::map<std::string, std::string> annotations_simple_map_;
|
||||
std::vector<AnnotationSnapshot> annotation_objects_;
|
||||
InitializationStateDcheck initialized_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ModuleSnapshotMinidump);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <memory>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "snapshot/minidump/minidump_annotation_reader.h"
|
||||
#include "snapshot/module_snapshot.h"
|
||||
#include "util/file/string_file.h"
|
||||
|
||||
|
@ -66,7 +67,7 @@ TEST(ProcessSnapshotMinidump, Empty) {
|
|||
}
|
||||
|
||||
// Writes |string| to |writer| as a MinidumpUTF8String, and returns the file
|
||||
// offst of the beginning of the string.
|
||||
// offset of the beginning of the string.
|
||||
RVA WriteString(FileWriterInterface* writer, const std::string& string) {
|
||||
RVA rva = static_cast<RVA>(writer->SeekGet());
|
||||
|
||||
|
@ -131,6 +132,48 @@ void WriteMinidumpStringList(MINIDUMP_LOCATION_DESCRIPTOR* location,
|
|||
rvas.size() * sizeof(RVA));
|
||||
}
|
||||
|
||||
// Writes |data| to |writer| as a MinidumpByteArray, and returns the file offset
|
||||
// from the beginning of the string.
|
||||
RVA WriteByteArray(FileWriterInterface* writer,
|
||||
const std::vector<uint8_t> data) {
|
||||
auto rva = static_cast<RVA>(writer->SeekGet());
|
||||
|
||||
auto length = static_cast<uint32_t>(data.size());
|
||||
EXPECT_TRUE(writer->Write(&length, sizeof(length)));
|
||||
EXPECT_TRUE(writer->Write(data.data(), length));
|
||||
|
||||
return rva;
|
||||
}
|
||||
|
||||
// Writes |annotations| to |writer| as a MinidumpAnnotationList, and populates
|
||||
// |location| with a location descriptor identifying what was written.
|
||||
void WriteMinidumpAnnotationList(
|
||||
MINIDUMP_LOCATION_DESCRIPTOR* location,
|
||||
FileWriterInterface* writer,
|
||||
const std::vector<AnnotationSnapshot>& annotations) {
|
||||
std::vector<MinidumpAnnotation> minidump_annotations;
|
||||
for (const auto& it : annotations) {
|
||||
MinidumpAnnotation annotation;
|
||||
annotation.name = WriteString(writer, it.name);
|
||||
annotation.type = it.type;
|
||||
annotation.reserved = 0;
|
||||
annotation.value = WriteByteArray(writer, it.value);
|
||||
minidump_annotations.push_back(annotation);
|
||||
}
|
||||
|
||||
location->Rva = static_cast<RVA>(writer->SeekGet());
|
||||
|
||||
auto count = static_cast<uint32_t>(minidump_annotations.size());
|
||||
EXPECT_TRUE(writer->Write(&count, sizeof(count)));
|
||||
|
||||
for (const auto& it : minidump_annotations) {
|
||||
EXPECT_TRUE(writer->Write(&it, sizeof(MinidumpAnnotation)));
|
||||
}
|
||||
|
||||
location->DataSize =
|
||||
sizeof(MinidumpAnnotationList) + count * sizeof(MinidumpAnnotation);
|
||||
}
|
||||
|
||||
TEST(ProcessSnapshotMinidump, ClientID) {
|
||||
StringFile string_file;
|
||||
|
||||
|
@ -215,6 +258,28 @@ TEST(ProcessSnapshotMinidump, AnnotationsSimpleMap) {
|
|||
EXPECT_EQ(annotations_simple_map, dictionary);
|
||||
}
|
||||
|
||||
TEST(ProcessSnapshotMinidump, AnnotationObjects) {
|
||||
StringFile string_file;
|
||||
|
||||
MINIDUMP_HEADER header{};
|
||||
EXPECT_TRUE(string_file.Write(&header, sizeof(header)));
|
||||
|
||||
std::vector<AnnotationSnapshot> annotations;
|
||||
annotations.emplace_back(
|
||||
AnnotationSnapshot("name 1", 0xBBBB, {'t', 'e', '\0', 's', 't', '\0'}));
|
||||
annotations.emplace_back(
|
||||
AnnotationSnapshot("name 2", 0xABBA, {0xF0, 0x9F, 0x92, 0x83}));
|
||||
|
||||
MINIDUMP_LOCATION_DESCRIPTOR location;
|
||||
WriteMinidumpAnnotationList(&location, &string_file, annotations);
|
||||
|
||||
std::vector<AnnotationSnapshot> read_annotations;
|
||||
EXPECT_TRUE(internal::ReadMinidumpAnnotationList(
|
||||
&string_file, location, &read_annotations));
|
||||
|
||||
EXPECT_EQ(read_annotations, annotations);
|
||||
}
|
||||
|
||||
TEST(ProcessSnapshotMinidump, Modules) {
|
||||
StringFile string_file;
|
||||
|
||||
|
@ -222,7 +287,7 @@ TEST(ProcessSnapshotMinidump, Modules) {
|
|||
EXPECT_TRUE(string_file.Write(&header, sizeof(header)));
|
||||
|
||||
MINIDUMP_MODULE minidump_module = {};
|
||||
uint32_t minidump_module_count = 3;
|
||||
uint32_t minidump_module_count = 4;
|
||||
|
||||
MINIDUMP_DIRECTORY minidump_module_list_directory = {};
|
||||
minidump_module_list_directory.StreamType = kMinidumpStreamTypeModuleList;
|
||||
|
@ -273,10 +338,26 @@ TEST(ProcessSnapshotMinidump, Modules) {
|
|||
crashpad_module_2_link.location.Rva = static_cast<RVA>(string_file.SeekGet());
|
||||
EXPECT_TRUE(string_file.Write(&crashpad_module_2, sizeof(crashpad_module_2)));
|
||||
|
||||
MinidumpModuleCrashpadInfo crashpad_module_4 = {};
|
||||
crashpad_module_4.version = MinidumpModuleCrashpadInfo::kVersion;
|
||||
std::vector<AnnotationSnapshot> annotations_4{
|
||||
{"first one", 0xBADE, {'a', 'b', 'c'}},
|
||||
{"2", 0xEDD1, {0x11, 0x22, 0x33}},
|
||||
{"threeeeee", 0xDADA, {'f'}},
|
||||
};
|
||||
WriteMinidumpAnnotationList(
|
||||
&crashpad_module_4.annotation_objects, &string_file, annotations_4);
|
||||
|
||||
MinidumpModuleCrashpadInfoLink crashpad_module_4_link = {};
|
||||
crashpad_module_4_link.minidump_module_list_index = 3;
|
||||
crashpad_module_4_link.location.DataSize = sizeof(crashpad_module_4);
|
||||
crashpad_module_4_link.location.Rva = static_cast<RVA>(string_file.SeekGet());
|
||||
EXPECT_TRUE(string_file.Write(&crashpad_module_4, sizeof(crashpad_module_4)));
|
||||
|
||||
MinidumpCrashpadInfo crashpad_info = {};
|
||||
crashpad_info.version = MinidumpCrashpadInfo::kVersion;
|
||||
|
||||
uint32_t crashpad_module_count = 2;
|
||||
uint32_t crashpad_module_count = 3;
|
||||
|
||||
crashpad_info.module_list.DataSize =
|
||||
sizeof(MinidumpModuleCrashpadInfoList) +
|
||||
|
@ -289,6 +370,8 @@ TEST(ProcessSnapshotMinidump, Modules) {
|
|||
sizeof(crashpad_module_0_link)));
|
||||
EXPECT_TRUE(string_file.Write(&crashpad_module_2_link,
|
||||
sizeof(crashpad_module_2_link)));
|
||||
EXPECT_TRUE(string_file.Write(&crashpad_module_4_link,
|
||||
sizeof(crashpad_module_4_link)));
|
||||
|
||||
MINIDUMP_DIRECTORY crashpad_info_directory = {};
|
||||
crashpad_info_directory.StreamType = kMinidumpStreamTypeCrashpadInfo;
|
||||
|
@ -332,6 +415,9 @@ TEST(ProcessSnapshotMinidump, Modules) {
|
|||
|
||||
annotations_vector = modules[2]->AnnotationsVector();
|
||||
EXPECT_EQ(annotations_vector, list_annotations_2);
|
||||
|
||||
auto annotation_objects = modules[3]->AnnotationObjects();
|
||||
EXPECT_EQ(annotation_objects, annotations_4);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -101,6 +101,8 @@
|
|||
'mac/thread_snapshot_mac.cc',
|
||||
'mac/thread_snapshot_mac.h',
|
||||
'memory_snapshot.h',
|
||||
'minidump/minidump_annotation_reader.cc',
|
||||
'minidump/minidump_annotation_reader.h',
|
||||
'minidump/minidump_simple_string_dictionary_reader.cc',
|
||||
'minidump/minidump_simple_string_dictionary_reader.h',
|
||||
'minidump/minidump_string_list_reader.cc',
|
||||
|
|
Загрузка…
Ссылка в новой задаче