Merge "Read .note.gnu.build-id."
This commit is contained in:
commit
a5913bdd07
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Elf::GetBuildID(std::string* build_id) {
|
||||||
|
return valid_ && interface_->GetBuildID(build_id);
|
||||||
|
}
|
||||||
|
|
||||||
void Elf::GetLastError(ErrorData* data) {
|
void Elf::GetLastError(ErrorData* data) {
|
||||||
if (valid_) {
|
if (valid_) {
|
||||||
*data = interface_->last_error();
|
*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>
|
template <typename EhdrType, typename ShdrType>
|
||||||
void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
|
void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
|
||||||
uint64_t offset = ehdr.e_shoff;
|
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.
|
// 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),
|
strtabs_.push_back(std::make_pair<uint64_t, uint64_t>(static_cast<uint64_t>(shdr.sh_addr),
|
||||||
static_cast<uint64_t>(shdr.sh_offset)));
|
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<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
|
||||||
template void ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_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<Elf32_Dyn>(std::string*);
|
||||||
template bool ElfInterface::GetSonameWithTemplate<Elf64_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 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);
|
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,
|
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 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 Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
|
||||||
|
|
||||||
virtual bool IsValidPc(uint64_t pc);
|
virtual bool IsValidPc(uint64_t pc);
|
||||||
|
|
@ -85,6 +87,8 @@ class ElfInterface {
|
||||||
uint64_t debug_frame_size() { return debug_frame_size_; }
|
uint64_t debug_frame_size() { return debug_frame_size_; }
|
||||||
uint64_t gnu_debugdata_offset() { return gnu_debugdata_offset_; }
|
uint64_t gnu_debugdata_offset() { return gnu_debugdata_offset_; }
|
||||||
uint64_t gnu_debugdata_size() { return gnu_debugdata_size_; }
|
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* eh_frame() { return eh_frame_.get(); }
|
||||||
DwarfSection* debug_frame() { return debug_frame_.get(); }
|
DwarfSection* debug_frame() { return debug_frame_.get(); }
|
||||||
|
|
@ -123,6 +127,9 @@ class ElfInterface {
|
||||||
template <typename EhdrType>
|
template <typename EhdrType>
|
||||||
static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size);
|
static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size);
|
||||||
|
|
||||||
|
template <typename NhdrType>
|
||||||
|
bool ReadBuildID(std::string* build_id);
|
||||||
|
|
||||||
Memory* memory_;
|
Memory* memory_;
|
||||||
std::unordered_map<uint64_t, LoadInfo> pt_loads_;
|
std::unordered_map<uint64_t, LoadInfo> pt_loads_;
|
||||||
|
|
||||||
|
|
@ -143,6 +150,9 @@ class ElfInterface {
|
||||||
uint64_t gnu_debugdata_offset_ = 0;
|
uint64_t gnu_debugdata_offset_ = 0;
|
||||||
uint64_t gnu_debugdata_size_ = 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;
|
uint8_t soname_type_ = SONAME_UNKNOWN;
|
||||||
std::string soname_;
|
std::string soname_;
|
||||||
|
|
||||||
|
|
@ -182,6 +192,10 @@ class ElfInterface32 : public ElfInterface {
|
||||||
return ElfInterface::GetGlobalVariableWithTemplate<Elf32_Sym>(name, memory_address);
|
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) {
|
static void GetMaxSize(Memory* memory, uint64_t* size) {
|
||||||
GetMaxSizeWithTemplate<Elf32_Ehdr>(memory, size);
|
GetMaxSizeWithTemplate<Elf32_Ehdr>(memory, size);
|
||||||
}
|
}
|
||||||
|
|
@ -212,6 +226,10 @@ class ElfInterface64 : public ElfInterface {
|
||||||
return ElfInterface::GetGlobalVariableWithTemplate<Elf64_Sym>(name, memory_address);
|
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) {
|
static void GetMaxSize(Memory* memory, uint64_t* size) {
|
||||||
GetMaxSizeWithTemplate<Elf64_Ehdr>(memory, size);
|
GetMaxSizeWithTemplate<Elf64_Ehdr>(memory, size);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,9 @@ class ElfInterfaceFake : public ElfInterface {
|
||||||
|
|
||||||
bool GetFunctionName(uint64_t, std::string*, uint64_t*) override;
|
bool GetFunctionName(uint64_t, std::string*, uint64_t*) override;
|
||||||
bool GetGlobalVariable(const 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;
|
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,
|
void InitSym(uint64_t offset, uint32_t value, uint32_t size, uint32_t name_offset,
|
||||||
uint64_t sym_offset, const char* name);
|
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_;
|
MemoryFake memory_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -898,7 +913,7 @@ void ElfInterfaceTest::InitSectionHeadersOffsets() {
|
||||||
|
|
||||||
Ehdr ehdr = {};
|
Ehdr ehdr = {};
|
||||||
ehdr.e_shoff = offset;
|
ehdr.e_shoff = offset;
|
||||||
ehdr.e_shnum = 6;
|
ehdr.e_shnum = 7;
|
||||||
ehdr.e_shentsize = sizeof(Shdr);
|
ehdr.e_shentsize = sizeof(Shdr);
|
||||||
ehdr.e_shstrndx = 2;
|
ehdr.e_shstrndx = 2;
|
||||||
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
|
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
|
||||||
|
|
@ -958,10 +973,19 @@ void ElfInterfaceTest::InitSectionHeadersOffsets() {
|
||||||
memory_.SetMemory(offset, &shdr, sizeof(shdr));
|
memory_.SetMemory(offset, &shdr, sizeof(shdr));
|
||||||
offset += ehdr.e_shentsize;
|
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(0xf100, ".debug_frame", sizeof(".debug_frame"));
|
||||||
memory_.SetMemory(0xf200, ".gnu_debugdata", sizeof(".gnu_debugdata"));
|
memory_.SetMemory(0xf200, ".gnu_debugdata", sizeof(".gnu_debugdata"));
|
||||||
memory_.SetMemory(0xf300, ".eh_frame", sizeof(".eh_frame"));
|
memory_.SetMemory(0xf300, ".eh_frame", sizeof(".eh_frame"));
|
||||||
memory_.SetMemory(0xf400, ".eh_frame_hdr", sizeof(".eh_frame_hdr"));
|
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;
|
uint64_t load_bias = 0;
|
||||||
ASSERT_TRUE(elf->Init(&load_bias));
|
ASSERT_TRUE(elf->Init(&load_bias));
|
||||||
|
|
@ -974,6 +998,8 @@ void ElfInterfaceTest::InitSectionHeadersOffsets() {
|
||||||
EXPECT_EQ(0x800U, elf->eh_frame_size());
|
EXPECT_EQ(0x800U, elf->eh_frame_size());
|
||||||
EXPECT_EQ(0xa000U, elf->eh_frame_hdr_offset());
|
EXPECT_EQ(0xa000U, elf->eh_frame_hdr_offset());
|
||||||
EXPECT_EQ(0xf00U, elf->eh_frame_hdr_size());
|
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) {
|
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));
|
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
|
} // namespace unwindstack
|
||||||
|
|
|
||||||
|
|
@ -311,6 +311,7 @@ class ElfInterfaceMock : public ElfInterface {
|
||||||
void InitHeaders(uint64_t) override {}
|
void InitHeaders(uint64_t) override {}
|
||||||
bool GetSoname(std::string*) override { return false; }
|
bool GetSoname(std::string*) override { return false; }
|
||||||
bool GetFunctionName(uint64_t, std::string*, uint64_t*) 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_METHOD4(Step, bool(uint64_t, Regs*, Memory*, bool*));
|
||||||
MOCK_METHOD2(GetGlobalVariable, bool(const std::string&, uint64_t*));
|
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());
|
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();
|
ElfInterface* interface = elf.interface();
|
||||||
if (elf.machine_type() == EM_ARM) {
|
if (elf.machine_type() == EM_ARM) {
|
||||||
DumpArm(&elf, reinterpret_cast<ElfInterfaceArm*>(interface));
|
DumpArm(&elf, reinterpret_cast<ElfInterfaceArm*>(interface));
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue