diff options
Diffstat (limited to 'src/common/linux')
-rw-r--r-- | src/common/linux/dump_symbols.cc | 4 | ||||
-rw-r--r-- | src/common/linux/dump_symbols_unittest.cc | 76 | ||||
-rw-r--r-- | src/common/linux/elfutils.h | 8 | ||||
-rw-r--r-- | src/common/linux/file_id.cc | 26 | ||||
-rw-r--r-- | src/common/linux/file_id.h | 4 | ||||
-rw-r--r-- | src/common/linux/file_id_unittest.cc | 17 |
6 files changed, 104 insertions, 31 deletions
diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc index 6b27120a..40b9e478 100644 --- a/src/common/linux/dump_symbols.cc +++ b/src/common/linux/dump_symbols.cc @@ -926,8 +926,10 @@ bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header, // 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"; + // This is just the raw Build ID in hex. + string code_id = FileID::ConvertIdentifierToString(identifier); - module.reset(new Module(name, os, architecture, id)); + module.reset(new Module(name, os, architecture, id, code_id)); return true; } diff --git a/src/common/linux/dump_symbols_unittest.cc b/src/common/linux/dump_symbols_unittest.cc index 3f86dbe6..bb7b2007 100644 --- a/src/common/linux/dump_symbols_unittest.cc +++ b/src/common/linux/dump_symbols_unittest.cc @@ -40,6 +40,8 @@ #include <vector> #include "breakpad_googletest_includes.h" +#include "common/linux/elf_gnu_compat.h" +#include "common/linux/elfutils.h" #include "common/linux/dump_symbols.h" #include "common/linux/synth_elf.h" #include "common/module.h" @@ -54,6 +56,7 @@ bool ReadSymbolDataInternal(const uint8_t* obj_file, Module** module); using google_breakpad::synth_elf::ELF; +using google_breakpad::synth_elf::Notes; using google_breakpad::synth_elf::StringTable; using google_breakpad::synth_elf::SymbolTable; using google_breakpad::test_assembler::kLittleEndian; @@ -61,7 +64,9 @@ using google_breakpad::test_assembler::Section; using std::stringstream; using std::vector; using ::testing::Test; +using ::testing::Types; +template<typename ElfClass> class DumpSymbols : public Test { public: void GetElfContents(ELF& elf) { @@ -78,7 +83,11 @@ class DumpSymbols : public Test { uint8_t* elfdata; }; -TEST_F(DumpSymbols, Invalid) { +typedef Types<ElfClass32, ElfClass64> ElfClasses; + +TYPED_TEST_CASE(DumpSymbols, ElfClasses); + +TYPED_TEST(DumpSymbols, Invalid) { Elf32_Ehdr header; memset(&header, 0, sizeof(header)); Module* module; @@ -90,8 +99,8 @@ TEST_F(DumpSymbols, Invalid) { &module)); } -TEST_F(DumpSymbols, SimplePublic32) { - ELF elf(EM_386, ELFCLASS32, kLittleEndian); +TYPED_TEST(DumpSymbols, SimplePublic) { + ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian); // Zero out text section for simplicity. Section text(kLittleEndian); text.Append(4096, 0); @@ -99,8 +108,11 @@ TEST_F(DumpSymbols, SimplePublic32) { // Add a public symbol. StringTable table(kLittleEndian); - SymbolTable syms(kLittleEndian, 4, table); - syms.AddSymbol("superfunc", (uint32_t)0x1000, (uint32_t)0x10, + 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); @@ -109,14 +121,14 @@ TEST_F(DumpSymbols, SimplePublic32) { SHF_ALLOC, // flags 0, // addr index, // link - sizeof(Elf32_Sym)); // entsize + sizeof(typename TypeParam::Sym)); // entsize elf.Finish(); - GetElfContents(elf); + this->GetElfContents(elf); Module* module; DumpOptions options(ALL_SYMBOL_DATA, true); - EXPECT_TRUE(ReadSymbolDataInternal(elfdata, + EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, "foo", vector<string>(), options, @@ -124,24 +136,40 @@ TEST_F(DumpSymbols, SimplePublic32) { stringstream s; module->Write(s, ALL_SYMBOL_DATA); - EXPECT_EQ("MODULE Linux x86 000000000000000000000000000000000 foo\n" - "PUBLIC 1000 0 superfunc\n", - s.str()); + const string expected = + string("MODULE Linux ") + TypeParam::kMachineName + + " 000000000000000000000000000000000 foo\n" + "INFO CODE_ID 00000000000000000000000000000000\n" + "PUBLIC 1000 0 superfunc\n"; + EXPECT_EQ(expected, s.str()); delete module; } -TEST_F(DumpSymbols, SimplePublic64) { - ELF elf(EM_X86_64, ELFCLASS64, kLittleEndian); +TYPED_TEST(DumpSymbols, SimpleBuildID) { + 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 Build ID + const uint8_t kExpectedIdentifierBytes[] = + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13}; + Notes notes(kLittleEndian); + notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, + sizeof(kExpectedIdentifierBytes)); + elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE); + // Add a public symbol. StringTable table(kLittleEndian); - SymbolTable syms(kLittleEndian, 8, table); - syms.AddSymbol("superfunc", (uint64_t)0x1000, (uint64_t)0x10, - ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), + 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, @@ -149,14 +177,14 @@ TEST_F(DumpSymbols, SimplePublic64) { SHF_ALLOC, // flags 0, // addr index, // link - sizeof(Elf64_Sym)); // entsize + sizeof(typename TypeParam::Sym)); // entsize elf.Finish(); - GetElfContents(elf); + this->GetElfContents(elf); Module* module; DumpOptions options(ALL_SYMBOL_DATA, true); - EXPECT_TRUE(ReadSymbolDataInternal(elfdata, + EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, "foo", vector<string>(), options, @@ -164,9 +192,13 @@ TEST_F(DumpSymbols, SimplePublic64) { stringstream s; module->Write(s, ALL_SYMBOL_DATA); - EXPECT_EQ("MODULE Linux x86_64 000000000000000000000000000000000 foo\n" - "PUBLIC 1000 0 superfunc\n", - s.str()); + const string expected = + string("MODULE Linux ") + TypeParam::kMachineName + + " 030201000504070608090A0B0C0D0E0F0 foo\n" + "INFO CODE_ID 000102030405060708090A0B0C0D0E0F10111213\n" + "PUBLIC 1000 0 superfunc\n"; + EXPECT_EQ(expected, s.str()); + delete module; } } // namespace google_breakpad diff --git a/src/common/linux/elfutils.h b/src/common/linux/elfutils.h index dccdc235..f34ba831 100644 --- a/src/common/linux/elfutils.h +++ b/src/common/linux/elfutils.h @@ -49,9 +49,13 @@ struct ElfClass32 { typedef Elf32_Shdr Shdr; typedef Elf32_Half Half; typedef Elf32_Off Off; + typedef Elf32_Sym Sym; typedef Elf32_Word Word; + static const int kClass = ELFCLASS32; + static const uint16_t kMachine = EM_386; static const size_t kAddrSize = sizeof(Elf32_Addr); + static constexpr const char* kMachineName = "x86"; }; struct ElfClass64 { @@ -62,9 +66,13 @@ struct ElfClass64 { typedef Elf64_Shdr Shdr; typedef Elf64_Half Half; typedef Elf64_Off Off; + typedef Elf64_Sym Sym; typedef Elf64_Word Word; + static const int kClass = ELFCLASS64; + static const uint16_t kMachine = EM_X86_64; static const size_t kAddrSize = sizeof(Elf64_Addr); + static constexpr const char* kMachineName = "x86_64"; }; bool IsValidElf(const void* elf_header); diff --git a/src/common/linux/file_id.cc b/src/common/linux/file_id.cc index e8dc528d..02207758 100644 --- a/src/common/linux/file_id.cc +++ b/src/common/linux/file_id.cc @@ -164,8 +164,18 @@ bool FileID::ElfFileIdentifier(wasteful_vector<uint8_t>& identifier) { return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier); } -// This function is not ever called in an unsafe context, so it's OK +// These three functions are not ever called in an unsafe context, so it's OK // to allocate memory and use libc. +static string bytes_to_hex_string(const uint8_t* bytes, size_t count) { + string result; + for (unsigned int idx = 0; idx < count; ++idx) { + char buf[3]; + snprintf(buf, sizeof(buf), "%02X", bytes[idx]); + result.append(buf); + } + return result; +} + // static string FileID::ConvertIdentifierToUUIDString( const wasteful_vector<uint8_t>& identifier) { @@ -181,13 +191,13 @@ string FileID::ConvertIdentifierToUUIDString( uint16_t* data3 = reinterpret_cast<uint16_t*>(identifier_swapped + 6); *data3 = htons(*data3); - string result; - for (unsigned int idx = 0; idx < kMDGUIDSize; ++idx) { - char buf[3]; - snprintf(buf, sizeof(buf), "%02X", identifier_swapped[idx]); - result.append(buf); - } - return result; + return bytes_to_hex_string(identifier_swapped, kMDGUIDSize); +} + +// static +string FileID::ConvertIdentifierToString( + const wasteful_vector<uint8_t>& identifier) { + return bytes_to_hex_string(&identifier[0], identifier.size()); } } // namespace google_breakpad diff --git a/src/common/linux/file_id.h b/src/common/linux/file_id.h index 80e5a8e9..a1d2fd6e 100644 --- a/src/common/linux/file_id.h +++ b/src/common/linux/file_id.h @@ -73,6 +73,10 @@ class FileID { static std::string ConvertIdentifierToUUIDString( const wasteful_vector<uint8_t>& identifier); + // Convert the entire |identifier| data to a hex string. + static std::string ConvertIdentifierToString( + const wasteful_vector<uint8_t>& identifier); + private: // Storage for the path specified std::string path_; diff --git a/src/common/linux/file_id_unittest.cc b/src/common/linux/file_id_unittest.cc index ec11bb25..3a819303 100644 --- a/src/common/linux/file_id_unittest.cc +++ b/src/common/linux/file_id_unittest.cc @@ -319,3 +319,20 @@ TYPED_TEST(FileIDTest, UniqueHashes) { EXPECT_NE(identifier_string_1, identifier_string_2); } + +TYPED_TEST(FileIDTest, ConvertIdentifierToString) { + const uint8_t kIdentifierBytes[] = + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}; + const char* kExpected = + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"; + + id_vector identifier(this->make_vector()); + identifier.insert(identifier.end(), + kIdentifierBytes, + kIdentifierBytes + sizeof(kIdentifierBytes)); + ASSERT_EQ(kExpected, + FileID::ConvertIdentifierToString(identifier)); +} |