Read .note.gnu.build-id.

This will be used by heapprofd to allow us to correlate build ids with
memory leaks in libraries and binaries.

Test: m
Test: host libunwindstack_test
Test: run unwind_info against my phone's libc.so (32/64) and compare
      to readelf Build ID output.

Bug: 120186412

Change-Id: I3cefd6cce9a8733509bf35b7175eb0f967783477
This commit is contained in:
Florian Mayer 2018-11-23 16:56:17 +00:00
parent 66a6d8877c
commit da459e56f7
8 changed files with 443 additions and 1 deletions

View file

@ -140,6 +140,10 @@ bool Elf::GetGlobalVariable(const std::string& name, uint64_t* memory_address) {
return true;
}
bool Elf::GetBuildID(std::string* build_id) {
return valid_ && interface_->GetBuildID(build_id);
}
void Elf::GetLastError(ErrorData* data) {
if (valid_) {
*data = interface_->last_error();

View file

@ -237,6 +237,56 @@ void ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias)
}
}
template <typename NhdrType>
bool ElfInterface::ReadBuildID(std::string* build_id) {
// Ensure there is no overflow in any of the calulations below.
uint64_t tmp;
if (__builtin_add_overflow(gnu_build_id_offset_, gnu_build_id_size_, &tmp)) {
return false;
}
uint64_t offset = 0;
while (offset < gnu_build_id_size_) {
if (gnu_build_id_size_ - offset < sizeof(NhdrType)) {
return false;
}
NhdrType hdr;
if (!memory_->ReadFully(gnu_build_id_offset_ + offset, &hdr, sizeof(hdr))) {
return false;
}
offset += sizeof(hdr);
if (gnu_build_id_size_ - offset < hdr.n_namesz) {
return false;
}
if (hdr.n_namesz > 0) {
std::string name(hdr.n_namesz, '\0');
if (!memory_->ReadFully(gnu_build_id_offset_ + offset, &(name[0]), hdr.n_namesz)) {
return false;
}
// Trim trailing \0 as GNU is stored as a C string in the ELF file.
if (name.back() == '\0')
name.resize(name.size() - 1);
// Align hdr.n_namesz to next power multiple of 4. See man 5 elf.
offset += (hdr.n_namesz + 3) & ~3;
if (name == "GNU" && hdr.n_type == NT_GNU_BUILD_ID) {
if (gnu_build_id_size_ - offset < hdr.n_descsz) {
return false;
}
build_id->resize(hdr.n_descsz);
return memory_->ReadFully(gnu_build_id_offset_ + offset, &(*build_id)[0],
hdr.n_descsz);
}
}
// Align hdr.n_descsz to next power multiple of 4. See man 5 elf.
offset += (hdr.n_descsz + 3) & ~3;
}
return false;
}
template <typename EhdrType, typename ShdrType>
void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
uint64_t offset = ehdr.e_shoff;
@ -308,6 +358,15 @@ void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
// In order to read soname, keep track of address to offset mapping.
strtabs_.push_back(std::make_pair<uint64_t, uint64_t>(static_cast<uint64_t>(shdr.sh_addr),
static_cast<uint64_t>(shdr.sh_offset)));
} else if (shdr.sh_type == SHT_NOTE) {
if (shdr.sh_name < sec_size) {
std::string name;
if (memory_->ReadString(sec_offset + shdr.sh_name, &name) &&
name == ".note.gnu.build-id") {
gnu_build_id_offset_ = shdr.sh_offset;
gnu_build_id_size_ = shdr.sh_size;
}
}
}
}
}
@ -492,6 +551,9 @@ template void ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf
template void ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
template void ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
template bool ElfInterface::ReadBuildID<Elf32_Nhdr>(std::string*);
template bool ElfInterface::ReadBuildID<Elf64_Nhdr>(std::string*);
template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);

View file

