mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
Add CodeViewRecordBuildId
Until now we've been stuffing ELF debug symbol link information into a CodeViewPDB70. This has reached the limits of its usefulness. We now add a CodeViewRecord that can contain a proper ELF build ID. Change-Id: Ice52cb2a958a1b9031943f280d9054da02d2f17d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1574107 Commit-Queue: Casey Dahlin <sadmac@google.com> Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
a7859e9bc6
commit
5f77cf41b6
@ -31,8 +31,7 @@
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
MinidumpModuleCodeViewRecordWriter::~MinidumpModuleCodeViewRecordWriter() {
|
||||
}
|
||||
MinidumpModuleCodeViewRecordWriter::~MinidumpModuleCodeViewRecordWriter() {}
|
||||
|
||||
namespace internal {
|
||||
|
||||
@ -45,8 +44,7 @@ MinidumpModuleCodeViewRecordPDBLinkWriter<
|
||||
|
||||
template <typename CodeViewRecordType>
|
||||
MinidumpModuleCodeViewRecordPDBLinkWriter<
|
||||
CodeViewRecordType>::~MinidumpModuleCodeViewRecordPDBLinkWriter() {
|
||||
}
|
||||
CodeViewRecordType>::~MinidumpModuleCodeViewRecordPDBLinkWriter() {}
|
||||
|
||||
template <typename CodeViewRecordType>
|
||||
size_t
|
||||
@ -82,8 +80,7 @@ template class internal::MinidumpModuleCodeViewRecordPDBLinkWriter<
|
||||
CodeViewRecordPDB20>;
|
||||
|
||||
MinidumpModuleCodeViewRecordPDB20Writer::
|
||||
~MinidumpModuleCodeViewRecordPDB20Writer() {
|
||||
}
|
||||
~MinidumpModuleCodeViewRecordPDB20Writer() {}
|
||||
|
||||
void MinidumpModuleCodeViewRecordPDB20Writer::SetTimestampAndAge(
|
||||
time_t timestamp,
|
||||
@ -100,8 +97,7 @@ template class internal::MinidumpModuleCodeViewRecordPDBLinkWriter<
|
||||
CodeViewRecordPDB70>;
|
||||
|
||||
MinidumpModuleCodeViewRecordPDB70Writer::
|
||||
~MinidumpModuleCodeViewRecordPDB70Writer() {
|
||||
}
|
||||
~MinidumpModuleCodeViewRecordPDB70Writer() {}
|
||||
|
||||
void MinidumpModuleCodeViewRecordPDB70Writer::InitializeFromSnapshot(
|
||||
const ModuleSnapshot* module_snapshot) {
|
||||
@ -115,15 +111,52 @@ void MinidumpModuleCodeViewRecordPDB70Writer::InitializeFromSnapshot(
|
||||
SetUUIDAndAge(uuid, age);
|
||||
}
|
||||
|
||||
MinidumpModuleCodeViewRecordBuildIDWriter::
|
||||
MinidumpModuleCodeViewRecordBuildIDWriter()
|
||||
: MinidumpModuleCodeViewRecordWriter(), build_id_() {}
|
||||
|
||||
MinidumpModuleCodeViewRecordBuildIDWriter::
|
||||
~MinidumpModuleCodeViewRecordBuildIDWriter() {}
|
||||
|
||||
size_t MinidumpModuleCodeViewRecordBuildIDWriter::SizeOfObject() {
|
||||
DCHECK_GE(state(), kStateFrozen);
|
||||
return offsetof(CodeViewRecordBuildID, build_id) + build_id_.size();
|
||||
}
|
||||
|
||||
void MinidumpModuleCodeViewRecordBuildIDWriter::SetBuildID(
|
||||
const std::vector<uint8_t>& build_id) {
|
||||
DCHECK_EQ(state(), kStateMutable);
|
||||
build_id_ = build_id;
|
||||
}
|
||||
|
||||
bool MinidumpModuleCodeViewRecordBuildIDWriter::WriteObject(
|
||||
FileWriterInterface* file_writer) {
|
||||
DCHECK_EQ(state(), kStateWritable);
|
||||
|
||||
CodeViewRecordBuildID cv;
|
||||
cv.signature = CodeViewRecordBuildID::kSignature;
|
||||
|
||||
WritableIoVec iov;
|
||||
iov.iov_base = &cv;
|
||||
iov.iov_len = offsetof(CodeViewRecordBuildID, build_id);
|
||||
std::vector<WritableIoVec> iovecs(1, iov);
|
||||
|
||||
if (!build_id_.empty()) {
|
||||
iov.iov_base = build_id_.data();
|
||||
iov.iov_len = build_id_.size();
|
||||
iovecs.push_back(iov);
|
||||
}
|
||||
|
||||
return file_writer->WriteIoVec(&iovecs);
|
||||
}
|
||||
|
||||
MinidumpModuleMiscDebugRecordWriter::MinidumpModuleMiscDebugRecordWriter()
|
||||
: internal::MinidumpWritable(),
|
||||
image_debug_misc_(),
|
||||
data_(),
|
||||
data_utf16_() {
|
||||
}
|
||||
data_utf16_() {}
|
||||
|
||||
MinidumpModuleMiscDebugRecordWriter::~MinidumpModuleMiscDebugRecordWriter() {
|
||||
}
|
||||
MinidumpModuleMiscDebugRecordWriter::~MinidumpModuleMiscDebugRecordWriter() {}
|
||||
|
||||
void MinidumpModuleMiscDebugRecordWriter::SetData(const std::string& data,
|
||||
bool utf16) {
|
||||
@ -203,8 +236,7 @@ MinidumpModuleWriter::MinidumpModuleWriter()
|
||||
module_.VersionInfo.dwStrucVersion = VS_FFI_STRUCVERSION;
|
||||
}
|
||||
|
||||
MinidumpModuleWriter::~MinidumpModuleWriter() {
|
||||
}
|
||||
MinidumpModuleWriter::~MinidumpModuleWriter() {}
|
||||
|
||||
void MinidumpModuleWriter::InitializeFromSnapshot(
|
||||
const ModuleSnapshot* module_snapshot) {
|
||||
@ -242,9 +274,21 @@ void MinidumpModuleWriter::InitializeFromSnapshot(
|
||||
}
|
||||
SetFileTypeAndSubtype(file_type, VFT2_UNKNOWN);
|
||||
|
||||
auto codeview_record =
|
||||
auto build_id = module_snapshot->BuildID();
|
||||
|
||||
std::unique_ptr<MinidumpModuleCodeViewRecordWriter> codeview_record;
|
||||
if (!build_id.empty()) {
|
||||
auto cv_record_build_id =
|
||||
std::make_unique<MinidumpModuleCodeViewRecordBuildIDWriter>();
|
||||
cv_record_build_id->SetBuildID(build_id);
|
||||
codeview_record = std::move(cv_record_build_id);
|
||||
} else {
|
||||
auto cv_record_pdb70 =
|
||||
std::make_unique<MinidumpModuleCodeViewRecordPDB70Writer>();
|
||||
codeview_record->InitializeFromSnapshot(module_snapshot);
|
||||
cv_record_pdb70->InitializeFromSnapshot(module_snapshot);
|
||||
codeview_record = std::move(cv_record_pdb70);
|
||||
}
|
||||
|
||||
SetCodeViewRecord(std::move(codeview_record));
|
||||
}
|
||||
|
||||
@ -372,11 +416,9 @@ bool MinidumpModuleWriter::WriteObject(FileWriterInterface* file_writer) {
|
||||
}
|
||||
|
||||
MinidumpModuleListWriter::MinidumpModuleListWriter()
|
||||
: MinidumpStreamWriter(), modules_(), module_list_base_() {
|
||||
}
|
||||
: MinidumpStreamWriter(), modules_(), module_list_base_() {}
|
||||
|
||||
MinidumpModuleListWriter::~MinidumpModuleListWriter() {
|
||||
}
|
||||
MinidumpModuleListWriter::~MinidumpModuleListWriter() {}
|
||||
|
||||
void MinidumpModuleListWriter::InitializeFromSnapshot(
|
||||
const std::vector<const ModuleSnapshot*>& module_snapshots) {
|
||||
|
@ -88,7 +88,8 @@ class MinidumpModuleCodeViewRecordPDBLinkWriter
|
||||
|
||||
//! \brief The writer for a CodeViewRecordPDB20 object in a minidump file.
|
||||
//!
|
||||
//! Most users will want MinidumpModuleCodeViewRecordPDB70Writer instead.
|
||||
//! Most users will want MinidumpModuleCodeViewRecordPDB70Writer or
|
||||
//! MinidumpModuleCodeViewRecordBuildIDWriter instead.
|
||||
class MinidumpModuleCodeViewRecordPDB20Writer final
|
||||
: public internal::MinidumpModuleCodeViewRecordPDBLinkWriter<
|
||||
CodeViewRecordPDB20> {
|
||||
@ -136,6 +137,26 @@ class MinidumpModuleCodeViewRecordPDB70Writer final
|
||||
DISALLOW_COPY_AND_ASSIGN(MinidumpModuleCodeViewRecordPDB70Writer);
|
||||
};
|
||||
|
||||
//! \brief The writer for a CodeViewRecordBuildID object in a minidump file.
|
||||
class MinidumpModuleCodeViewRecordBuildIDWriter final
|
||||
: public MinidumpModuleCodeViewRecordWriter {
|
||||
public:
|
||||
MinidumpModuleCodeViewRecordBuildIDWriter();
|
||||
~MinidumpModuleCodeViewRecordBuildIDWriter() override;
|
||||
|
||||
//! \brief Sets the build ID used for symbol lookup.
|
||||
void SetBuildID(const std::vector<uint8_t>& build_id);
|
||||
|
||||
private:
|
||||
// MinidumpWritable:
|
||||
size_t SizeOfObject() override;
|
||||
bool WriteObject(FileWriterInterface* file_writer) override;
|
||||
|
||||
std::vector<uint8_t> build_id_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MinidumpModuleCodeViewRecordBuildIDWriter);
|
||||
};
|
||||
|
||||
//! \brief The writer for an IMAGE_DEBUG_MISC object in a minidump file.
|
||||
//!
|
||||
//! Most users will want MinidumpModuleCodeViewRecordPDB70Writer instead.
|
||||
|
@ -265,6 +265,61 @@ void ExpectModule(const MINIDUMP_MODULE* expected,
|
||||
expected_debug_utf16));
|
||||
}
|
||||
|
||||
// ExpectModuleWithBuildIDCv() is like ExpectModule( but expects the module to
|
||||
// have a BuildID CodeView Record.
|
||||
void ExpectModuleWithBuildIDCv(const MINIDUMP_MODULE* expected,
|
||||
const MINIDUMP_MODULE* observed,
|
||||
const std::string& file_contents,
|
||||
const std::string& expected_module_name,
|
||||
const std::vector<uint8_t>& expected_build_id) {
|
||||
EXPECT_EQ(observed->BaseOfImage, expected->BaseOfImage);
|
||||
EXPECT_EQ(observed->SizeOfImage, expected->SizeOfImage);
|
||||
EXPECT_EQ(observed->CheckSum, expected->CheckSum);
|
||||
EXPECT_EQ(observed->TimeDateStamp, expected->TimeDateStamp);
|
||||
EXPECT_EQ(observed->VersionInfo.dwSignature,
|
||||
implicit_cast<uint32_t>(VS_FFI_SIGNATURE));
|
||||
EXPECT_EQ(observed->VersionInfo.dwStrucVersion,
|
||||
implicit_cast<uint32_t>(VS_FFI_STRUCVERSION));
|
||||
EXPECT_EQ(observed->VersionInfo.dwFileVersionMS,
|
||||
expected->VersionInfo.dwFileVersionMS);
|
||||
EXPECT_EQ(observed->VersionInfo.dwFileVersionLS,
|
||||
expected->VersionInfo.dwFileVersionLS);
|
||||
EXPECT_EQ(observed->VersionInfo.dwProductVersionMS,
|
||||
expected->VersionInfo.dwProductVersionMS);
|
||||
EXPECT_EQ(observed->VersionInfo.dwProductVersionLS,
|
||||
expected->VersionInfo.dwProductVersionLS);
|
||||
EXPECT_EQ(observed->VersionInfo.dwFileFlagsMask,
|
||||
expected->VersionInfo.dwFileFlagsMask);
|
||||
EXPECT_EQ(observed->VersionInfo.dwFileFlags,
|
||||
expected->VersionInfo.dwFileFlags);
|
||||
EXPECT_EQ(observed->VersionInfo.dwFileOS, expected->VersionInfo.dwFileOS);
|
||||
EXPECT_EQ(observed->VersionInfo.dwFileType, expected->VersionInfo.dwFileType);
|
||||
EXPECT_EQ(observed->VersionInfo.dwFileSubtype,
|
||||
expected->VersionInfo.dwFileSubtype);
|
||||
EXPECT_EQ(observed->VersionInfo.dwFileDateMS,
|
||||
expected->VersionInfo.dwFileDateMS);
|
||||
EXPECT_EQ(observed->VersionInfo.dwFileDateLS,
|
||||
expected->VersionInfo.dwFileDateLS);
|
||||
EXPECT_EQ(observed->Reserved0, 0u);
|
||||
EXPECT_EQ(observed->Reserved1, 0u);
|
||||
|
||||
EXPECT_NE(observed->ModuleNameRva, 0u);
|
||||
base::string16 observed_module_name_utf16 =
|
||||
MinidumpStringAtRVAAsString(file_contents, observed->ModuleNameRva);
|
||||
base::string16 expected_module_name_utf16 =
|
||||
base::UTF8ToUTF16(expected_module_name);
|
||||
EXPECT_EQ(observed_module_name_utf16, expected_module_name_utf16);
|
||||
|
||||
const CodeViewRecordBuildID* codeview_build_id_record =
|
||||
MinidumpWritableAtLocationDescriptor<CodeViewRecordBuildID>(
|
||||
file_contents, observed->CvRecord);
|
||||
ASSERT_TRUE(codeview_build_id_record);
|
||||
EXPECT_EQ(memcmp(expected_build_id.data(),
|
||||
&codeview_build_id_record->build_id,
|
||||
expected_build_id.size()),
|
||||
0);
|
||||
}
|
||||
|
||||
TEST(MinidumpModuleWriter, EmptyModule) {
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
auto module_list_writer = std::make_unique<MinidumpModuleListWriter>();
|
||||
@ -325,9 +380,22 @@ TEST(MinidumpModuleWriter, OneModule) {
|
||||
constexpr uint32_t kFileType = VFT_DRV;
|
||||
constexpr uint32_t kFileSubtype = VFT2_DRV_KEYBOARD;
|
||||
static constexpr char kPDBName[] = "statical.pdb";
|
||||
static constexpr uint8_t kPDBUUIDBytes[16] =
|
||||
{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
|
||||
0x08, 0x19, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x7f};
|
||||
static constexpr uint8_t kPDBUUIDBytes[16] = {0xfe,
|
||||
0xdc,
|
||||
0xba,
|
||||
0x98,
|
||||
0x76,
|
||||
0x54,
|
||||
0x32,
|
||||
0x10,
|
||||
0x08,
|
||||
0x19,
|
||||
0x2a,
|
||||
0x3b,
|
||||
0x4c,
|
||||
0x5d,
|
||||
0x6e,
|
||||
0x7f};
|
||||
UUID pdb_uuid;
|
||||
pdb_uuid.InitializeFromBytes(kPDBUUIDBytes);
|
||||
constexpr uint32_t kPDBAge = 1;
|
||||
@ -471,6 +539,50 @@ TEST(MinidumpModuleWriter, OneModule_CodeViewUsesPDB20_MiscUsesUTF16) {
|
||||
kDebugUTF16));
|
||||
}
|
||||
|
||||
TEST(MinidumpModuleWriter, OneModule_CodeViewBuildID) {
|
||||
// MinidumpModuleWriter.OneModule tested with a BuildID CodeView
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
auto module_list_writer = std::make_unique<MinidumpModuleListWriter>();
|
||||
|
||||
static constexpr char kModuleName[] = "dinosaur";
|
||||
static constexpr char kBuildID[] =
|
||||
"averylonghashcodeormaybeitsjustrandomnumbershardtosay";
|
||||
|
||||
std::vector<uint8_t> build_id_data(kBuildID, kBuildID + 53);
|
||||
|
||||
auto module_writer = std::make_unique<MinidumpModuleWriter>();
|
||||
module_writer->SetName(kModuleName);
|
||||
|
||||
auto codeview_build_id_writer =
|
||||
std::make_unique<MinidumpModuleCodeViewRecordBuildIDWriter>();
|
||||
codeview_build_id_writer->SetBuildID(build_id_data);
|
||||
module_writer->SetCodeViewRecord(std::move(codeview_build_id_writer));
|
||||
|
||||
module_list_writer->AddModule(std::move(module_writer));
|
||||
ASSERT_TRUE(minidump_file_writer.AddStream(std::move(module_list_writer)));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
|
||||
ASSERT_GT(string_file.string().size(),
|
||||
sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) +
|
||||
sizeof(MINIDUMP_MODULE_LIST) + 1 * sizeof(MINIDUMP_MODULE));
|
||||
|
||||
const MINIDUMP_MODULE_LIST* module_list = nullptr;
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
GetModuleListStream(string_file.string(), &module_list));
|
||||
|
||||
EXPECT_EQ(module_list->NumberOfModules, 1u);
|
||||
|
||||
MINIDUMP_MODULE expected = {};
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(ExpectModuleWithBuildIDCv(&expected,
|
||||
&module_list->Modules[0],
|
||||
string_file.string(),
|
||||
kModuleName,
|
||||
build_id_data));
|
||||
}
|
||||
|
||||
TEST(MinidumpModuleWriter, ThreeModules) {
|
||||
// As good exercise, this test uses three modules, one with a PDB 7.0 link as
|
||||
// its CodeView record, one with no CodeView record, and one with a PDB 2.0
|
||||
@ -482,9 +594,22 @@ TEST(MinidumpModuleWriter, ThreeModules) {
|
||||
constexpr uint64_t kModuleBase0 = 0x100101000;
|
||||
constexpr uint32_t kModuleSize0 = 0xf000;
|
||||
static constexpr char kPDBName0[] = "main";
|
||||
static constexpr uint8_t kPDBUUIDBytes0[16] =
|
||||
{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11,
|
||||
0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99};
|
||||
static constexpr uint8_t kPDBUUIDBytes0[16] = {0xaa,
|
||||
0xbb,
|
||||
0xcc,
|
||||
0xdd,
|
||||
0xee,
|
||||
0xff,
|
||||
0x00,
|
||||
0x11,
|
||||
0x22,
|
||||
0x33,
|
||||
0x44,
|
||||
0x55,
|
||||
0x66,
|
||||
0x77,
|
||||
0x88,
|
||||
0x99};
|
||||
UUID pdb_uuid_0;
|
||||
pdb_uuid_0.InitializeFromBytes(kPDBUUIDBytes0);
|
||||
constexpr uint32_t kPDBAge0 = 0;
|
||||
@ -666,9 +791,22 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) {
|
||||
expect_modules[0].VersionInfo.dwFileType = VFT_APP;
|
||||
module_paths[0] = "/usr/bin/true";
|
||||
module_pdbs[0] = "true";
|
||||
static constexpr uint8_t kUUIDBytes0[16] =
|
||||
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
|
||||
static constexpr uint8_t kUUIDBytes0[16] = {0x00,
|
||||
0x11,
|
||||
0x22,
|
||||
0x33,
|
||||
0x44,
|
||||
0x55,
|
||||
0x66,
|
||||
0x77,
|
||||
0x88,
|
||||
0x99,
|
||||
0xaa,
|
||||
0xbb,
|
||||
0xcc,
|
||||
0xdd,
|
||||
0xee,
|
||||
0xff};
|
||||
uuids[0].InitializeFromBytes(kUUIDBytes0);
|
||||
ages[0] = 10;
|
||||
|
||||
@ -682,9 +820,22 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) {
|
||||
expect_modules[1].VersionInfo.dwFileType = VFT_DLL;
|
||||
module_paths[1] = "/usr/lib/libSystem.B.dylib";
|
||||
module_pdbs[1] = "libSystem.B.dylib.pdb";
|
||||
static constexpr uint8_t kUUIDBytes1[16] =
|
||||
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
|
||||
static constexpr uint8_t kUUIDBytes1[16] = {0x00,
|
||||
0x01,
|
||||
0x02,
|
||||
0x03,
|
||||
0x04,
|
||||
0x05,
|
||||
0x06,
|
||||
0x07,
|
||||
0x08,
|
||||
0x09,
|
||||
0x0a,
|
||||
0x0b,
|
||||
0x0c,
|
||||
0x0d,
|
||||
0x0e,
|
||||
0x0f};
|
||||
uuids[1].InitializeFromBytes(kUUIDBytes1);
|
||||
ages[1] = 20;
|
||||
|
||||
@ -698,9 +849,22 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) {
|
||||
expect_modules[2].VersionInfo.dwFileType = VFT_UNKNOWN;
|
||||
module_paths[2] = "/usr/lib/dyld";
|
||||
module_pdbs[2] = "/usr/lib/dyld.pdb";
|
||||
static constexpr uint8_t kUUIDBytes2[16] =
|
||||
{0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
|
||||
0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0};
|
||||
static constexpr uint8_t kUUIDBytes2[16] = {0xff,
|
||||
0xfe,
|
||||
0xfd,
|
||||
0xfc,
|
||||
0xfb,
|
||||
0xfa,
|
||||
0xf9,
|
||||
0xf8,
|
||||
0xf7,
|
||||
0xf6,
|
||||
0xf5,
|
||||
0xf4,
|
||||
0xf3,
|
||||
0xf2,
|
||||
0xf1,
|
||||
0xf0};
|
||||
uuids[2].InitializeFromBytes(kUUIDBytes2);
|
||||
ages[2] = 30;
|
||||
|
||||
|
@ -210,17 +210,13 @@ struct MinidumpMemoryInfoListTraits {
|
||||
struct MinidumpModuleCrashpadInfoListTraits {
|
||||
using ListType = MinidumpModuleCrashpadInfoList;
|
||||
enum : size_t { kElementSize = sizeof(MinidumpModuleCrashpadInfoLink) };
|
||||
static size_t ElementCount(const ListType* list) {
|
||||
return list->count;
|
||||
}
|
||||
static size_t ElementCount(const ListType* list) { return list->count; }
|
||||
};
|
||||
|
||||
struct MinidumpSimpleStringDictionaryListTraits {
|
||||
using ListType = MinidumpSimpleStringDictionary;
|
||||
enum : size_t { kElementSize = sizeof(MinidumpSimpleStringDictionaryEntry) };
|
||||
static size_t ElementCount(const ListType* list) {
|
||||
return list->count;
|
||||
}
|
||||
static size_t ElementCount(const ListType* list) { return list->count; }
|
||||
};
|
||||
|
||||
struct MinidumpAnnotationListObjectsTraits {
|
||||
@ -253,16 +249,18 @@ const typename T::ListType* MinidumpListAtLocationDescriptor(
|
||||
} // namespace
|
||||
|
||||
template <>
|
||||
const MINIDUMP_MEMORY_LIST* MinidumpWritableAtLocationDescriptor<
|
||||
MINIDUMP_MEMORY_LIST>(const std::string& file_contents,
|
||||
const MINIDUMP_MEMORY_LIST*
|
||||
MinidumpWritableAtLocationDescriptor<MINIDUMP_MEMORY_LIST>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
|
||||
return MinidumpListAtLocationDescriptor<MinidumpMemoryListTraits>(
|
||||
file_contents, location);
|
||||
}
|
||||
|
||||
template <>
|
||||
const MINIDUMP_MODULE_LIST* MinidumpWritableAtLocationDescriptor<
|
||||
MINIDUMP_MODULE_LIST>(const std::string& file_contents,
|
||||
const MINIDUMP_MODULE_LIST*
|
||||
MinidumpWritableAtLocationDescriptor<MINIDUMP_MODULE_LIST>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
|
||||
return MinidumpListAtLocationDescriptor<MinidumpModuleListTraits>(
|
||||
file_contents, location);
|
||||
@ -278,24 +276,27 @@ MinidumpWritableAtLocationDescriptor<MINIDUMP_UNLOADED_MODULE_LIST>(
|
||||
}
|
||||
|
||||
template <>
|
||||
const MINIDUMP_THREAD_LIST* MinidumpWritableAtLocationDescriptor<
|
||||
MINIDUMP_THREAD_LIST>(const std::string& file_contents,
|
||||
const MINIDUMP_THREAD_LIST*
|
||||
MinidumpWritableAtLocationDescriptor<MINIDUMP_THREAD_LIST>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
|
||||
return MinidumpListAtLocationDescriptor<MinidumpThreadListTraits>(
|
||||
file_contents, location);
|
||||
}
|
||||
|
||||
template <>
|
||||
const MINIDUMP_HANDLE_DATA_STREAM* MinidumpWritableAtLocationDescriptor<
|
||||
MINIDUMP_HANDLE_DATA_STREAM>(const std::string& file_contents,
|
||||
const MINIDUMP_HANDLE_DATA_STREAM*
|
||||
MinidumpWritableAtLocationDescriptor<MINIDUMP_HANDLE_DATA_STREAM>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
|
||||
return MinidumpListAtLocationDescriptor<MinidumpHandleDataStreamTraits>(
|
||||
file_contents, location);
|
||||
}
|
||||
|
||||
template <>
|
||||
const MINIDUMP_MEMORY_INFO_LIST* MinidumpWritableAtLocationDescriptor<
|
||||
MINIDUMP_MEMORY_INFO_LIST>(const std::string& file_contents,
|
||||
const MINIDUMP_MEMORY_INFO_LIST*
|
||||
MinidumpWritableAtLocationDescriptor<MINIDUMP_MEMORY_INFO_LIST>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
|
||||
return MinidumpListAtLocationDescriptor<MinidumpMemoryInfoListTraits>(
|
||||
file_contents, location);
|
||||
@ -357,29 +358,52 @@ const T* MinidumpCVPDBAtLocationDescriptor(
|
||||
} // namespace
|
||||
|
||||
template <>
|
||||
const CodeViewRecordPDB20* MinidumpWritableAtLocationDescriptor<
|
||||
CodeViewRecordPDB20>(const std::string& file_contents,
|
||||
const CodeViewRecordPDB20*
|
||||
MinidumpWritableAtLocationDescriptor<CodeViewRecordPDB20>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
|
||||
return MinidumpCVPDBAtLocationDescriptor<CodeViewRecordPDB20>(file_contents,
|
||||
location);
|
||||
}
|
||||
|
||||
template <>
|
||||
const CodeViewRecordPDB70* MinidumpWritableAtLocationDescriptor<
|
||||
CodeViewRecordPDB70>(const std::string& file_contents,
|
||||
const CodeViewRecordPDB70*
|
||||
MinidumpWritableAtLocationDescriptor<CodeViewRecordPDB70>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
|
||||
return MinidumpCVPDBAtLocationDescriptor<CodeViewRecordPDB70>(file_contents,
|
||||
location);
|
||||
}
|
||||
|
||||
TestUInt32MinidumpWritable::TestUInt32MinidumpWritable(uint32_t value)
|
||||
: MinidumpWritable(),
|
||||
value_(value) {
|
||||
template <>
|
||||
const CodeViewRecordBuildID*
|
||||
MinidumpWritableAtLocationDescriptor<CodeViewRecordBuildID>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location) {
|
||||
const CodeViewRecordBuildID* cv =
|
||||
reinterpret_cast<const CodeViewRecordBuildID*>(
|
||||
MinidumpWritableAtLocationDescriptorInternal(
|
||||
file_contents,
|
||||
location,
|
||||
offsetof(CodeViewRecordBuildID, build_id),
|
||||
true));
|
||||
|
||||
if (!cv) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TestUInt32MinidumpWritable::~TestUInt32MinidumpWritable() {
|
||||
if (cv->signature != CodeViewRecordBuildID::kSignature) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return cv;
|
||||
}
|
||||
|
||||
TestUInt32MinidumpWritable::TestUInt32MinidumpWritable(uint32_t value)
|
||||
: MinidumpWritable(), value_(value) {}
|
||||
|
||||
TestUInt32MinidumpWritable::~TestUInt32MinidumpWritable() {}
|
||||
|
||||
size_t TestUInt32MinidumpWritable::SizeOfObject() {
|
||||
return sizeof(value_);
|
||||
}
|
||||
|
@ -104,6 +104,7 @@ MINIDUMP_ALLOW_OVERSIZED_DATA(IMAGE_DEBUG_MISC);
|
||||
MINIDUMP_ALLOW_OVERSIZED_DATA(MINIDUMP_STRING);
|
||||
MINIDUMP_ALLOW_OVERSIZED_DATA(CodeViewRecordPDB20);
|
||||
MINIDUMP_ALLOW_OVERSIZED_DATA(CodeViewRecordPDB70);
|
||||
MINIDUMP_ALLOW_OVERSIZED_DATA(CodeViewRecordBuildID);
|
||||
MINIDUMP_ALLOW_OVERSIZED_DATA(MinidumpUTF8String);
|
||||
|
||||
// minidump_file_writer_test accesses its variable-sized test streams via a
|
||||
@ -179,13 +180,15 @@ const MINIDUMP_HEADER* MinidumpWritableAtLocationDescriptor<MINIDUMP_HEADER>(
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location);
|
||||
|
||||
template <>
|
||||
const MINIDUMP_MEMORY_LIST* MinidumpWritableAtLocationDescriptor<
|
||||
MINIDUMP_MEMORY_LIST>(const std::string& file_contents,
|
||||
const MINIDUMP_MEMORY_LIST*
|
||||
MinidumpWritableAtLocationDescriptor<MINIDUMP_MEMORY_LIST>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location);
|
||||
|
||||
template <>
|
||||
const MINIDUMP_MODULE_LIST* MinidumpWritableAtLocationDescriptor<
|
||||
MINIDUMP_MODULE_LIST>(const std::string& file_contents,
|
||||
const MINIDUMP_MODULE_LIST*
|
||||
MinidumpWritableAtLocationDescriptor<MINIDUMP_MODULE_LIST>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location);
|
||||
|
||||
template <>
|
||||
@ -195,28 +198,39 @@ MinidumpWritableAtLocationDescriptor<MINIDUMP_UNLOADED_MODULE_LIST>(
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location);
|
||||
|
||||
template <>
|
||||
const MINIDUMP_THREAD_LIST* MinidumpWritableAtLocationDescriptor<
|
||||
MINIDUMP_THREAD_LIST>(const std::string& file_contents,
|
||||
const MINIDUMP_THREAD_LIST*
|
||||
MinidumpWritableAtLocationDescriptor<MINIDUMP_THREAD_LIST>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location);
|
||||
|
||||
template <>
|
||||
const MINIDUMP_HANDLE_DATA_STREAM* MinidumpWritableAtLocationDescriptor<
|
||||
MINIDUMP_HANDLE_DATA_STREAM>(const std::string& file_contents,
|
||||
const MINIDUMP_HANDLE_DATA_STREAM*
|
||||
MinidumpWritableAtLocationDescriptor<MINIDUMP_HANDLE_DATA_STREAM>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location);
|
||||
|
||||
template <>
|
||||
const MINIDUMP_MEMORY_INFO_LIST* MinidumpWritableAtLocationDescriptor<
|
||||
MINIDUMP_MEMORY_INFO_LIST>(const std::string& file_contents,
|
||||
const MINIDUMP_MEMORY_INFO_LIST*
|
||||
MinidumpWritableAtLocationDescriptor<MINIDUMP_MEMORY_INFO_LIST>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location);
|
||||
|
||||
template <>
|
||||
const CodeViewRecordPDB20* MinidumpWritableAtLocationDescriptor<
|
||||
CodeViewRecordPDB20>(const std::string& file_contents,
|
||||
const CodeViewRecordPDB20*
|
||||
MinidumpWritableAtLocationDescriptor<CodeViewRecordPDB20>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location);
|
||||
|
||||
template <>
|
||||
const CodeViewRecordPDB70* MinidumpWritableAtLocationDescriptor<
|
||||
CodeViewRecordPDB70>(const std::string& file_contents,
|
||||
const CodeViewRecordPDB70*
|
||||
MinidumpWritableAtLocationDescriptor<CodeViewRecordPDB70>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location);
|
||||
|
||||
template <>
|
||||
const CodeViewRecordBuildID*
|
||||
MinidumpWritableAtLocationDescriptor<CodeViewRecordBuildID>(
|
||||
const std::string& file_contents,
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR& location);
|
||||
|
||||
template <>
|
||||
|
@ -150,13 +150,10 @@ void ModuleSnapshotElf::UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
*age = 0;
|
||||
|
||||
std::unique_ptr<ElfImageReader::NoteReader> notes =
|
||||
elf_reader_->NotesWithNameAndType(ELF_NOTE_GNU, NT_GNU_BUILD_ID, 64);
|
||||
std::string desc;
|
||||
VMAddress desc_addr;
|
||||
notes->NextNote(nullptr, nullptr, &desc, &desc_addr);
|
||||
desc.insert(desc.end(), 16 - std::min(desc.size(), size_t{16}), '\0');
|
||||
uuid->InitializeFromBytes(reinterpret_cast<const uint8_t*>(&desc[0]));
|
||||
auto build_id = BuildID();
|
||||
build_id.insert(
|
||||
build_id.end(), 16 - std::min(build_id.size(), size_t{16}), '\0');
|
||||
uuid->InitializeFromBytes(build_id.data());
|
||||
|
||||
// TODO(scottmg): https://crashpad.chromium.org/bug/229. These are
|
||||
// endian-swapped to match FileID::ConvertIdentifierToUUIDString() in
|
||||
@ -171,6 +168,21 @@ std::string ModuleSnapshotElf::DebugFileName() const {
|
||||
return base::FilePath(Name()).BaseName().value();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ModuleSnapshotElf::BuildID() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
std::unique_ptr<ElfImageReader::NoteReader> notes =
|
||||
elf_reader_->NotesWithNameAndType(ELF_NOTE_GNU, NT_GNU_BUILD_ID, 64);
|
||||
std::string desc;
|
||||
VMAddress desc_addr;
|
||||
notes->NextNote(nullptr, nullptr, &desc, &desc_addr);
|
||||
|
||||
std::vector<uint8_t> build_id;
|
||||
build_id.reserve(desc.size());
|
||||
std::copy(desc.begin(), desc.end(), std::back_inserter(build_id));
|
||||
return build_id;
|
||||
}
|
||||
|
||||
std::vector<std::string> ModuleSnapshotElf::AnnotationsVector() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return std::vector<std::string>();
|
||||
|
@ -77,6 +77,7 @@ class ModuleSnapshotElf final : public ModuleSnapshot {
|
||||
ModuleType GetModuleType() const override;
|
||||
void UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const override;
|
||||
std::string DebugFileName() const override;
|
||||
std::vector<uint8_t> BuildID() const override;
|
||||
std::vector<std::string> AnnotationsVector() const override;
|
||||
std::map<std::string, std::string> AnnotationsSimpleMap() const override;
|
||||
std::vector<AnnotationSnapshot> AnnotationObjects() const override;
|
||||
|
@ -14,8 +14,8 @@
|
||||
|
||||
#include "snapshot/mac/module_snapshot_mac.h"
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach/mach.h>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
@ -34,11 +34,9 @@ ModuleSnapshotMac::ModuleSnapshotMac()
|
||||
timestamp_(0),
|
||||
mach_o_image_reader_(nullptr),
|
||||
process_reader_(nullptr),
|
||||
initialized_() {
|
||||
}
|
||||
initialized_() {}
|
||||
|
||||
ModuleSnapshotMac::~ModuleSnapshotMac() {
|
||||
}
|
||||
ModuleSnapshotMac::~ModuleSnapshotMac() {}
|
||||
|
||||
bool ModuleSnapshotMac::Initialize(
|
||||
ProcessReaderMac* process_reader,
|
||||
@ -170,6 +168,11 @@ std::string ModuleSnapshotMac::DebugFileName() const {
|
||||
return base::FilePath(Name()).BaseName().value();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ModuleSnapshotMac::BuildID() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return std::vector<uint8_t>();
|
||||
}
|
||||
|
||||
std::vector<std::string> ModuleSnapshotMac::AnnotationsVector() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
MachOImageAnnotationsReader annotations_reader(
|
||||
|
@ -77,6 +77,7 @@ class ModuleSnapshotMac final : public ModuleSnapshot {
|
||||
ModuleType GetModuleType() const override;
|
||||
void UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const override;
|
||||
std::string DebugFileName() const override;
|
||||
std::vector<uint8_t> BuildID() const override;
|
||||
std::vector<std::string> AnnotationsVector() const override;
|
||||
std::map<std::string, std::string> AnnotationsSimpleMap() const override;
|
||||
std::vector<AnnotationSnapshot> AnnotationObjects() const override;
|
||||
|
@ -14,13 +14,15 @@
|
||||
|
||||
#include "snapshot/minidump/module_snapshot_minidump.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "minidump/minidump_extensions.h"
|
||||
#include "snapshot/minidump/minidump_annotation_reader.h"
|
||||
#include "snapshot/minidump/minidump_string_reader.h"
|
||||
#include "snapshot/minidump/minidump_simple_string_dictionary_reader.h"
|
||||
#include "snapshot/minidump/minidump_string_list_reader.h"
|
||||
#include "snapshot/minidump/minidump_string_reader.h"
|
||||
#include "util/misc/pdb_structures.h"
|
||||
|
||||
namespace crashpad {
|
||||
@ -33,13 +35,13 @@ ModuleSnapshotMinidump::ModuleSnapshotMinidump()
|
||||
annotations_simple_map_(),
|
||||
annotation_objects_(),
|
||||
uuid_(),
|
||||
build_id_(),
|
||||
name_(),
|
||||
debug_file_name_(),
|
||||
age_(0),
|
||||
initialized_() {
|
||||
}
|
||||
initialized_() {}
|
||||
|
||||
ModuleSnapshotMinidump::~ModuleSnapshotMinidump() {
|
||||
}
|
||||
ModuleSnapshotMinidump::~ModuleSnapshotMinidump() {}
|
||||
|
||||
bool ModuleSnapshotMinidump::Initialize(
|
||||
FileReaderInterface* file_reader,
|
||||
@ -63,31 +65,66 @@ bool ModuleSnapshotMinidump::Initialize(
|
||||
|
||||
ReadMinidumpUTF16String(file_reader, minidump_module_.ModuleNameRva, &name_);
|
||||
|
||||
if (minidump_module_.CvRecord.Rva != 0) {
|
||||
CodeViewRecordPDB70 cv;
|
||||
if (minidump_module_.CvRecord.Rva != 0 &&
|
||||
!InitializeModuleCodeView(file_reader)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModuleSnapshotMinidump::InitializeModuleCodeView(
|
||||
FileReaderInterface* file_reader) {
|
||||
uint32_t signature;
|
||||
|
||||
DCHECK_NE(minidump_module_.CvRecord.Rva, 0u);
|
||||
|
||||
if (minidump_module_.CvRecord.DataSize < sizeof(signature)) {
|
||||
LOG(ERROR) << "CodeView record in module too small to contain signature";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file_reader->SeekSet(minidump_module_.CvRecord.Rva)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file_reader->ReadExactly(&cv, sizeof(cv))) {
|
||||
std::vector<uint8_t> cv_record;
|
||||
cv_record.resize(minidump_module_.CvRecord.DataSize);
|
||||
|
||||
if (!file_reader->ReadExactly(cv_record.data(), cv_record.size())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cv.signature == 'SDSR') {
|
||||
age_ = cv.age;
|
||||
uuid_ = cv.uuid;
|
||||
} else if (cv.signature != '01BN') {
|
||||
signature = *reinterpret_cast<uint32_t*>(cv_record.data());
|
||||
|
||||
if (signature == CodeViewRecordPDB70::kSignature) {
|
||||
if (cv_record.size() < offsetof(CodeViewRecordPDB70, pdb_name)) {
|
||||
LOG(ERROR) << "CodeView record in module marked as PDB70 but too small";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto cv_record_pdb70 =
|
||||
reinterpret_cast<CodeViewRecordPDB70*>(cv_record.data());
|
||||
|
||||
age_ = cv_record_pdb70->age;
|
||||
uuid_ = cv_record_pdb70->uuid;
|
||||
|
||||
std::copy(cv_record.begin() + offsetof(CodeViewRecordPDB70, pdb_name),
|
||||
cv_record.end(),
|
||||
std::back_inserter(debug_file_name_));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (signature == CodeViewRecordBuildID::kSignature) {
|
||||
std::copy(cv_record.begin() + offsetof(CodeViewRecordBuildID, build_id),
|
||||
cv_record.end(),
|
||||
std::back_inserter(build_id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG(ERROR) << "Bad CodeView signature in module";
|
||||
return false;
|
||||
} else {
|
||||
LOG(ERROR) << "NB10 not supported";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string ModuleSnapshotMinidump::Name() const {
|
||||
@ -155,8 +192,12 @@ void ModuleSnapshotMinidump::UUIDAndAge(crashpad::UUID* uuid,
|
||||
|
||||
std::string ModuleSnapshotMinidump::DebugFileName() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
NOTREACHED(); // https://crashpad.chromium.org/bug/10
|
||||
return std::string();
|
||||
return debug_file_name_;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ModuleSnapshotMinidump::BuildID() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return build_id_;
|
||||
}
|
||||
|
||||
std::vector<std::string> ModuleSnapshotMinidump::AnnotationsVector() const {
|
||||
|
@ -75,6 +75,7 @@ class ModuleSnapshotMinidump final : public ModuleSnapshot {
|
||||
ModuleType GetModuleType() const override;
|
||||
void UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const override;
|
||||
std::string DebugFileName() const override;
|
||||
std::vector<uint8_t> BuildID() const override;
|
||||
std::vector<std::string> AnnotationsVector() const override;
|
||||
std::map<std::string, std::string> AnnotationsSimpleMap() const override;
|
||||
std::vector<AnnotationSnapshot> AnnotationObjects() const override;
|
||||
@ -88,12 +89,18 @@ class ModuleSnapshotMinidump final : public ModuleSnapshot {
|
||||
const MINIDUMP_LOCATION_DESCRIPTOR*
|
||||
minidump_module_crashpad_info_location);
|
||||
|
||||
// Initializes data from the CodeView record, which usually points toward
|
||||
// debug symbols.
|
||||
bool InitializeModuleCodeView(FileReaderInterface* file_reader);
|
||||
|
||||
MINIDUMP_MODULE minidump_module_;
|
||||
std::vector<std::string> annotations_vector_;
|
||||
std::map<std::string, std::string> annotations_simple_map_;
|
||||
std::vector<AnnotationSnapshot> annotation_objects_;
|
||||
UUID uuid_;
|
||||
std::vector<uint8_t> build_id_;
|
||||
std::string name_;
|
||||
std::string debug_file_name_;
|
||||
uint32_t age_;
|
||||
InitializationStateDcheck initialized_;
|
||||
|
||||
|
@ -331,16 +331,28 @@ TEST(ProcessSnapshotMinidump, Modules) {
|
||||
EXPECT_TRUE(string_file.Write(&name16[0], size));
|
||||
}
|
||||
|
||||
CodeViewRecordPDB70 cv;
|
||||
cv.signature = CodeViewRecordPDB70::kSignature;
|
||||
cv.age = 7;
|
||||
cv.uuid.InitializeFromString("00112233-4455-6677-8899-aabbccddeeff");
|
||||
cv.pdb_name[0] = '\0';
|
||||
CodeViewRecordPDB70 pdb70_cv;
|
||||
pdb70_cv.signature = CodeViewRecordPDB70::kSignature;
|
||||
pdb70_cv.age = 7;
|
||||
pdb70_cv.uuid.InitializeFromString("00112233-4455-6677-8899-aabbccddeeff");
|
||||
pdb70_cv.pdb_name[0] = '\0';
|
||||
|
||||
minidump_module.CvRecord.Rva = static_cast<RVA>(string_file.SeekGet());
|
||||
minidump_module.CvRecord.DataSize = sizeof(cv);
|
||||
auto pdb70_loc = static_cast<RVA>(string_file.SeekGet());
|
||||
auto pdb70_size = sizeof(pdb70_cv);
|
||||
|
||||
EXPECT_TRUE(string_file.Write(&cv, sizeof(cv)));
|
||||
EXPECT_TRUE(string_file.Write(&pdb70_cv, sizeof(pdb70_cv)));
|
||||
|
||||
CodeViewRecordBuildID build_id_cv;
|
||||
build_id_cv.signature = CodeViewRecordBuildID::kSignature;
|
||||
|
||||
auto build_id_cv_loc = static_cast<RVA>(string_file.SeekGet());
|
||||
|
||||
EXPECT_TRUE(string_file.Write(&build_id_cv,
|
||||
offsetof(CodeViewRecordBuildID, build_id)));
|
||||
EXPECT_TRUE(string_file.Write("atestbuildidbecausewhynot", 25));
|
||||
|
||||
auto build_id_cv_size =
|
||||
static_cast<size_t>(string_file.SeekGet() - build_id_cv_loc);
|
||||
|
||||
MINIDUMP_DIRECTORY minidump_module_list_directory = {};
|
||||
minidump_module_list_directory.StreamType = kMinidumpStreamTypeModuleList;
|
||||
@ -355,6 +367,15 @@ TEST(ProcessSnapshotMinidump, Modules) {
|
||||
for (uint32_t minidump_module_index = 0;
|
||||
minidump_module_index < minidump_module_count;
|
||||
++minidump_module_index) {
|
||||
if (minidump_module_index % 2) {
|
||||
minidump_module.CvRecord.Rva = pdb70_loc;
|
||||
minidump_module.CvRecord.DataSize = static_cast<uint32_t>(pdb70_size);
|
||||
} else {
|
||||
minidump_module.CvRecord.Rva = build_id_cv_loc;
|
||||
minidump_module.CvRecord.DataSize =
|
||||
static_cast<uint32_t>(build_id_cv_size);
|
||||
}
|
||||
|
||||
minidump_module.ModuleNameRva = name_rvas[minidump_module_index];
|
||||
EXPECT_TRUE(string_file.Write(&minidump_module, sizeof(minidump_module)));
|
||||
minidump_module.TimeDateStamp++;
|
||||
@ -479,12 +500,19 @@ TEST(ProcessSnapshotMinidump, Modules) {
|
||||
EXPECT_EQ(modules[i]->GetModuleType(),
|
||||
ModuleSnapshot::kModuleTypeExecutable);
|
||||
|
||||
if (i % 2) {
|
||||
uint32_t age;
|
||||
UUID uuid;
|
||||
modules[i]->UUIDAndAge(&uuid, &age);
|
||||
|
||||
EXPECT_EQ(uuid.ToString(), "00112233-4455-6677-8899-aabbccddeeff");
|
||||
EXPECT_EQ(age, 7U);
|
||||
} else {
|
||||
auto build_id = modules[i]->BuildID();
|
||||
std::string build_id_text(build_id.data(),
|
||||
build_id.data() + build_id.size());
|
||||
EXPECT_EQ(build_id_text, "atestbuildidbecausewhynot");
|
||||
}
|
||||
}
|
||||
|
||||
auto annotations_simple_map = modules[0]->AnnotationsSimpleMap();
|
||||
@ -626,8 +654,8 @@ TEST(ProcessSnapshotMinidump, System) {
|
||||
minidump_system_info_directory.Location.Rva =
|
||||
static_cast<RVA>(string_file.SeekGet());
|
||||
|
||||
ASSERT_TRUE(string_file.Write(&minidump_system_info,
|
||||
sizeof(minidump_system_info)));
|
||||
ASSERT_TRUE(
|
||||
string_file.Write(&minidump_system_info, sizeof(minidump_system_info)));
|
||||
|
||||
header.StreamDirectoryRva = static_cast<RVA>(string_file.SeekGet());
|
||||
ASSERT_TRUE(string_file.Write(&minidump_system_info_directory,
|
||||
@ -680,8 +708,8 @@ TEST(ProcessSnapshotMinidump, ThreadContextARM64) {
|
||||
minidump_system_info_directory.Location.Rva =
|
||||
static_cast<RVA>(string_file.SeekGet());
|
||||
|
||||
ASSERT_TRUE(string_file.Write(&minidump_system_info,
|
||||
sizeof(minidump_system_info)));
|
||||
ASSERT_TRUE(
|
||||
string_file.Write(&minidump_system_info, sizeof(minidump_system_info)));
|
||||
|
||||
MINIDUMP_THREAD minidump_thread = {};
|
||||
uint32_t minidump_thread_count = 1;
|
||||
@ -801,8 +829,8 @@ TEST(ProcessSnapshotMinidump, ThreadContextX86_64) {
|
||||
minidump_system_info_directory.Location.Rva =
|
||||
static_cast<RVA>(string_file.SeekGet());
|
||||
|
||||
ASSERT_TRUE(string_file.Write(&minidump_system_info,
|
||||
sizeof(minidump_system_info)));
|
||||
ASSERT_TRUE(
|
||||
string_file.Write(&minidump_system_info, sizeof(minidump_system_info)));
|
||||
|
||||
MINIDUMP_THREAD minidump_thread = {};
|
||||
uint32_t minidump_thread_count = 1;
|
||||
@ -1045,10 +1073,14 @@ TEST(ProcessSnapshotMinidump, MemoryMap) {
|
||||
std::vector<const MemoryMapRegionSnapshot*> map =
|
||||
process_snapshot.MemoryMap();
|
||||
ASSERT_EQ(map.size(), minidump_memory_info_count);
|
||||
EXPECT_EQ(memcmp(&map[0]->AsMinidumpMemoryInfo(), &minidump_memory_info_1,
|
||||
sizeof(minidump_memory_info_1)), 0);
|
||||
EXPECT_EQ(memcmp(&map[1]->AsMinidumpMemoryInfo(), &minidump_memory_info_2,
|
||||
sizeof(minidump_memory_info_2)), 0);
|
||||
EXPECT_EQ(memcmp(&map[0]->AsMinidumpMemoryInfo(),
|
||||
&minidump_memory_info_1,
|
||||
sizeof(minidump_memory_info_1)),
|
||||
0);
|
||||
EXPECT_EQ(memcmp(&map[1]->AsMinidumpMemoryInfo(),
|
||||
&minidump_memory_info_2,
|
||||
sizeof(minidump_memory_info_2)),
|
||||
0);
|
||||
}
|
||||
|
||||
TEST(ProcessSnapshotMinidump, Stacks) {
|
||||
@ -1063,9 +1095,21 @@ TEST(ProcessSnapshotMinidump, Stacks) {
|
||||
minidump_thread.ThreadId = 42;
|
||||
minidump_thread.Stack.StartOfMemoryRange = 0xbeefd00d;
|
||||
|
||||
std::vector<uint8_t> minidump_stack = {
|
||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||
};
|
||||
std::vector<uint8_t> minidump_stack = {'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'a',
|
||||
'b',
|
||||
'c',
|
||||
'd',
|
||||
'e',
|
||||
'f'};
|
||||
|
||||
minidump_thread.Stack.Memory.DataSize =
|
||||
base::checked_cast<uint32_t>(minidump_stack.size());
|
||||
|
@ -146,6 +146,7 @@ class ModuleSnapshot {
|
||||
//! Windows with incremental linking. On other platforms \a age will always be
|
||||
//! `0`.
|
||||
//!
|
||||
//! \sa BuildID()
|
||||
//! \sa DebugFileName()
|
||||
virtual void UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const = 0;
|
||||
|
||||
@ -159,6 +160,20 @@ class ModuleSnapshot {
|
||||
//! \sa UUIDAndAge()
|
||||
virtual std::string DebugFileName() const = 0;
|
||||
|
||||
//! \brief Returns the module’s build ID.
|
||||
//!
|
||||
//! On ELF platforms, the build ID is a variable-length byte stream that
|
||||
//! identifies a library uniquely, and is usually used to look up its debug
|
||||
//! symbols when stored separately. This will return an empty vector if it is
|
||||
//! unsupported.
|
||||
//!
|
||||
//! BuildID() and UUIDAndAge() are never available in the same place. When
|
||||
//! UUIDAndAge() is unavailable, it will be filled out with the contents of
|
||||
//! BuildID() (either 0-padded or truncated) and age will be zero.
|
||||
//!
|
||||
//! \sa UUIDAndAge()
|
||||
virtual std::vector<uint8_t> BuildID() const = 0;
|
||||
|
||||
//! \brief Returns string annotations recorded in the module.
|
||||
//!
|
||||
//! This method retrieves annotations recorded in a module. These annotations
|
||||
|
@ -81,6 +81,10 @@ std::string ModuleSnapshotSanitized::DebugFileName() const {
|
||||
return snapshot_->DebugFileName();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ModuleSnapshotSanitized::BuildID() const {
|
||||
return snapshot_->BuildID();
|
||||
}
|
||||
|
||||
std::vector<std::string> ModuleSnapshotSanitized::AnnotationsVector() const {
|
||||
// TODO(jperaza): If/when AnnotationsVector() begins to be used, determine
|
||||
// whether and how the content should be sanitized.
|
||||
|
@ -56,6 +56,7 @@ class ModuleSnapshotSanitized final : public ModuleSnapshot {
|
||||
ModuleType GetModuleType() const override;
|
||||
void UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const override;
|
||||
std::string DebugFileName() const override;
|
||||
std::vector<uint8_t> BuildID() const override;
|
||||
std::vector<std::string> AnnotationsVector() const override;
|
||||
std::map<std::string, std::string> AnnotationsSimpleMap() const override;
|
||||
std::vector<AnnotationSnapshot> AnnotationObjects() const override;
|
||||
|
@ -30,11 +30,9 @@ TestModuleSnapshot::TestModuleSnapshot()
|
||||
debug_file_name_(),
|
||||
annotations_vector_(),
|
||||
annotations_simple_map_(),
|
||||
extra_memory_ranges_() {
|
||||
}
|
||||
extra_memory_ranges_() {}
|
||||
|
||||
TestModuleSnapshot::~TestModuleSnapshot() {
|
||||
}
|
||||
TestModuleSnapshot::~TestModuleSnapshot() {}
|
||||
|
||||
std::string TestModuleSnapshot::Name() const {
|
||||
return name_;
|
||||
@ -85,6 +83,10 @@ std::string TestModuleSnapshot::DebugFileName() const {
|
||||
return debug_file_name_;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> TestModuleSnapshot::BuildID() const {
|
||||
return build_id_;
|
||||
}
|
||||
|
||||
std::vector<std::string> TestModuleSnapshot::AnnotationsVector() const {
|
||||
return annotations_vector_;
|
||||
}
|
||||
|
@ -64,6 +64,9 @@ class TestModuleSnapshot final : public ModuleSnapshot {
|
||||
uuid_ = uuid;
|
||||
age_ = age;
|
||||
}
|
||||
void SetBuildID(const std::vector<uint8_t>& build_id) {
|
||||
build_id_ = build_id;
|
||||
}
|
||||
void SetDebugFileName(const std::string& debug_file_name) {
|
||||
debug_file_name_ = debug_file_name;
|
||||
}
|
||||
@ -101,6 +104,7 @@ class TestModuleSnapshot final : public ModuleSnapshot {
|
||||
ModuleType GetModuleType() const override;
|
||||
void UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const override;
|
||||
std::string DebugFileName() const override;
|
||||
std::vector<uint8_t> BuildID() const override;
|
||||
std::vector<std::string> AnnotationsVector() const override;
|
||||
std::map<std::string, std::string> AnnotationsSimpleMap() const override;
|
||||
std::vector<AnnotationSnapshot> AnnotationObjects() const override;
|
||||
@ -117,6 +121,7 @@ class TestModuleSnapshot final : public ModuleSnapshot {
|
||||
ModuleType module_type_;
|
||||
uint32_t age_;
|
||||
crashpad::UUID uuid_;
|
||||
std::vector<uint8_t> build_id_;
|
||||
std::string debug_file_name_;
|
||||
std::vector<std::string> annotations_vector_;
|
||||
std::map<std::string, std::string> annotations_simple_map_;
|
||||
|
@ -44,8 +44,7 @@ ModuleSnapshotWin::ModuleSnapshotWin()
|
||||
age_(0),
|
||||
initialized_() {}
|
||||
|
||||
ModuleSnapshotWin::~ModuleSnapshotWin() {
|
||||
}
|
||||
ModuleSnapshotWin::~ModuleSnapshotWin() {}
|
||||
|
||||
bool ModuleSnapshotWin::Initialize(
|
||||
ProcessReaderWin* process_reader,
|
||||
@ -195,6 +194,11 @@ std::string ModuleSnapshotWin::DebugFileName() const {
|
||||
return pdb_name_;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ModuleSnapshotWin::BuildID() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return std::vector<uint8_t>();
|
||||
}
|
||||
|
||||
std::vector<std::string> ModuleSnapshotWin::AnnotationsVector() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
// These correspond to system-logged things on Mac. We don't currently track
|
||||
|
@ -84,6 +84,7 @@ class ModuleSnapshotWin final : public ModuleSnapshot {
|
||||
ModuleType GetModuleType() const override;
|
||||
void UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const override;
|
||||
std::string DebugFileName() const override;
|
||||
std::vector<uint8_t> BuildID() const override;
|
||||
std::vector<std::string> AnnotationsVector() const override;
|
||||
std::map<std::string, std::string> AnnotationsSimpleMap() const override;
|
||||
std::vector<AnnotationSnapshot> AnnotationObjects() const override;
|
||||
|
@ -18,5 +18,6 @@ namespace crashpad {
|
||||
|
||||
const uint32_t CodeViewRecordPDB20::kSignature;
|
||||
const uint32_t CodeViewRecordPDB70::kSignature;
|
||||
const uint32_t CodeViewRecordBuildID::kSignature;
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -90,12 +90,7 @@ struct CodeViewRecordPDB70 {
|
||||
// UUID has a constructor, which makes it non-POD, which makes this structure
|
||||
// non-POD. In order for the default constructor to zero-initialize other
|
||||
// members, an explicit constructor must be provided.
|
||||
CodeViewRecordPDB70()
|
||||
: signature(),
|
||||
uuid(),
|
||||
age(),
|
||||
pdb_name() {
|
||||
}
|
||||
CodeViewRecordPDB70() : signature(), uuid(), age(), pdb_name() {}
|
||||
|
||||
//! \brief The magic number identifying this structure version, stored in
|
||||
//! #signature.
|
||||
@ -127,6 +122,27 @@ struct CodeViewRecordPDB70 {
|
||||
uint8_t pdb_name[1];
|
||||
};
|
||||
|
||||
//! \brief A CodeView record containing an ELF build-id.
|
||||
//!
|
||||
//! This identifier comes from the ELF section `NT_GNU_BUILD_ID`.
|
||||
struct CodeViewRecordBuildID {
|
||||
//! \brief The magic number identifying this structure version, stored in
|
||||
//! #signature.
|
||||
//!
|
||||
//! In a hex dump, this will appear as “LEpB” when produced by a little-endian
|
||||
//! machine.
|
||||
static const uint32_t kSignature = 'BpEL';
|
||||
|
||||
//! \brief The magic number identifying this structure version, the value of
|
||||
//! #kSignature.
|
||||
uint32_t signature;
|
||||
|
||||
//! \brief The build ID for this object.
|
||||
//!
|
||||
//! This usually comes from `NT_GNU_BUILD_ID` on ELF objects.
|
||||
uint8_t build_id[1];
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_MISC_PDB_STRUCTURES_H_
|
||||
|
Loading…
x
Reference in New Issue
Block a user