aboutsummaryrefslogtreecommitdiff
path: root/src/common/linux
diff options
context:
space:
mode:
authorTed Mielczarek <ted@mielczarek.org>2016-06-10 13:23:29 -0400
committerTed Mielczarek <ted@mielczarek.org>2016-06-10 13:23:29 -0400
commitc44217f6468152bf5693df7ec78a48d97e2b0e83 (patch)
treef05595f7a39b34c8111c6a74bfbf505c66dfa4b1 /src/common/linux
parentFix a trivial parsing bug caught by static analysis (diff)
downloadbreakpad-c44217f6468152bf5693df7ec78a48d97e2b0e83.tar.xz
Dump INFO CODE_ID containing Build ID in Linux dump_syms
I'd like to have the Build ID available for our symbol server uploading, and this will make it easy. Most of this change is me rewriting dump_symbols_unittest to be typed tests so I could add a new test there. R=mark@chromium.org BUG= Review URL: https://codereview.chromium.org/2052263002 .
Diffstat (limited to 'src/common/linux')
-rw-r--r--src/common/linux/dump_symbols.cc4
-rw-r--r--src/common/linux/dump_symbols_unittest.cc76
-rw-r--r--src/common/linux/elfutils.h8
-rw-r--r--src/common/linux/file_id.cc26
-rw-r--r--src/common/linux/file_id.h4
-rw-r--r--src/common/linux/file_id_unittest.cc17
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));
+}