@ -65,6 +65,8 @@ class Elf {
bool GetGlobalVariable(const std::string& name, uint64_t* memory_address);
bool GetBuildID(std::string* build_id);
uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
bool Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, Regs* regs, Memory* process_memory,

View file

@ -62,6 +62,8 @@ class ElfInterface {
virtual bool GetGlobalVariable(const std::string& name, uint64_t* memory_address) = 0;
virtual bool GetBuildID(std::string* build_id) = 0;
virtual bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
virtual bool IsValidPc(uint64_t pc);
@ -85,6 +87,8 @@ class ElfInterface {
uint64_t debug_frame_size() { return debug_frame_size_; }
uint64_t gnu_debugdata_offset() { return gnu_debugdata_offset_; }
uint64_t gnu_debugdata_size() { return gnu_debugdata_size_; }
uint64_t gnu_build_id_offset() { return gnu_build_id_offset_; }
uint64_t gnu_build_id_size() { return gnu_build_id_size_; }
DwarfSection* eh_frame() { return eh_frame_.get(); }
DwarfSection* debug_frame() { return debug_frame_.get(); }
@ -123,6 +127,9 @@ class ElfInterface {
template <typename EhdrType>
static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size);
template <typename NhdrType>
bool ReadBuildID(std::string* build_id);
Memory* memory_;
std::unordered_map<uint64_t, LoadInfo> pt_loads_;
@ -143,6 +150,9 @@ class ElfInterface {
uint64_t gnu_debugdata_offset_ = 0;
uint64_t gnu_debugdata_size_ = 0;
uint64_t gnu_build_id_offset_ = 0;
uint64_t gnu_build_id_size_ = 0;
uint8_t soname_type_ = SONAME_UNKNOWN;
std::string soname_;
@ -182,6 +192,10 @@ class ElfInterface32 : public ElfInterface {
return ElfInterface::GetGlobalVariableWithTemplate<Elf32_Sym>(name, memory_address);
}
bool GetBuildID(std::string* build_id) {
return ElfInterface::ReadBuildID<Elf32_Nhdr>(build_id);
}
static void GetMaxSize(Memory* memory, uint64_t* size) {
GetMaxSizeWithTemplate<Elf32_Ehdr>(memory, size);
}
@ -212,6 +226,10 @@ class ElfInterface64 : public ElfInterface {
return ElfInterface::GetGlobalVariableWithTemplate<Elf64_Sym>(name, memory_address);
}
bool GetBuildID(std::string* build_id) {
return ElfInterface::ReadBuildID<Elf64_Nhdr>(build_id);
}
static void GetMaxSize(Memory* memory, uint64_t* size) {
GetMaxSizeWithTemplate<Elf64_Ehdr>(memory, size);
}

View file

@ -72,6 +72,9 @@ class ElfInterfaceFake : public ElfInterface {
bool GetFunctionName(uint64_t, std::string*, uint64_t*) override;
bool GetGlobalVariable(const std::string&, uint64_t*) override;
bool GetBuildID(std::string*) override {
return false;
}
bool Step(uint64_t, Regs*, Memory*, bool*) override;

View file

@ -116,6 +116,21 @@ class ElfInterfaceTest : public ::testing::Test {
void InitSym(uint64_t offset, uint32_t value, uint32_t size, uint32_t name_offset,
uint64_t sym_offset, const char* name);
template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
void BuildID();
template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
void BuildIDTwoNotes();
template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
void BuildIDSectionTooSmallForName();
template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
void BuildIDSectionTooSmallForDesc();
template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
void BuildIDSectionTooSmallForHeader();
MemoryFake memory_;
};
@ -898,7 +913,7 @@ void ElfInterfaceTest::InitSectionHeadersOffsets() {
Ehdr ehdr = {};
ehdr.e_shoff = offset;
ehdr.e_shnum = 6;
ehdr.e_shnum = 7;
ehdr.e_shentsize = sizeof(Shdr);
ehdr.e_shstrndx = 2;
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
@ -958,10 +973,19 @@ void ElfInterfaceTest::InitSectionHeadersOffsets() {
memory_.SetMemory(offset, &shdr, sizeof(shdr));
offset += ehdr.e_shentsize;
memset(&shdr, 0, sizeof(shdr));
shdr.sh_type = SHT_NOTE;
shdr.sh_name = 0x500;
shdr.sh_offset = 0xb000;
shdr.sh_size = 0xf00;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
offset += ehdr.e_shentsize;
memory_.SetMemory(0xf100, ".debug_frame", sizeof(".debug_frame"));
memory_.SetMemory(0xf200, ".gnu_debugdata", sizeof(".gnu_debugdata"));
memory_.SetMemory(0xf300, ".eh_frame", sizeof(".eh_frame"));
memory_.SetMemory(0xf400, ".eh_frame_hdr", sizeof(".eh_frame_hdr"));
memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
uint64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
@ -974,6 +998,8 @@ void ElfInterfaceTest::InitSectionHeadersOffsets() {
EXPECT_EQ(0x800U, elf->eh_frame_size());
EXPECT_EQ(0xa000U, elf->eh_frame_hdr_offset());
EXPECT_EQ(0xf00U, elf->eh_frame_hdr_size());
EXPECT_EQ(0xb000U, elf->gnu_build_id_offset());
EXPECT_EQ(0xf00U, elf->gnu_build_id_size());
}
TEST_F(ElfInterfaceTest, init_section_headers_offsets32) {
@ -1153,4 +1179,321 @@ TEST_F(ElfInterfaceTest, is_valid_pc_from_eh_frame) {
EXPECT_FALSE(elf->IsValidPc(0x2a00));
}
template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
void ElfInterfaceTest::BuildID() {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
uint64_t offset = 0x2000;
Ehdr ehdr = {};
ehdr.e_shoff = offset;
ehdr.e_shnum = 3;
ehdr.e_shentsize = sizeof(Shdr);
ehdr.e_shstrndx = 2;
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
offset += ehdr.e_shentsize;
char note_section[128];
Nhdr note_header = {};
note_header.n_namesz = 4; // "GNU"
note_header.n_descsz = 8; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(&note_section, &note_header, sizeof(note_header));
size_t note_offset = sizeof(note_header);
memcpy(&note_section[note_offset], "GNU", sizeof("GNU"));
note_offset += sizeof("GNU");
memcpy(&note_section[note_offset], "BUILDID", sizeof("BUILDID"));
note_offset += sizeof("BUILDID");
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
shdr.sh_name = 0x500;
shdr.sh_offset = 0xb000;
shdr.sh_size = sizeof(note_section);
memory_.SetMemory(offset, &shdr, sizeof(shdr));
offset += ehdr.e_shentsize;
// The string data for section header names.
memset(&shdr, 0, sizeof(shdr));
shdr.sh_type = SHT_STRTAB;
shdr.sh_name = 0x20000;
shdr.sh_offset = 0xf000;
shdr.sh_size = 0x1000;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
offset += ehdr.e_shentsize;
memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
memory_.SetMemory(0xb000, note_section, sizeof(note_section));
uint64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
std::string build_id;
ASSERT_TRUE(elf->GetBuildID(&build_id));
EXPECT_STREQ(build_id.c_str(), "BUILDID");
}
template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
void ElfInterfaceTest::BuildIDTwoNotes() {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
uint64_t offset = 0x2000;
Ehdr ehdr = {};
ehdr.e_shoff = offset;
ehdr.e_shnum = 3;
ehdr.e_shentsize = sizeof(Shdr);
ehdr.e_shstrndx = 2;
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
offset += ehdr.e_shentsize;
char note_section[128];
Nhdr note_header = {};
note_header.n_namesz = 8; // "WRONG" aligned to 4
note_header.n_descsz = 8; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(&note_section, &note_header, sizeof(note_header));
size_t note_offset = sizeof(note_header);
memcpy(&note_section[note_offset], "WRONG", sizeof("WRONG"));
note_offset += 8;
memcpy(&note_section[note_offset], "BUILDID", sizeof("BUILDID"));
note_offset += sizeof("BUILDID");
note_header.n_namesz = 4; // "GNU"
note_header.n_descsz = 8; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(&note_section[note_offset], &note_header, sizeof(note_header));
note_offset += sizeof(note_header);
memcpy(&note_section[note_offset], "GNU", sizeof("GNU"));
note_offset += sizeof("GNU");
memcpy(&note_section[note_offset], "BUILDID", sizeof("BUILDID"));
note_offset += sizeof("BUILDID");
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
shdr.sh_name = 0x500;
shdr.sh_offset = 0xb000;
shdr.sh_size = sizeof(note_section);
memory_.SetMemory(offset, &shdr, sizeof(shdr));
offset += ehdr.e_shentsize;
// The string data for section header names.
memset(&shdr, 0, sizeof(shdr));
shdr.sh_type = SHT_STRTAB;
shdr.sh_name = 0x20000;
shdr.sh_offset = 0xf000;
shdr.sh_size = 0x1000;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
offset += ehdr.e_shentsize;
memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
memory_.SetMemory(0xb000, note_section, sizeof(note_section));
uint64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
std::string build_id;
ASSERT_TRUE(elf->GetBuildID(&build_id));
EXPECT_STREQ(build_id.c_str(), "BUILDID");
}
template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
void ElfInterfaceTest::BuildIDSectionTooSmallForName () {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
uint64_t offset = 0x2000;
Ehdr ehdr = {};
ehdr.e_shoff = offset;
ehdr.e_shnum = 3;
ehdr.e_shentsize = sizeof(Shdr);
ehdr.e_shstrndx = 2;
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
offset += ehdr.e_shentsize;
char note_section[128];
Nhdr note_header = {};
note_header.n_namesz = 4; // "GNU"
note_header.n_descsz = 8; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(&note_section, &note_header, sizeof(note_header));
size_t note_offset = sizeof(note_header);
memcpy(&note_section[note_offset], "GNU", sizeof("GNU"));
note_offset += sizeof("GNU");
memcpy(&note_section[note_offset], "BUILDID", sizeof("BUILDID"));
note_offset += sizeof("BUILDID");
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
shdr.sh_name = 0x500;
shdr.sh_offset = 0xb000;
shdr.sh_size = sizeof(note_header) + 1;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
offset += ehdr.e_shentsize;
// The string data for section header names.
memset(&shdr, 0, sizeof(shdr));
shdr.sh_type = SHT_STRTAB;
shdr.sh_name = 0x20000;
shdr.sh_offset = 0xf000;
shdr.sh_size = 0x1000;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
offset += ehdr.e_shentsize;
memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
memory_.SetMemory(0xb000, note_section, sizeof(note_section));
uint64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
std::string build_id;
ASSERT_FALSE(elf->GetBuildID(&build_id));
}
template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
void ElfInterfaceTest::BuildIDSectionTooSmallForDesc () {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
uint64_t offset = 0x2000;
Ehdr ehdr = {};
ehdr.e_shoff = offset;
ehdr.e_shnum = 3;
ehdr.e_shentsize = sizeof(Shdr);
ehdr.e_shstrndx = 2;
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
offset += ehdr.e_shentsize;
char note_section[128];
Nhdr note_header = {};
note_header.n_namesz = 4; // "GNU"
note_header.n_descsz = 8; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(&note_section, &note_header, sizeof(note_header));
size_t note_offset = sizeof(note_header);
memcpy(&note_section[note_offset], "GNU", sizeof("GNU"));
note_offset += sizeof("GNU");
memcpy(&note_section[note_offset], "BUILDID", sizeof("BUILDID"));
note_offset += sizeof("BUILDID");
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
shdr.sh_name = 0x500;
shdr.sh_offset = 0xb000;
shdr.sh_size = sizeof(note_header) + sizeof("GNU") + 1;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
offset += ehdr.e_shentsize;
// The string data for section header names.
memset(&shdr, 0, sizeof(shdr));
shdr.sh_type = SHT_STRTAB;
shdr.sh_name = 0x20000;
shdr.sh_offset = 0xf000;
shdr.sh_size = 0x1000;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
offset += ehdr.e_shentsize;
memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
memory_.SetMemory(0xb000, note_section, sizeof(note_section));
uint64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
std::string build_id;
ASSERT_FALSE(elf->GetBuildID(&build_id));
}
template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
void ElfInterfaceTest::BuildIDSectionTooSmallForHeader () {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
uint64_t offset = 0x2000;
Ehdr ehdr = {};
ehdr.e_shoff = offset;
ehdr.e_shnum = 3;
ehdr.e_shentsize = sizeof(Shdr);
ehdr.e_shstrndx = 2;
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
offset += ehdr.e_shentsize;
char note_section[128];
Nhdr note_header = {};
note_header.n_namesz = 4; // "GNU"
note_header.n_descsz = 8; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(&note_section, &note_header, sizeof(note_header));
size_t note_offset = sizeof(note_header);
memcpy(&note_section[note_offset], "GNU", sizeof("GNU"));
note_offset += sizeof("GNU");
memcpy(&note_section[note_offset], "BUILDID", sizeof("BUILDID"));
note_offset += sizeof("BUILDID");
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
shdr.sh_name = 0x500;
shdr.sh_offset = 0xb000;
shdr.sh_size = sizeof(note_header) - 1;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
offset += ehdr.e_shentsize;
// The string data for section header names.
memset(&shdr, 0, sizeof(shdr));
shdr.sh_type = SHT_STRTAB;
shdr.sh_name = 0x20000;
shdr.sh_offset = 0xf000;
shdr.sh_size = 0x1000;
memory_.SetMemory(offset, &shdr, sizeof(shdr));
offset += ehdr.e_shentsize;
memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
memory_.SetMemory(0xb000, note_section, sizeof(note_section));
uint64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
std::string build_id;
ASSERT_FALSE(elf->GetBuildID(&build_id));
}
TEST_F(ElfInterfaceTest, build_id32) {
BuildID<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
}
TEST_F(ElfInterfaceTest, build_id64) {
BuildID<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
}
TEST_F(ElfInterfaceTest, build_id_two_notes32) {
BuildIDTwoNotes<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
}
TEST_F(ElfInterfaceTest, build_id_two_notes64) {
BuildIDTwoNotes<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
}
TEST_F(ElfInterfaceTest, build_id_section_too_small_for_name32) {
BuildIDSectionTooSmallForName<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
}
TEST_F(ElfInterfaceTest, build_id_section_too_small_for_name64) {
BuildIDSectionTooSmallForName<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
}
TEST_F(ElfInterfaceTest, build_id_section_too_small_for_desc32) {
BuildIDSectionTooSmallForDesc<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
}
TEST_F(ElfInterfaceTest, build_id_section_too_small_for_desc64) {
BuildIDSectionTooSmallForDesc<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
}
TEST_F(ElfInterfaceTest, build_id_section_too_small_for_header32) {
BuildIDSectionTooSmallForHeader<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
}
TEST_F(ElfInterfaceTest, build_id_section_too_small_for_header64) {
BuildIDSectionTooSmallForHeader<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
}
} // namespace unwindstack

View file

@ -311,6 +311,7 @@ class ElfInterfaceMock : public ElfInterface {
void InitHeaders(uint64_t) override {}
bool GetSoname(std::string*) override { return false; }
bool GetFunctionName(uint64_t, std::string*, uint64_t*) override { return false; }
bool GetBuildID(std::string*) override { return false; }
MOCK_METHOD4(Step, bool(uint64_t, Regs*, Memory*, bool*));
MOCK_METHOD2(GetGlobalVariable, bool(const std::string&, uint64_t*));

View file

@ -123,6 +123,15 @@ int GetElfInfo(const char* file, uint64_t offset) {
printf("Soname: %s\n", soname.c_str());
}
std::string build_id;
if (elf.GetBuildID(&build_id)) {
printf("Build ID: ");
for (size_t i = 0; i < build_id.size(); ++i) {
printf("%02hhx", build_id[i]);
}
printf("\n");
}
ElfInterface* interface = elf.interface();
if (elf.machine_type() == EM_ARM) {
DumpArm(&elf, reinterpret_cast<ElfInterfaceArm*>(interface));