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:
parent
66a6d8877c
commit
da459e56f7
8 changed files with 443 additions and 1 deletions
|
@ -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();
|
||||
|
|
|
@ -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*);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(¬e_section, ¬e_header, sizeof(note_header));
|
||||
size_t note_offset = sizeof(note_header);
|
||||
memcpy(¬e_section[note_offset], "GNU", sizeof("GNU"));
|
||||
note_offset += sizeof("GNU");
|
||||
memcpy(¬e_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(¬e_section, ¬e_header, sizeof(note_header));
|
||||
size_t note_offset = sizeof(note_header);
|
||||
memcpy(¬e_section[note_offset], "WRONG", sizeof("WRONG"));
|
||||
note_offset += 8;
|
||||
memcpy(¬e_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(¬e_section[note_offset], ¬e_header, sizeof(note_header));
|
||||
note_offset += sizeof(note_header);
|
||||
memcpy(¬e_section[note_offset], "GNU", sizeof("GNU"));
|
||||
note_offset += sizeof("GNU");
|
||||
memcpy(¬e_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(¬e_section, ¬e_header, sizeof(note_header));
|
||||
size_t note_offset = sizeof(note_header);
|
||||
memcpy(¬e_section[note_offset], "GNU", sizeof("GNU"));
|
||||
note_offset += sizeof("GNU");
|
||||
memcpy(¬e_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(¬e_section, ¬e_header, sizeof(note_header));
|
||||
size_t note_offset = sizeof(note_header);
|
||||
memcpy(¬e_section[note_offset], "GNU", sizeof("GNU"));
|
||||
note_offset += sizeof("GNU");
|
||||
memcpy(¬e_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(¬e_section, ¬e_header, sizeof(note_header));
|
||||
size_t note_offset = sizeof(note_header);
|
||||
memcpy(¬e_section[note_offset], "GNU", sizeof("GNU"));
|
||||
note_offset += sizeof("GNU");
|
||||
memcpy(¬e_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
|
||||
|
|
|
@ -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*));
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in a new issue