Merge "Add section parsing and function name handling."
am: 62a17c6c4a
Change-Id: I010d9e6efa6d472242704be7a53e7bfeed24c4d5
This commit is contained in:
commit
ee5c756d25
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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*);
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
// Forward declarations.
|
||||
class Memory;
|
||||
class Regs;
|
||||
class Symbols;
|
||||
|
||||
struct LoadInfo {
|
||||
uint64_t offset;
|
||||
|
@ -46,7 +47,7 @@ enum : uint8_t {
|
|||
class ElfInterface {
|
||||
public:
|
||||
ElfInterface(Memory* memory) : memory_(memory) {}
|
||||
virtual ~ElfInterface() = default;
|
||||
virtual ~ElfInterface();
|
||||
|
||||
virtual bool Init() = 0;
|
||||
|
||||
|
@ -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_;
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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_));
|
||||
|
@ -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…
Reference in New Issue