Loading libunwindstack/Elf.h +2 −2 Original line number Diff line number Diff line Loading @@ -45,8 +45,8 @@ class Elf { return valid_ && interface_->GetSoname(name); } bool GetFunctionName(uint64_t, std::string*, uint64_t*) { return false; bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) { return valid_ && interface_->GetFunctionName(addr, name, func_offset); } bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory) { Loading libunwindstack/ElfInterface.cpp +95 −13 Original line number Diff line number Diff line Loading @@ -22,9 +22,18 @@ #include "DwarfDebugFrame.h" #include "DwarfEhFrame.h" #include "DwarfSection.h" #include "ElfInterface.h" #include "Log.h" #include "Memory.h" #include "Regs.h" #include "Symbols.h" ElfInterface::~ElfInterface() { for (auto symbol : symbols_) { delete symbol; } } template <typename AddressType> void ElfInterface::InitHeadersWithTemplate() { Loading Loading @@ -57,7 +66,13 @@ bool ElfInterface::ReadAllHeaders() { if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr)) { return false; } return ReadSectionHeaders<EhdrType, ShdrType>(ehdr); // We could still potentially unwind without the section header // information, so ignore any errors. if (!ReadSectionHeaders<EhdrType, ShdrType>(ehdr)) { log(0, "Malformed section header found, ignoring..."); } return true; } template <typename EhdrType, typename PhdrType> Loading Loading @@ -147,12 +162,39 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { } // Skip the first header, it's always going to be NULL. offset += ehdr.e_shentsize; for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) { if (!memory_->ReadField(offset, &shdr, &shdr.sh_type, sizeof(shdr.sh_type))) { return false; } if (shdr.sh_type == SHT_PROGBITS) { if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { if (!memory_->Read(offset, &shdr, sizeof(shdr))) { return false; } // Need to go get the information about the section that contains // the string terminated names. ShdrType str_shdr; if (shdr.sh_link >= ehdr.e_shnum) { return false; } uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize; if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_type, sizeof(str_shdr.sh_type))) { return false; } if (str_shdr.sh_type != SHT_STRTAB) { return false; } if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_offset, sizeof(str_shdr.sh_offset))) { return false; } if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_size, sizeof(str_shdr.sh_size))) { return false; } symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize, str_shdr.sh_offset, str_shdr.sh_size)); } else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) { // Look for the .debug_frame and .gnu_debugdata. if (!memory_->ReadField(offset, &shdr, &shdr.sh_name, sizeof(shdr.sh_name))) { return false; Loading @@ -160,18 +202,20 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { if (shdr.sh_name < sec_size) { std::string name; if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) { uint64_t* offset_ptr = nullptr; uint64_t* size_ptr = nullptr; if (name == ".debug_frame") { if (memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) && memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) { debug_frame_offset_ = shdr.sh_offset; debug_frame_size_ = shdr.sh_size; } offset_ptr = &debug_frame_offset_; size_ptr = &debug_frame_size_; } else if (name == ".gnu_debugdata") { if (memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) && memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) { gnu_debugdata_offset_ = shdr.sh_offset; gnu_debugdata_size_ = shdr.sh_size; offset_ptr = &gnu_debugdata_offset_; size_ptr = &gnu_debugdata_size_; } if (offset_ptr != nullptr && memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) && memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) { *offset_ptr = shdr.sh_offset; *size_ptr = shdr.sh_size; } } } Loading Loading @@ -228,7 +272,40 @@ bool ElfInterface::GetSonameWithTemplate(std::string* soname) { return true; } bool ElfInterface::Step(uint64_t, Regs*, Memory*) { template <typename SymType> bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, std::string* name, uint64_t* func_offset) { if (symbols_.empty()) { return false; } for (const auto symbol : symbols_) { if (symbol->GetName<SymType>(addr, load_bias_, memory_, name, func_offset)) { return true; } } return false; } bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory) { // Need to subtract off the load_bias to get the correct pc. if (pc < load_bias_) { return false; } pc -= load_bias_; // Try the eh_frame first. DwarfSection* eh_frame = eh_frame_.get(); if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory)) { return true; } // Try the debug_frame next. DwarfSection* debug_frame = debug_frame_.get(); if (debug_frame != nullptr && debug_frame->Step(pc, regs, process_memory)) { return true; } return false; } Loading @@ -247,3 +324,8 @@ template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*); template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*); template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, std::string*, uint64_t*); template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*, uint64_t*); libunwindstack/ElfInterface.h +11 −5 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ // Forward declarations. class Memory; class Regs; class Symbols; struct LoadInfo { uint64_t offset; Loading @@ -46,7 +47,7 @@ enum : uint8_t { class ElfInterface { public: ElfInterface(Memory* memory) : memory_(memory) {} virtual ~ElfInterface() = default; virtual ~ElfInterface(); virtual bool Init() = 0; Loading Loading @@ -94,6 +95,9 @@ class ElfInterface { template <typename DynType> bool GetSonameWithTemplate(std::string* soname); template <typename SymType> bool GetFunctionNameWithTemplate(uint64_t addr, std::string* name, uint64_t* func_offset); virtual bool HandleType(uint64_t, uint32_t) { return false; } Memory* memory_; Loading @@ -118,6 +122,8 @@ class ElfInterface { std::unique_ptr<DwarfSection> eh_frame_; std::unique_ptr<DwarfSection> debug_frame_; std::vector<Symbols*> symbols_; }; class ElfInterface32 : public ElfInterface { Loading @@ -135,8 +141,8 @@ class ElfInterface32 : public ElfInterface { return ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(soname); } bool GetFunctionName(uint64_t, std::string*, uint64_t*) override { return false; bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset); } }; Loading @@ -155,8 +161,8 @@ class ElfInterface64 : public ElfInterface { return ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(soname); } bool GetFunctionName(uint64_t, std::string*, uint64_t*) override { return false; bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset); } }; Loading libunwindstack/tests/ElfInterfaceTest.cpp +203 −0 Original line number Diff line number Diff line Loading @@ -79,9 +79,37 @@ class ElfInterfaceTest : public ::testing::Test { template <typename ElfType> void InitHeadersDebugFrameFail(); template <typename Ehdr, typename Shdr, typename ElfInterfaceType> void InitSectionHeadersMalformed(); template <typename Ehdr, typename Shdr, typename Sym, typename ElfInterfaceType> void InitSectionHeaders(uint64_t entry_size); template <typename Ehdr, typename Shdr, typename ElfInterfaceType> void InitSectionHeadersOffsets(); template <typename Sym> void InitSym(uint64_t offset, uint32_t value, uint32_t size, uint32_t name_offset, uint64_t sym_offset, const char* name); MemoryFake memory_; }; template <typename Sym> void ElfInterfaceTest::InitSym(uint64_t offset, uint32_t value, uint32_t size, uint32_t name_offset, uint64_t sym_offset, const char* name) { Sym sym; memset(&sym, 0, sizeof(sym)); sym.st_info = STT_FUNC; sym.st_value = value; sym.st_size = size; sym.st_name = name_offset; sym.st_shndx = SHN_COMMON; memory_.SetMemory(offset, &sym, sizeof(sym)); memory_.SetMemory(sym_offset + name_offset, name, strlen(name) + 1); } template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType> void ElfInterfaceTest::SinglePtLoad() { std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_)); Loading Loading @@ -718,3 +746,178 @@ TEST_F(ElfInterfaceTest, init_headers_debug_frame32_fail) { TEST_F(ElfInterfaceTest, init_headers_debug_frame64_fail) { InitHeadersDebugFrameFail<MockElfInterface64>(); } template <typename Ehdr, typename Shdr, typename ElfInterfaceType> void ElfInterfaceTest::InitSectionHeadersMalformed() { std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_)); Ehdr ehdr; memset(&ehdr, 0, sizeof(ehdr)); ehdr.e_shoff = 0x1000; ehdr.e_shnum = 10; ehdr.e_shentsize = sizeof(Shdr); memory_.SetMemory(0, &ehdr, sizeof(ehdr)); ASSERT_TRUE(elf->Init()); } TEST_F(ElfInterfaceTest, init_section_headers_malformed32) { InitSectionHeadersMalformed<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(); } TEST_F(ElfInterfaceTest, init_section_headers_malformed64) { InitSectionHeadersMalformed<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(); } template <typename Ehdr, typename Shdr, typename Sym, typename ElfInterfaceType> void ElfInterfaceTest::InitSectionHeaders(uint64_t entry_size) { std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_)); uint64_t offset = 0x1000; Ehdr ehdr; memset(&ehdr, 0, sizeof(ehdr)); ehdr.e_shoff = offset; ehdr.e_shnum = 10; ehdr.e_shentsize = entry_size; memory_.SetMemory(0, &ehdr, sizeof(ehdr)); offset += ehdr.e_shentsize; Shdr shdr; memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_SYMTAB; shdr.sh_link = 4; shdr.sh_addr = 0x5000; shdr.sh_offset = 0x5000; shdr.sh_entsize = sizeof(Sym); shdr.sh_size = shdr.sh_entsize * 10; memory_.SetMemory(offset, &shdr, sizeof(shdr)); offset += ehdr.e_shentsize; memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_DYNSYM; shdr.sh_link = 4; shdr.sh_addr = 0x6000; shdr.sh_offset = 0x6000; shdr.sh_entsize = sizeof(Sym); shdr.sh_size = shdr.sh_entsize * 10; memory_.SetMemory(offset, &shdr, sizeof(shdr)); offset += ehdr.e_shentsize; memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_PROGBITS; shdr.sh_name = 0xa000; memory_.SetMemory(offset, &shdr, sizeof(shdr)); offset += ehdr.e_shentsize; // The string data for the entries. 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; InitSym<Sym>(0x5000, 0x90000, 0x1000, 0x100, 0xf000, "function_one"); InitSym<Sym>(0x6000, 0xd0000, 0x1000, 0x300, 0xf000, "function_two"); ASSERT_TRUE(elf->Init()); EXPECT_EQ(0U, elf->debug_frame_offset()); EXPECT_EQ(0U, elf->debug_frame_size()); EXPECT_EQ(0U, elf->gnu_debugdata_offset()); EXPECT_EQ(0U, elf->gnu_debugdata_size()); // Look in the first symbol table. std::string name; uint64_t name_offset; ASSERT_TRUE(elf->GetFunctionName(0x90010, &name, &name_offset)); EXPECT_EQ("function_one", name); EXPECT_EQ(16U, name_offset); ASSERT_TRUE(elf->GetFunctionName(0xd0020, &name, &name_offset)); EXPECT_EQ("function_two", name); EXPECT_EQ(32U, name_offset); } TEST_F(ElfInterfaceTest, init_section_headers32) { InitSectionHeaders<Elf32_Ehdr, Elf32_Shdr, Elf32_Sym, ElfInterface32>(sizeof(Elf32_Shdr)); } TEST_F(ElfInterfaceTest, init_section_headers64) { InitSectionHeaders<Elf64_Ehdr, Elf64_Shdr, Elf64_Sym, ElfInterface64>(sizeof(Elf64_Shdr)); } TEST_F(ElfInterfaceTest, init_section_headers_non_std_entry_size32) { InitSectionHeaders<Elf32_Ehdr, Elf32_Shdr, Elf32_Sym, ElfInterface32>(0x100); } TEST_F(ElfInterfaceTest, init_section_headers_non_std_entry_size64) { InitSectionHeaders<Elf64_Ehdr, Elf64_Shdr, Elf64_Sym, ElfInterface64>(0x100); } template <typename Ehdr, typename Shdr, typename ElfInterfaceType> void ElfInterfaceTest::InitSectionHeadersOffsets() { std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_)); uint64_t offset = 0x2000; Ehdr ehdr; memset(&ehdr, 0, sizeof(ehdr)); ehdr.e_shoff = offset; ehdr.e_shnum = 10; ehdr.e_shentsize = sizeof(Shdr); ehdr.e_shstrndx = 2; memory_.SetMemory(0, &ehdr, sizeof(ehdr)); offset += ehdr.e_shentsize; Shdr shdr; memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_PROGBITS; shdr.sh_link = 2; shdr.sh_name = 0x200; shdr.sh_addr = 0x5000; shdr.sh_offset = 0x5000; shdr.sh_entsize = 0x100; shdr.sh_size = 0x800; 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; memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_PROGBITS; shdr.sh_link = 2; shdr.sh_name = 0x100; shdr.sh_addr = 0x6000; shdr.sh_offset = 0x6000; shdr.sh_entsize = 0x100; shdr.sh_size = 0x500; 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")); ASSERT_TRUE(elf->Init()); EXPECT_EQ(0x6000U, elf->debug_frame_offset()); EXPECT_EQ(0x500U, elf->debug_frame_size()); EXPECT_EQ(0x5000U, elf->gnu_debugdata_offset()); EXPECT_EQ(0x800U, elf->gnu_debugdata_size()); } TEST_F(ElfInterfaceTest, init_section_headers_offsets32) { InitSectionHeadersOffsets<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(); } TEST_F(ElfInterfaceTest, init_section_headers_offsets64) { InitSectionHeadersOffsets<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(); } Loading
libunwindstack/Elf.h +2 −2 Original line number Diff line number Diff line Loading @@ -45,8 +45,8 @@ class Elf { return valid_ && interface_->GetSoname(name); } bool GetFunctionName(uint64_t, std::string*, uint64_t*) { return false; bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) { return valid_ && interface_->GetFunctionName(addr, name, func_offset); } bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory) { Loading
libunwindstack/ElfInterface.cpp +95 −13 Original line number Diff line number Diff line Loading @@ -22,9 +22,18 @@ #include "DwarfDebugFrame.h" #include "DwarfEhFrame.h" #include "DwarfSection.h" #include "ElfInterface.h" #include "Log.h" #include "Memory.h" #include "Regs.h" #include "Symbols.h" ElfInterface::~ElfInterface() { for (auto symbol : symbols_) { delete symbol; } } template <typename AddressType> void ElfInterface::InitHeadersWithTemplate() { Loading Loading @@ -57,7 +66,13 @@ bool ElfInterface::ReadAllHeaders() { if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr)) { return false; } return ReadSectionHeaders<EhdrType, ShdrType>(ehdr); // We could still potentially unwind without the section header // information, so ignore any errors. if (!ReadSectionHeaders<EhdrType, ShdrType>(ehdr)) { log(0, "Malformed section header found, ignoring..."); } return true; } template <typename EhdrType, typename PhdrType> Loading Loading @@ -147,12 +162,39 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { } // Skip the first header, it's always going to be NULL. offset += ehdr.e_shentsize; for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) { if (!memory_->ReadField(offset, &shdr, &shdr.sh_type, sizeof(shdr.sh_type))) { return false; } if (shdr.sh_type == SHT_PROGBITS) { if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { if (!memory_->Read(offset, &shdr, sizeof(shdr))) { return false; } // Need to go get the information about the section that contains // the string terminated names. ShdrType str_shdr; if (shdr.sh_link >= ehdr.e_shnum) { return false; } uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize; if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_type, sizeof(str_shdr.sh_type))) { return false; } if (str_shdr.sh_type != SHT_STRTAB) { return false; } if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_offset, sizeof(str_shdr.sh_offset))) { return false; } if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_size, sizeof(str_shdr.sh_size))) { return false; } symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize, str_shdr.sh_offset, str_shdr.sh_size)); } else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) { // Look for the .debug_frame and .gnu_debugdata. if (!memory_->ReadField(offset, &shdr, &shdr.sh_name, sizeof(shdr.sh_name))) { return false; Loading @@ -160,18 +202,20 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { if (shdr.sh_name < sec_size) { std::string name; if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) { uint64_t* offset_ptr = nullptr; uint64_t* size_ptr = nullptr; if (name == ".debug_frame") { if (memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) && memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) { debug_frame_offset_ = shdr.sh_offset; debug_frame_size_ = shdr.sh_size; } offset_ptr = &debug_frame_offset_; size_ptr = &debug_frame_size_; } else if (name == ".gnu_debugdata") { if (memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) && memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) { gnu_debugdata_offset_ = shdr.sh_offset; gnu_debugdata_size_ = shdr.sh_size; offset_ptr = &gnu_debugdata_offset_; size_ptr = &gnu_debugdata_size_; } if (offset_ptr != nullptr && memory_->ReadField(offset, &shdr, &shdr.sh_offset, sizeof(shdr.sh_offset)) && memory_->ReadField(offset, &shdr, &shdr.sh_size, sizeof(shdr.sh_size))) { *offset_ptr = shdr.sh_offset; *size_ptr = shdr.sh_size; } } } Loading Loading @@ -228,7 +272,40 @@ bool ElfInterface::GetSonameWithTemplate(std::string* soname) { return true; } bool ElfInterface::Step(uint64_t, Regs*, Memory*) { template <typename SymType> bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, std::string* name, uint64_t* func_offset) { if (symbols_.empty()) { return false; } for (const auto symbol : symbols_) { if (symbol->GetName<SymType>(addr, load_bias_, memory_, name, func_offset)) { return true; } } return false; } bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory) { // Need to subtract off the load_bias to get the correct pc. if (pc < load_bias_) { return false; } pc -= load_bias_; // Try the eh_frame first. DwarfSection* eh_frame = eh_frame_.get(); if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory)) { return true; } // Try the debug_frame next. DwarfSection* debug_frame = debug_frame_.get(); if (debug_frame != nullptr && debug_frame->Step(pc, regs, process_memory)) { return true; } return false; } Loading @@ -247,3 +324,8 @@ template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*); template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*); template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, std::string*, uint64_t*); template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*, uint64_t*);
libunwindstack/ElfInterface.h +11 −5 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ // Forward declarations. class Memory; class Regs; class Symbols; struct LoadInfo { uint64_t offset; Loading @@ -46,7 +47,7 @@ enum : uint8_t { class ElfInterface { public: ElfInterface(Memory* memory) : memory_(memory) {} virtual ~ElfInterface() = default; virtual ~ElfInterface(); virtual bool Init() = 0; Loading Loading @@ -94,6 +95,9 @@ class ElfInterface { template <typename DynType> bool GetSonameWithTemplate(std::string* soname); template <typename SymType> bool GetFunctionNameWithTemplate(uint64_t addr, std::string* name, uint64_t* func_offset); virtual bool HandleType(uint64_t, uint32_t) { return false; } Memory* memory_; Loading @@ -118,6 +122,8 @@ class ElfInterface { std::unique_ptr<DwarfSection> eh_frame_; std::unique_ptr<DwarfSection> debug_frame_; std::vector<Symbols*> symbols_; }; class ElfInterface32 : public ElfInterface { Loading @@ -135,8 +141,8 @@ class ElfInterface32 : public ElfInterface { return ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(soname); } bool GetFunctionName(uint64_t, std::string*, uint64_t*) override { return false; bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset); } }; Loading @@ -155,8 +161,8 @@ class ElfInterface64 : public ElfInterface { return ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(soname); } bool GetFunctionName(uint64_t, std::string*, uint64_t*) override { return false; bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset); } }; Loading
libunwindstack/tests/ElfInterfaceTest.cpp +203 −0 Original line number Diff line number Diff line Loading @@ -79,9 +79,37 @@ class ElfInterfaceTest : public ::testing::Test { template <typename ElfType> void InitHeadersDebugFrameFail(); template <typename Ehdr, typename Shdr, typename ElfInterfaceType> void InitSectionHeadersMalformed(); template <typename Ehdr, typename Shdr, typename Sym, typename ElfInterfaceType> void InitSectionHeaders(uint64_t entry_size); template <typename Ehdr, typename Shdr, typename ElfInterfaceType> void InitSectionHeadersOffsets(); template <typename Sym> void InitSym(uint64_t offset, uint32_t value, uint32_t size, uint32_t name_offset, uint64_t sym_offset, const char* name); MemoryFake memory_; }; template <typename Sym> void ElfInterfaceTest::InitSym(uint64_t offset, uint32_t value, uint32_t size, uint32_t name_offset, uint64_t sym_offset, const char* name) { Sym sym; memset(&sym, 0, sizeof(sym)); sym.st_info = STT_FUNC; sym.st_value = value; sym.st_size = size; sym.st_name = name_offset; sym.st_shndx = SHN_COMMON; memory_.SetMemory(offset, &sym, sizeof(sym)); memory_.SetMemory(sym_offset + name_offset, name, strlen(name) + 1); } template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType> void ElfInterfaceTest::SinglePtLoad() { std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_)); Loading Loading @@ -718,3 +746,178 @@ TEST_F(ElfInterfaceTest, init_headers_debug_frame32_fail) { TEST_F(ElfInterfaceTest, init_headers_debug_frame64_fail) { InitHeadersDebugFrameFail<MockElfInterface64>(); } template <typename Ehdr, typename Shdr, typename ElfInterfaceType> void ElfInterfaceTest::InitSectionHeadersMalformed() { std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_)); Ehdr ehdr; memset(&ehdr, 0, sizeof(ehdr)); ehdr.e_shoff = 0x1000; ehdr.e_shnum = 10; ehdr.e_shentsize = sizeof(Shdr); memory_.SetMemory(0, &ehdr, sizeof(ehdr)); ASSERT_TRUE(elf->Init()); } TEST_F(ElfInterfaceTest, init_section_headers_malformed32) { InitSectionHeadersMalformed<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(); } TEST_F(ElfInterfaceTest, init_section_headers_malformed64) { InitSectionHeadersMalformed<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(); } template <typename Ehdr, typename Shdr, typename Sym, typename ElfInterfaceType> void ElfInterfaceTest::InitSectionHeaders(uint64_t entry_size) { std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_)); uint64_t offset = 0x1000; Ehdr ehdr; memset(&ehdr, 0, sizeof(ehdr)); ehdr.e_shoff = offset; ehdr.e_shnum = 10; ehdr.e_shentsize = entry_size; memory_.SetMemory(0, &ehdr, sizeof(ehdr)); offset += ehdr.e_shentsize; Shdr shdr; memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_SYMTAB; shdr.sh_link = 4; shdr.sh_addr = 0x5000; shdr.sh_offset = 0x5000; shdr.sh_entsize = sizeof(Sym); shdr.sh_size = shdr.sh_entsize * 10; memory_.SetMemory(offset, &shdr, sizeof(shdr)); offset += ehdr.e_shentsize; memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_DYNSYM; shdr.sh_link = 4; shdr.sh_addr = 0x6000; shdr.sh_offset = 0x6000; shdr.sh_entsize = sizeof(Sym); shdr.sh_size = shdr.sh_entsize * 10; memory_.SetMemory(offset, &shdr, sizeof(shdr)); offset += ehdr.e_shentsize; memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_PROGBITS; shdr.sh_name = 0xa000; memory_.SetMemory(offset, &shdr, sizeof(shdr)); offset += ehdr.e_shentsize; // The string data for the entries. 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; InitSym<Sym>(0x5000, 0x90000, 0x1000, 0x100, 0xf000, "function_one"); InitSym<Sym>(0x6000, 0xd0000, 0x1000, 0x300, 0xf000, "function_two"); ASSERT_TRUE(elf->Init()); EXPECT_EQ(0U, elf->debug_frame_offset()); EXPECT_EQ(0U, elf->debug_frame_size()); EXPECT_EQ(0U, elf->gnu_debugdata_offset()); EXPECT_EQ(0U, elf->gnu_debugdata_size()); // Look in the first symbol table. std::string name; uint64_t name_offset; ASSERT_TRUE(elf->GetFunctionName(0x90010, &name, &name_offset)); EXPECT_EQ("function_one", name); EXPECT_EQ(16U, name_offset); ASSERT_TRUE(elf->GetFunctionName(0xd0020, &name, &name_offset)); EXPECT_EQ("function_two", name); EXPECT_EQ(32U, name_offset); } TEST_F(ElfInterfaceTest, init_section_headers32) { InitSectionHeaders<Elf32_Ehdr, Elf32_Shdr, Elf32_Sym, ElfInterface32>(sizeof(Elf32_Shdr)); } TEST_F(ElfInterfaceTest, init_section_headers64) { InitSectionHeaders<Elf64_Ehdr, Elf64_Shdr, Elf64_Sym, ElfInterface64>(sizeof(Elf64_Shdr)); } TEST_F(ElfInterfaceTest, init_section_headers_non_std_entry_size32) { InitSectionHeaders<Elf32_Ehdr, Elf32_Shdr, Elf32_Sym, ElfInterface32>(0x100); } TEST_F(ElfInterfaceTest, init_section_headers_non_std_entry_size64) { InitSectionHeaders<Elf64_Ehdr, Elf64_Shdr, Elf64_Sym, ElfInterface64>(0x100); } template <typename Ehdr, typename Shdr, typename ElfInterfaceType> void ElfInterfaceTest::InitSectionHeadersOffsets() { std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_)); uint64_t offset = 0x2000; Ehdr ehdr; memset(&ehdr, 0, sizeof(ehdr)); ehdr.e_shoff = offset; ehdr.e_shnum = 10; ehdr.e_shentsize = sizeof(Shdr); ehdr.e_shstrndx = 2; memory_.SetMemory(0, &ehdr, sizeof(ehdr)); offset += ehdr.e_shentsize; Shdr shdr; memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_PROGBITS; shdr.sh_link = 2; shdr.sh_name = 0x200; shdr.sh_addr = 0x5000; shdr.sh_offset = 0x5000; shdr.sh_entsize = 0x100; shdr.sh_size = 0x800; 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; memset(&shdr, 0, sizeof(shdr)); shdr.sh_type = SHT_PROGBITS; shdr.sh_link = 2; shdr.sh_name = 0x100; shdr.sh_addr = 0x6000; shdr.sh_offset = 0x6000; shdr.sh_entsize = 0x100; shdr.sh_size = 0x500; 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")); ASSERT_TRUE(elf->Init()); EXPECT_EQ(0x6000U, elf->debug_frame_offset()); EXPECT_EQ(0x500U, elf->debug_frame_size()); EXPECT_EQ(0x5000U, elf->gnu_debugdata_offset()); EXPECT_EQ(0x800U, elf->gnu_debugdata_size()); } TEST_F(ElfInterfaceTest, init_section_headers_offsets32) { InitSectionHeadersOffsets<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(); } TEST_F(ElfInterfaceTest, init_section_headers_offsets64) { InitSectionHeadersOffsets<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(); }