diff --git a/minidump/minidump_module_writer.cc b/minidump/minidump_module_writer.cc index 305d37c4..6e533524 100644 --- a/minidump/minidump_module_writer.cc +++ b/minidump/minidump_module_writer.cc @@ -31,8 +31,7 @@ namespace crashpad { -MinidumpModuleCodeViewRecordWriter::~MinidumpModuleCodeViewRecordWriter() { -} +MinidumpModuleCodeViewRecordWriter::~MinidumpModuleCodeViewRecordWriter() {} namespace internal { @@ -45,8 +44,7 @@ MinidumpModuleCodeViewRecordPDBLinkWriter< template MinidumpModuleCodeViewRecordPDBLinkWriter< - CodeViewRecordType>::~MinidumpModuleCodeViewRecordPDBLinkWriter() { -} + CodeViewRecordType>::~MinidumpModuleCodeViewRecordPDBLinkWriter() {} template 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& 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 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 = - std::make_unique(); - codeview_record->InitializeFromSnapshot(module_snapshot); + auto build_id = module_snapshot->BuildID(); + + std::unique_ptr codeview_record; + if (!build_id.empty()) { + auto cv_record_build_id = + std::make_unique(); + cv_record_build_id->SetBuildID(build_id); + codeview_record = std::move(cv_record_build_id); + } else { + auto cv_record_pdb70 = + std::make_unique(); + 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& module_snapshots) { diff --git a/minidump/minidump_module_writer.h b/minidump/minidump_module_writer.h index 555c4115..b328bf04 100644 --- a/minidump/minidump_module_writer.h +++ b/minidump/minidump_module_writer.h @@ -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& build_id); + + private: + // MinidumpWritable: + size_t SizeOfObject() override; + bool WriteObject(FileWriterInterface* file_writer) override; + + std::vector 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. diff --git a/minidump/minidump_module_writer_test.cc b/minidump/minidump_module_writer_test.cc index 8b5fc062..71db3ac1 100644 --- a/minidump/minidump_module_writer_test.cc +++ b/minidump/minidump_module_writer_test.cc @@ -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& 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(VS_FFI_SIGNATURE)); + EXPECT_EQ(observed->VersionInfo.dwStrucVersion, + implicit_cast(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( + 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(); @@ -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(); + + static constexpr char kModuleName[] = "dinosaur"; + static constexpr char kBuildID[] = + "averylonghashcodeormaybeitsjustrandomnumbershardtosay"; + + std::vector build_id_data(kBuildID, kBuildID + 53); + + auto module_writer = std::make_unique(); + module_writer->SetName(kModuleName); + + auto codeview_build_id_writer = + std::make_unique(); + 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; diff --git a/minidump/test/minidump_writable_test_util.cc b/minidump/test/minidump_writable_test_util.cc index 1a832bf3..db07b366 100644 --- a/minidump/test/minidump_writable_test_util.cc +++ b/minidump/test/minidump_writable_test_util.cc @@ -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,17 +249,19 @@ const typename T::ListType* MinidumpListAtLocationDescriptor( } // namespace template <> -const MINIDUMP_MEMORY_LIST* MinidumpWritableAtLocationDescriptor< - MINIDUMP_MEMORY_LIST>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location) { +const MINIDUMP_MEMORY_LIST* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { return MinidumpListAtLocationDescriptor( file_contents, location); } template <> -const MINIDUMP_MODULE_LIST* MinidumpWritableAtLocationDescriptor< - MINIDUMP_MODULE_LIST>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location) { +const MINIDUMP_MODULE_LIST* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { return MinidumpListAtLocationDescriptor( file_contents, location); } @@ -278,25 +276,28 @@ MinidumpWritableAtLocationDescriptor( } template <> -const MINIDUMP_THREAD_LIST* MinidumpWritableAtLocationDescriptor< - MINIDUMP_THREAD_LIST>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location) { +const MINIDUMP_THREAD_LIST* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { return MinidumpListAtLocationDescriptor( file_contents, location); } template <> -const MINIDUMP_HANDLE_DATA_STREAM* MinidumpWritableAtLocationDescriptor< - MINIDUMP_HANDLE_DATA_STREAM>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location) { +const MINIDUMP_HANDLE_DATA_STREAM* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { return MinidumpListAtLocationDescriptor( file_contents, location); } template <> -const MINIDUMP_MEMORY_INFO_LIST* MinidumpWritableAtLocationDescriptor< - MINIDUMP_MEMORY_INFO_LIST>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location) { +const MINIDUMP_MEMORY_INFO_LIST* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { return MinidumpListAtLocationDescriptor( file_contents, location); } @@ -357,28 +358,51 @@ const T* MinidumpCVPDBAtLocationDescriptor( } // namespace template <> -const CodeViewRecordPDB20* MinidumpWritableAtLocationDescriptor< - CodeViewRecordPDB20>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location) { +const CodeViewRecordPDB20* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { return MinidumpCVPDBAtLocationDescriptor(file_contents, location); } template <> -const CodeViewRecordPDB70* MinidumpWritableAtLocationDescriptor< - CodeViewRecordPDB70>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location) { +const CodeViewRecordPDB70* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { return MinidumpCVPDBAtLocationDescriptor(file_contents, location); } -TestUInt32MinidumpWritable::TestUInt32MinidumpWritable(uint32_t value) - : MinidumpWritable(), - value_(value) { +template <> +const CodeViewRecordBuildID* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location) { + const CodeViewRecordBuildID* cv = + reinterpret_cast( + MinidumpWritableAtLocationDescriptorInternal( + file_contents, + location, + offsetof(CodeViewRecordBuildID, build_id), + true)); + + if (!cv) { + return nullptr; + } + + if (cv->signature != CodeViewRecordBuildID::kSignature) { + return nullptr; + } + + return cv; } -TestUInt32MinidumpWritable::~TestUInt32MinidumpWritable() { -} +TestUInt32MinidumpWritable::TestUInt32MinidumpWritable(uint32_t value) + : MinidumpWritable(), value_(value) {} + +TestUInt32MinidumpWritable::~TestUInt32MinidumpWritable() {} size_t TestUInt32MinidumpWritable::SizeOfObject() { return sizeof(value_); diff --git a/minidump/test/minidump_writable_test_util.h b/minidump/test/minidump_writable_test_util.h index 5b176d2b..6c706fba 100644 --- a/minidump/test/minidump_writable_test_util.h +++ b/minidump/test/minidump_writable_test_util.h @@ -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,14 +180,16 @@ const MINIDUMP_HEADER* MinidumpWritableAtLocationDescriptor( const MINIDUMP_LOCATION_DESCRIPTOR& location); template <> -const MINIDUMP_MEMORY_LIST* MinidumpWritableAtLocationDescriptor< - MINIDUMP_MEMORY_LIST>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location); +const MINIDUMP_MEMORY_LIST* +MinidumpWritableAtLocationDescriptor( + 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_LOCATION_DESCRIPTOR& location); +const MINIDUMP_MODULE_LIST* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); template <> const MINIDUMP_UNLOADED_MODULE_LIST* @@ -195,29 +198,40 @@ MinidumpWritableAtLocationDescriptor( const MINIDUMP_LOCATION_DESCRIPTOR& location); template <> -const MINIDUMP_THREAD_LIST* MinidumpWritableAtLocationDescriptor< - MINIDUMP_THREAD_LIST>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location); +const MINIDUMP_THREAD_LIST* +MinidumpWritableAtLocationDescriptor( + 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_LOCATION_DESCRIPTOR& location); +const MINIDUMP_HANDLE_DATA_STREAM* +MinidumpWritableAtLocationDescriptor( + 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_LOCATION_DESCRIPTOR& location); +const MINIDUMP_MEMORY_INFO_LIST* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); template <> -const CodeViewRecordPDB20* MinidumpWritableAtLocationDescriptor< - CodeViewRecordPDB20>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location); +const CodeViewRecordPDB20* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); template <> -const CodeViewRecordPDB70* MinidumpWritableAtLocationDescriptor< - CodeViewRecordPDB70>(const std::string& file_contents, - const MINIDUMP_LOCATION_DESCRIPTOR& location); +const CodeViewRecordPDB70* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); + +template <> +const CodeViewRecordBuildID* +MinidumpWritableAtLocationDescriptor( + const std::string& file_contents, + const MINIDUMP_LOCATION_DESCRIPTOR& location); template <> const MinidumpModuleCrashpadInfoList* diff --git a/snapshot/elf/module_snapshot_elf.cc b/snapshot/elf/module_snapshot_elf.cc index 39385a6d..cfe07dd4 100644 --- a/snapshot/elf/module_snapshot_elf.cc +++ b/snapshot/elf/module_snapshot_elf.cc @@ -150,13 +150,10 @@ void ModuleSnapshotElf::UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); *age = 0; - std::unique_ptr 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(&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 ModuleSnapshotElf::BuildID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + + std::unique_ptr 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 build_id; + build_id.reserve(desc.size()); + std::copy(desc.begin(), desc.end(), std::back_inserter(build_id)); + return build_id; +} + std::vector ModuleSnapshotElf::AnnotationsVector() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return std::vector(); diff --git a/snapshot/elf/module_snapshot_elf.h b/snapshot/elf/module_snapshot_elf.h index 15c3f3c2..be27242f 100644 --- a/snapshot/elf/module_snapshot_elf.h +++ b/snapshot/elf/module_snapshot_elf.h @@ -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 BuildID() const override; std::vector AnnotationsVector() const override; std::map AnnotationsSimpleMap() const override; std::vector AnnotationObjects() const override; diff --git a/snapshot/mac/module_snapshot_mac.cc b/snapshot/mac/module_snapshot_mac.cc index 41608978..947744db 100644 --- a/snapshot/mac/module_snapshot_mac.cc +++ b/snapshot/mac/module_snapshot_mac.cc @@ -14,8 +14,8 @@ #include "snapshot/mac/module_snapshot_mac.h" -#include #include +#include #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 ModuleSnapshotMac::BuildID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector(); +} + std::vector ModuleSnapshotMac::AnnotationsVector() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); MachOImageAnnotationsReader annotations_reader( diff --git a/snapshot/mac/module_snapshot_mac.h b/snapshot/mac/module_snapshot_mac.h index fe2d40a1..d78c3266 100644 --- a/snapshot/mac/module_snapshot_mac.h +++ b/snapshot/mac/module_snapshot_mac.h @@ -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 BuildID() const override; std::vector AnnotationsVector() const override; std::map AnnotationsSimpleMap() const override; std::vector AnnotationObjects() const override; diff --git a/snapshot/minidump/module_snapshot_minidump.cc b/snapshot/minidump/module_snapshot_minidump.cc index b3e33d04..a316e83b 100644 --- a/snapshot/minidump/module_snapshot_minidump.cc +++ b/snapshot/minidump/module_snapshot_minidump.cc @@ -14,13 +14,15 @@ #include "snapshot/minidump/module_snapshot_minidump.h" +#include #include +#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,33 +65,68 @@ bool ModuleSnapshotMinidump::Initialize( ReadMinidumpUTF16String(file_reader, minidump_module_.ModuleNameRva, &name_); - if (minidump_module_.CvRecord.Rva != 0) { - CodeViewRecordPDB70 cv; - - if (!file_reader->SeekSet(minidump_module_.CvRecord.Rva)) { - return false; - } - - if (!file_reader->ReadExactly(&cv, sizeof(cv))) { - return false; - } - - if (cv.signature == 'SDSR') { - age_ = cv.age; - uuid_ = cv.uuid; - } else if (cv.signature != '01BN') { - LOG(ERROR) << "Bad CodeView signature in module"; - return false; - } else { - LOG(ERROR) << "NB10 not supported"; - return false; - } + 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; + } + + std::vector cv_record; + cv_record.resize(minidump_module_.CvRecord.DataSize); + + if (!file_reader->ReadExactly(cv_record.data(), cv_record.size())) { + return false; + } + + signature = *reinterpret_cast(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(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; +} + std::string ModuleSnapshotMinidump::Name() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); return name_; @@ -138,10 +175,10 @@ void ModuleSnapshotMinidump::SourceVersion(uint16_t* version_0, ModuleSnapshot::ModuleType ModuleSnapshotMinidump::GetModuleType() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); switch (minidump_module_.VersionInfo.dwFileType) { - case VFT_APP: - return kModuleTypeExecutable; - case VFT_DLL: - return kModuleTypeSharedLibrary; + case VFT_APP: + return kModuleTypeExecutable; + case VFT_DLL: + return kModuleTypeSharedLibrary; } return kModuleTypeUnknown; } @@ -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 ModuleSnapshotMinidump::BuildID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return build_id_; } std::vector ModuleSnapshotMinidump::AnnotationsVector() const { @@ -201,7 +242,7 @@ bool ModuleSnapshotMinidump::InitializeModuleCrashpadInfo( MinidumpModuleCrashpadInfo minidump_module_crashpad_info; if (minidump_module_crashpad_info_location->DataSize < - sizeof(minidump_module_crashpad_info)) { + sizeof(minidump_module_crashpad_info)) { LOG(ERROR) << "minidump_module_crashpad_info size mismatch"; return false; } @@ -216,7 +257,7 @@ bool ModuleSnapshotMinidump::InitializeModuleCrashpadInfo( } if (minidump_module_crashpad_info.version != - MinidumpModuleCrashpadInfo::kVersion) { + MinidumpModuleCrashpadInfo::kVersion) { LOG(ERROR) << "minidump_module_crashpad_info version mismatch"; return false; } diff --git a/snapshot/minidump/module_snapshot_minidump.h b/snapshot/minidump/module_snapshot_minidump.h index e6e50c51..023d0d59 100644 --- a/snapshot/minidump/module_snapshot_minidump.h +++ b/snapshot/minidump/module_snapshot_minidump.h @@ -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 BuildID() const override; std::vector AnnotationsVector() const override; std::map AnnotationsSimpleMap() const override; std::vector 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 annotations_vector_; std::map annotations_simple_map_; std::vector annotation_objects_; UUID uuid_; + std::vector build_id_; std::string name_; + std::string debug_file_name_; uint32_t age_; InitializationStateDcheck initialized_; diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc index a03edfb1..7d5d16d3 100644 --- a/snapshot/minidump/process_snapshot_minidump_test.cc +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -307,10 +307,10 @@ TEST(ProcessSnapshotMinidump, Modules) { constexpr uint32_t minidump_module_count = 4; RVA name_rvas[minidump_module_count]; std::string names[minidump_module_count] = { - "libtacotruck", - "libevidencebased", - "libgeorgism", - "librealistutopia", + "libtacotruck", + "libevidencebased", + "libgeorgism", + "librealistutopia", }; minidump_module.BaseOfImage = 0xbadf00d; @@ -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(string_file.SeekGet()); - minidump_module.CvRecord.DataSize = sizeof(cv); + auto pdb70_loc = static_cast(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(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(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(pdb70_size); + } else { + minidump_module.CvRecord.Rva = build_id_cv_loc; + minidump_module.CvRecord.DataSize = + static_cast(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); - uint32_t age; - UUID uuid; - modules[i]->UUIDAndAge(&uuid, &age); + 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); + 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(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(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(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(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; @@ -1015,7 +1043,7 @@ TEST(ProcessSnapshotMinidump, MemoryMap) { MINIDUMP_DIRECTORY minidump_memory_info_list_directory = {}; minidump_memory_info_list_directory.StreamType = - kMinidumpStreamTypeMemoryInfoList; + kMinidumpStreamTypeMemoryInfoList; minidump_memory_info_list_directory.Location.DataSize = sizeof(minidump_memory_info_list) + minidump_memory_info_count * sizeof(MINIDUMP_MEMORY_INFO); @@ -1043,12 +1071,16 @@ TEST(ProcessSnapshotMinidump, MemoryMap) { EXPECT_TRUE(process_snapshot.Initialize(&string_file)); std::vector map = - process_snapshot.MemoryMap(); + 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 minidump_stack = { - '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; + std::vector 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(minidump_stack.size()); diff --git a/snapshot/module_snapshot.h b/snapshot/module_snapshot.h index eea74660..f7eb83c8 100644 --- a/snapshot/module_snapshot.h +++ b/snapshot/module_snapshot.h @@ -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 BuildID() const = 0; + //! \brief Returns string annotations recorded in the module. //! //! This method retrieves annotations recorded in a module. These annotations diff --git a/snapshot/sanitized/module_snapshot_sanitized.cc b/snapshot/sanitized/module_snapshot_sanitized.cc index 94cb3d00..32b13578 100644 --- a/snapshot/sanitized/module_snapshot_sanitized.cc +++ b/snapshot/sanitized/module_snapshot_sanitized.cc @@ -81,6 +81,10 @@ std::string ModuleSnapshotSanitized::DebugFileName() const { return snapshot_->DebugFileName(); } +std::vector ModuleSnapshotSanitized::BuildID() const { + return snapshot_->BuildID(); +} + std::vector ModuleSnapshotSanitized::AnnotationsVector() const { // TODO(jperaza): If/when AnnotationsVector() begins to be used, determine // whether and how the content should be sanitized. diff --git a/snapshot/sanitized/module_snapshot_sanitized.h b/snapshot/sanitized/module_snapshot_sanitized.h index 4f375ce0..bbe1f5f4 100644 --- a/snapshot/sanitized/module_snapshot_sanitized.h +++ b/snapshot/sanitized/module_snapshot_sanitized.h @@ -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 BuildID() const override; std::vector AnnotationsVector() const override; std::map AnnotationsSimpleMap() const override; std::vector AnnotationObjects() const override; diff --git a/snapshot/test/test_module_snapshot.cc b/snapshot/test/test_module_snapshot.cc index 9141edad..ad0c2dec 100644 --- a/snapshot/test/test_module_snapshot.cc +++ b/snapshot/test/test_module_snapshot.cc @@ -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 TestModuleSnapshot::BuildID() const { + return build_id_; +} + std::vector TestModuleSnapshot::AnnotationsVector() const { return annotations_vector_; } diff --git a/snapshot/test/test_module_snapshot.h b/snapshot/test/test_module_snapshot.h index d1262fa6..fb84aaf4 100644 --- a/snapshot/test/test_module_snapshot.h +++ b/snapshot/test/test_module_snapshot.h @@ -64,6 +64,9 @@ class TestModuleSnapshot final : public ModuleSnapshot { uuid_ = uuid; age_ = age; } + void SetBuildID(const std::vector& 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 BuildID() const override; std::vector AnnotationsVector() const override; std::map AnnotationsSimpleMap() const override; std::vector AnnotationObjects() const override; @@ -117,6 +121,7 @@ class TestModuleSnapshot final : public ModuleSnapshot { ModuleType module_type_; uint32_t age_; crashpad::UUID uuid_; + std::vector build_id_; std::string debug_file_name_; std::vector annotations_vector_; std::map annotations_simple_map_; diff --git a/snapshot/win/module_snapshot_win.cc b/snapshot/win/module_snapshot_win.cc index d9d74c1b..49d178a8 100644 --- a/snapshot/win/module_snapshot_win.cc +++ b/snapshot/win/module_snapshot_win.cc @@ -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 ModuleSnapshotWin::BuildID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return std::vector(); +} + std::vector ModuleSnapshotWin::AnnotationsVector() const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); // These correspond to system-logged things on Mac. We don't currently track diff --git a/snapshot/win/module_snapshot_win.h b/snapshot/win/module_snapshot_win.h index f18a8809..b32216c3 100644 --- a/snapshot/win/module_snapshot_win.h +++ b/snapshot/win/module_snapshot_win.h @@ -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 BuildID() const override; std::vector AnnotationsVector() const override; std::map AnnotationsSimpleMap() const override; std::vector AnnotationObjects() const override; diff --git a/util/misc/pdb_structures.cc b/util/misc/pdb_structures.cc index c62f11c0..e904dc63 100644 --- a/util/misc/pdb_structures.cc +++ b/util/misc/pdb_structures.cc @@ -18,5 +18,6 @@ namespace crashpad { const uint32_t CodeViewRecordPDB20::kSignature; const uint32_t CodeViewRecordPDB70::kSignature; +const uint32_t CodeViewRecordBuildID::kSignature; } // namespace crashpad diff --git a/util/misc/pdb_structures.h b/util/misc/pdb_structures.h index d0cc9a32..834cfdc8 100644 --- a/util/misc/pdb_structures.h +++ b/util/misc/pdb_structures.h @@ -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_