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:
Robert Sesek 2017-11-01 16:24:09 -04:00 коммит произвёл Commit Bot
Родитель e38c57a9c6
Коммит 620a29dbf3
6 изменённых файлов: 270 добавлений и 9 удалений

Просмотреть файл

@ -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',