From 54986d34d4611983243f8401563ff022b649afbf Mon Sep 17 00:00:00 2001 From: Sean Carpenter Date: Wed, 8 May 2024 16:25:28 -0700 Subject: [PATCH] Adds a custom Module ID flag to dump_syms TEST=make check BUG=b:328511413 Change-Id: I09d4c5e92213501b647311b804e65f272772bbaf Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/5523975 Reviewed-by: Ivan Penkov Reviewed-by: Ivan Penkov --- src/common/linux/dump_symbols.cc | 34 +++++++++------ src/common/linux/dump_symbols.h | 3 ++ src/common/linux/dump_symbols_unittest.cc | 52 +++++++++++++++++++++++ src/tools/linux/dump_syms/dump_syms.cc | 13 +++++- 4 files changed, 88 insertions(+), 14 deletions(-) diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc index 2877c9ca8..846757d4e 100644 --- a/src/common/linux/dump_symbols.cc +++ b/src/common/linux/dump_symbols.cc @@ -1148,6 +1148,7 @@ template bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header, const string& obj_filename, const string& obj_os, + const string& module_id, scoped_ptr& module, bool enable_multiple_field) { PageAllocator allocator; @@ -1171,10 +1172,14 @@ bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header, ? name_buf : google_breakpad::BaseName(obj_filename); - // Add an extra "0" at the end. PDB files on Windows have an 'age' - // number appended to the end of the file identifier; this isn't - // really used or necessary on other platforms, but be consistent. - string id = FileID::ConvertIdentifierToUUIDString(identifier) + "0"; + // Use the provided module_id + string id = module_id.empty() + // Add an extra "0" at the end. PDB files on Windows have an 'age' + // number appended to the end of the file identifier; this isn't + // really used or necessary on other platforms, but be consistent. + ? FileID::ConvertIdentifierToUUIDString(identifier) + "0" + : module_id; + // This is just the raw Build ID in hex. string code_id = FileID::ConvertIdentifierToString(identifier); @@ -1188,6 +1193,7 @@ template bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header, const string& obj_filename, const string& obj_os, + const string& module_id, const std::vector& debug_dirs, const DumpOptions& options, Module** out_module) { @@ -1196,8 +1202,8 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header, *out_module = NULL; scoped_ptr module; - if (!InitModuleForElfClass(elf_header, obj_filename, obj_os, module, - options.enable_multiple_field)) { + if (!InitModuleForElfClass(elf_header, obj_filename, obj_os, module_id, + module, options.enable_multiple_field)) { return false; } @@ -1246,6 +1252,7 @@ namespace google_breakpad { bool ReadSymbolDataInternal(const uint8_t* obj_file, const string& obj_filename, const string& obj_os, + const string& module_id, const std::vector& debug_dirs, const DumpOptions& options, Module** module) { @@ -1258,12 +1265,12 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file, if (elfclass == ELFCLASS32) { return ReadSymbolDataElfClass( reinterpret_cast(obj_file), obj_filename, obj_os, - debug_dirs, options, module); + module_id, debug_dirs, options, module); } if (elfclass == ELFCLASS64) { return ReadSymbolDataElfClass( reinterpret_cast(obj_file), obj_filename, obj_os, - debug_dirs, options, module); + module_id, debug_dirs, options, module); } return false; @@ -1272,11 +1279,12 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file, bool WriteSymbolFile(const string& load_path, const string& obj_file, const string& obj_os, + const string& module_id, const std::vector& debug_dirs, const DumpOptions& options, std::ostream& sym_stream) { Module* module; - if (!ReadSymbolData(load_path, obj_file, obj_os, debug_dirs, options, + if (!ReadSymbolData(load_path, obj_file, obj_os, module_id, debug_dirs, options, &module)) return false; @@ -1291,6 +1299,7 @@ bool WriteSymbolFile(const string& load_path, bool WriteSymbolFileHeader(const string& load_path, const string& obj_file, const string& obj_os, + const string& module_id, std::ostream& sym_stream) { MmapWrapper map_wrapper; void* elf_header = NULL; @@ -1309,14 +1318,14 @@ bool WriteSymbolFileHeader(const string& load_path, if (elfclass == ELFCLASS32) { if (!InitModuleForElfClass( reinterpret_cast(elf_header), obj_file, obj_os, - module, /*enable_multiple_field=*/false)) { + module_id, module, /*enable_multiple_field=*/false)) { fprintf(stderr, "Failed to load ELF module: %s\n", obj_file.c_str()); return false; } } else if (elfclass == ELFCLASS64) { if (!InitModuleForElfClass( reinterpret_cast(elf_header), obj_file, obj_os, - module, /*enable_multiple_field=*/false)) { + module_id, module, /*enable_multiple_field=*/false)) { fprintf(stderr, "Failed to load ELF module: %s\n", obj_file.c_str()); return false; } @@ -1331,6 +1340,7 @@ bool WriteSymbolFileHeader(const string& load_path, bool ReadSymbolData(const string& load_path, const string& obj_file, const string& obj_os, + const string& module_id, const std::vector& debug_dirs, const DumpOptions& options, Module** module) { @@ -1340,7 +1350,7 @@ bool ReadSymbolData(const string& load_path, return false; return ReadSymbolDataInternal(reinterpret_cast(elf_header), - obj_file, obj_os, debug_dirs, options, module); + obj_file, obj_os, module_id, debug_dirs, options, module); } } // namespace google_breakpad diff --git a/src/common/linux/dump_symbols.h b/src/common/linux/dump_symbols.h index d38ba6fe9..25ede3e0f 100644 --- a/src/common/linux/dump_symbols.h +++ b/src/common/linux/dump_symbols.h @@ -70,6 +70,7 @@ struct DumpOptions { bool WriteSymbolFile(const string& load_path, const string& obj_file, const string& obj_os, + const string& module_id, const std::vector& debug_dirs, const DumpOptions& options, std::ostream& sym_stream); @@ -81,6 +82,7 @@ bool WriteSymbolFile(const string& load_path, bool WriteSymbolFileHeader(const string& load_path, const string& obj_file, const string& obj_os, + const string& module_id, std::ostream& sym_stream); // As above, but simply return the debugging information in MODULE @@ -89,6 +91,7 @@ bool WriteSymbolFileHeader(const string& load_path, bool ReadSymbolData(const string& load_path, const string& obj_file, const string& obj_os, + const string& module_id, const std::vector& debug_dirs, const DumpOptions& options, Module** module); diff --git a/src/common/linux/dump_symbols_unittest.cc b/src/common/linux/dump_symbols_unittest.cc index df3cca529..f20ac0dfc 100644 --- a/src/common/linux/dump_symbols_unittest.cc +++ b/src/common/linux/dump_symbols_unittest.cc @@ -55,6 +55,7 @@ namespace google_breakpad { bool ReadSymbolDataInternal(const uint8_t* obj_file, const string& obj_filename, const string& obj_os, + const string& module_id, const std::vector& debug_dir, const DumpOptions& options, Module** module); @@ -99,6 +100,7 @@ TYPED_TEST(DumpSymbols, Invalid) { EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast(&header), "foo", "Linux", + "", vector(), options, &module)); @@ -136,6 +138,7 @@ TYPED_TEST(DumpSymbols, SimplePublic) { EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, "foo", "Linux", + "", vector(), options, &module)); @@ -151,6 +154,54 @@ TYPED_TEST(DumpSymbols, SimplePublic) { delete module; } +TYPED_TEST(DumpSymbols, ModuleIdOverride) { + ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian); + // Zero out text section for simplicity. + Section text(kLittleEndian); + text.Append(4096, 0); + elf.AddSection(".text", text, SHT_PROGBITS); + + // Add a public symbol. + StringTable table(kLittleEndian); + SymbolTable syms(kLittleEndian, TypeParam::kAddrSize, table); + syms.AddSymbol("superfunc", + (typename TypeParam::Addr)0x1000, + (typename TypeParam::Addr)0x10, + // ELF32_ST_INFO works for 32-or 64-bit. + ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), + SHN_UNDEF + 1); + int index = elf.AddSection(".dynstr", table, SHT_STRTAB); + elf.AddSection(".dynsym", syms, + SHT_DYNSYM, // type + SHF_ALLOC, // flags + 0, // addr + index, // link + sizeof(typename TypeParam::Sym)); // entsize + + elf.Finish(); + this->GetElfContents(elf); + + Module* module; + DumpOptions options(ALL_SYMBOL_DATA, true, false, false); + EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, + "foo", + "Linux", + "some_module_id", + vector(), + options, + &module)); + + stringstream s; + module->Write(s, ALL_SYMBOL_DATA); + const string expected = + string("MODULE Linux ") + TypeParam::kMachineName + + " some_module_id foo\n" + "INFO CODE_ID 00000000000000000000000000000000\n" + "PUBLIC 1000 0 superfunc\n"; + EXPECT_EQ(expected, s.str()); + delete module; +} + TYPED_TEST(DumpSymbols, SimpleBuildID) { ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian); // Zero out text section for simplicity. @@ -193,6 +244,7 @@ TYPED_TEST(DumpSymbols, SimpleBuildID) { EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, "foo", "Linux", + "", vector(), options, &module)); diff --git a/src/tools/linux/dump_syms/dump_syms.cc b/src/tools/linux/dump_syms/dump_syms.cc index 99deb958f..007b46094 100644 --- a/src/tools/linux/dump_syms/dump_syms.cc +++ b/src/tools/linux/dump_syms/dump_syms.cc @@ -59,6 +59,7 @@ int usage(const char* self) { fprintf(stderr, " -r Do not handle inter-compilation " "unit references\n"); fprintf(stderr, " -v Print all warnings to stderr\n"); + fprintf(stderr, " -b Use specified id for the module id\n"); fprintf(stderr, " -n Use specified name for name of the object\n"); fprintf(stderr, " -o Use specified name for the " "operating system\n"); @@ -79,6 +80,7 @@ int main(int argc, char** argv) { bool log_to_stderr = false; bool enable_multiple_field = false; std::string obj_name; + std::string module_id; const char* obj_os = "Linux"; int arg_index = 1; while (arg_index < argc && strlen(argv[arg_index]) > 0 && @@ -95,6 +97,13 @@ int main(int argc, char** argv) { handle_inter_cu_refs = false; } else if (strcmp("-v", argv[arg_index]) == 0) { log_to_stderr = true; + } else if (strcmp("-b", argv[arg_index]) == 0) { + if (arg_index + 1 >= argc) { + fprintf(stderr, "Missing argument to -b\n"); + return usage(argv[0]); + } + module_id = argv[arg_index + 1]; + ++arg_index; } else if (strcmp("-n", argv[arg_index]) == 0) { if (arg_index + 1 >= argc) { fprintf(stderr, "Missing argument to -n\n"); @@ -140,7 +149,7 @@ int main(int argc, char** argv) { obj_name = binary; if (header_only) { - if (!WriteSymbolFileHeader(binary, obj_name, obj_os, std::cout)) { + if (!WriteSymbolFileHeader(binary, obj_name, obj_os, module_id, std::cout)) { fprintf(saved_stderr, "Failed to process file.\n"); return 1; } @@ -149,7 +158,7 @@ int main(int argc, char** argv) { (cfi ? CFI : NO_DATA) | SYMBOLS_AND_FILES; google_breakpad::DumpOptions options(symbol_data, handle_inter_cu_refs, enable_multiple_field, preserve_load_address); - if (!WriteSymbolFile(binary, obj_name, obj_os, debug_dirs, options, + if (!WriteSymbolFile(binary, obj_name, obj_os, module_id, debug_dirs, options, std::cout)) { fprintf(saved_stderr, "Failed to write symbol file.\n"); return 1;