Merge "Fix soname reading code."

This commit is contained in:
Christopher Ferris 2018-02-16 17:25:42 +00:00 committed by Gerrit Code Review
commit 76eda07ff6
6 changed files with 130 additions and 136 deletions

View File

@ -19,6 +19,7 @@
#include <memory>
#include <string>
#include <utility>
#include <7zCrc.h>
#include <Xz.h>
@ -322,19 +323,13 @@ 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))) {
if (!memory_->Read(offset, &shdr, sizeof(shdr))) {
last_error_.code = ERROR_MEMORY_INVALID;
last_error_.address =
offset + reinterpret_cast<uintptr_t>(&shdr.sh_type) - reinterpret_cast<uintptr_t>(&shdr);
last_error_.address = offset;
return false;
}
if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
if (!memory_->ReadFully(offset, &shdr, sizeof(shdr))) {
last_error_.code = ERROR_MEMORY_INVALID;
last_error_.address = offset;
return false;
}
// Need to go get the information about the section that contains
// the string terminated names.
ShdrType str_shdr;
@ -343,39 +338,19 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
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))) {
if (!memory_->Read(str_offset, &str_shdr, sizeof(str_shdr))) {
last_error_.code = ERROR_MEMORY_INVALID;
last_error_.address = str_offset + reinterpret_cast<uintptr_t>(&str_shdr.sh_type) -
reinterpret_cast<uintptr_t>(&str_shdr);
last_error_.address = str_offset;
return false;
}
if (str_shdr.sh_type != SHT_STRTAB) {
last_error_.code = ERROR_UNWIND_INFO;
return false;
}
if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_offset,
sizeof(str_shdr.sh_offset))) {
last_error_.code = ERROR_MEMORY_INVALID;
last_error_.address = str_offset + reinterpret_cast<uintptr_t>(&str_shdr.sh_offset) -
reinterpret_cast<uintptr_t>(&str_shdr);
return false;
}
if (!memory_->ReadField(str_offset, &str_shdr, &str_shdr.sh_size, sizeof(str_shdr.sh_size))) {
last_error_.code = ERROR_MEMORY_INVALID;
last_error_.address = str_offset + reinterpret_cast<uintptr_t>(&str_shdr.sh_size) -
reinterpret_cast<uintptr_t>(&str_shdr);
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))) {
last_error_.code = ERROR_MEMORY_INVALID;
last_error_.address = offset + reinterpret_cast<uintptr_t>(&shdr.sh_name) -
reinterpret_cast<uintptr_t>(&shdr);
return false;
}
if (shdr.sh_name < sec_size) {
std::string name;
if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) {
@ -394,14 +369,16 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
offset_ptr = &eh_frame_hdr_offset_;
size_ptr = &eh_frame_hdr_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))) {
if (offset_ptr != nullptr) {
*offset_ptr = shdr.sh_offset;
*size_ptr = shdr.sh_size;
}
}
}
} else if (shdr.sh_type == SHT_STRTAB) {
// 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)));
}
}
return true;
@ -420,7 +397,7 @@ bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
soname_type_ = SONAME_INVALID;
uint64_t soname_offset = 0;
uint64_t strtab_offset = 0;
uint64_t strtab_addr = 0;
uint64_t strtab_size = 0;
// Find the soname location from the dynamic headers section.
@ -435,7 +412,7 @@ bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
}
if (dyn.d_tag == DT_STRTAB) {
strtab_offset = dyn.d_un.d_ptr;
strtab_addr = dyn.d_un.d_ptr;
} else if (dyn.d_tag == DT_STRSZ) {
strtab_size = dyn.d_un.d_val;
} else if (dyn.d_tag == DT_SONAME) {
@ -445,16 +422,22 @@ bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
}
}
soname_offset += strtab_offset;
if (soname_offset >= strtab_offset + strtab_size) {
return false;
// Need to map the strtab address to the real offset.
for (const auto& entry : strtabs_) {
if (entry.first == strtab_addr) {
soname_offset = entry.second + soname_offset;
if (soname_offset >= entry.second + strtab_size) {
return false;
}
if (!memory_->ReadString(soname_offset, &soname_)) {
return false;
}
soname_type_ = SONAME_VALID;
*soname = soname_;
return true;
}
}
if (!memory_->ReadString(soname_offset, &soname_)) {
return false;
}
soname_type_ = SONAME_VALID;
*soname = soname_;
return true;
return false;
}
template <typename SymType>

View File

@ -157,6 +157,7 @@ class ElfInterface {
ElfInterface* gnu_debugdata_interface_ = nullptr;
std::vector<Symbols*> symbols_;
std::vector<std::pair<uint64_t, uint64_t>> strtabs_;
};
class ElfInterface32 : public ElfInterface {

View File

@ -63,15 +63,28 @@ class ElfInterfaceTest : public ::testing::Test {
template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
void ManyPhdrs();
template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
enum SonameTestEnum : uint8_t {
SONAME_NORMAL,
SONAME_DTNULL_AFTER,
SONAME_DTSIZE_SMALL,
SONAME_MISSING_MAP,
};
template <typename Ehdr, typename Phdr, typename Shdr, typename Dyn>
void SonameInit(SonameTestEnum test_type = SONAME_NORMAL);
template <typename ElfInterfaceType>
void Soname();
template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
template <typename ElfInterfaceType>
void SonameAfterDtNull();
template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
template <typename ElfInterfaceType>
void SonameSize();
template <typename ElfInterfaceType>
void SonameMissingMap();
template <typename ElfType>
void InitHeadersEhFrameTest();
@ -465,17 +478,29 @@ TEST_F(ElfInterfaceTest, elf32_arm) {
ASSERT_EQ(2U, elf_arm.total_entries());
}
template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
void ElfInterfaceTest::Soname() {
std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
template <typename Ehdr, typename Phdr, typename Shdr, typename Dyn>
void ElfInterfaceTest::SonameInit(SonameTestEnum test_type) {
Ehdr ehdr;
memset(&ehdr, 0, sizeof(ehdr));
ehdr.e_shoff = 0x200;
ehdr.e_shnum = 2;
ehdr.e_shentsize = sizeof(Shdr);
ehdr.e_phoff = 0x100;
ehdr.e_phnum = 1;
ehdr.e_phentsize = sizeof(Phdr);
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
Shdr shdr;
memset(&shdr, 0, sizeof(shdr));
shdr.sh_type = SHT_STRTAB;
if (test_type == SONAME_MISSING_MAP) {
shdr.sh_addr = 0x20100;
} else {
shdr.sh_addr = 0x10100;
}
shdr.sh_offset = 0x10000;
memory_.SetMemory(0x200 + sizeof(shdr), &shdr, sizeof(shdr));
Phdr phdr;
memset(&phdr, 0, sizeof(phdr));
phdr.p_type = PT_DYNAMIC;
@ -487,15 +512,25 @@ void ElfInterfaceTest::Soname() {
Dyn dyn;
dyn.d_tag = DT_STRTAB;
dyn.d_un.d_ptr = 0x10000;
dyn.d_un.d_ptr = 0x10100;
memory_.SetMemory(offset, &dyn, sizeof(dyn));
offset += sizeof(dyn);
dyn.d_tag = DT_STRSZ;
dyn.d_un.d_val = 0x1000;
if (test_type == SONAME_DTSIZE_SMALL) {
dyn.d_un.d_val = 0x10;
} else {
dyn.d_un.d_val = 0x1000;
}
memory_.SetMemory(offset, &dyn, sizeof(dyn));
offset += sizeof(dyn);
if (test_type == SONAME_DTNULL_AFTER) {
dyn.d_tag = DT_NULL;
memory_.SetMemory(offset, &dyn, sizeof(dyn));
offset += sizeof(dyn);
}
dyn.d_tag = DT_SONAME;
dyn.d_un.d_val = 0x10;
memory_.SetMemory(offset, &dyn, sizeof(dyn));
@ -505,6 +540,11 @@ void ElfInterfaceTest::Soname() {
memory_.SetMemory(offset, &dyn, sizeof(dyn));
SetStringMemory(0x10010, "fake_soname.so");
}
template <typename ElfInterfaceType>
void ElfInterfaceTest::Soname() {
std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
uint64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
@ -516,55 +556,19 @@ void ElfInterfaceTest::Soname() {
}
TEST_F(ElfInterfaceTest, elf32_soname) {
Soname<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn, ElfInterface32>();
SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>();
Soname<ElfInterface32>();
}
TEST_F(ElfInterfaceTest, elf64_soname) {
Soname<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>();
Soname<ElfInterface64>();
}
template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
template <typename ElfInterfaceType>
void ElfInterfaceTest::SonameAfterDtNull() {
std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
Ehdr ehdr;
memset(&ehdr, 0, sizeof(ehdr));
ehdr.e_phoff = 0x100;
ehdr.e_phnum = 1;
ehdr.e_phentsize = sizeof(Phdr);
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
Phdr phdr;
memset(&phdr, 0, sizeof(phdr));
phdr.p_type = PT_DYNAMIC;
phdr.p_offset = 0x2000;
phdr.p_memsz = sizeof(Dyn) * 3;
memory_.SetMemory(0x100, &phdr, sizeof(phdr));
Dyn dyn;
uint64_t offset = 0x2000;
dyn.d_tag = DT_STRTAB;
dyn.d_un.d_ptr = 0x10000;
memory_.SetMemory(offset, &dyn, sizeof(dyn));
offset += sizeof(dyn);
dyn.d_tag = DT_STRSZ;
dyn.d_un.d_val = 0x1000;
memory_.SetMemory(offset, &dyn, sizeof(dyn));
offset += sizeof(dyn);
dyn.d_tag = DT_NULL;
memory_.SetMemory(offset, &dyn, sizeof(dyn));
offset += sizeof(dyn);
dyn.d_tag = DT_SONAME;
dyn.d_un.d_val = 0x10;
memory_.SetMemory(offset, &dyn, sizeof(dyn));
offset += sizeof(dyn);
SetStringMemory(0x10010, "fake_soname.so");
uint64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
EXPECT_EQ(0U, load_bias);
@ -574,54 +578,19 @@ void ElfInterfaceTest::SonameAfterDtNull() {
}
TEST_F(ElfInterfaceTest, elf32_soname_after_dt_null) {
SonameAfterDtNull<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn, ElfInterface32>();
SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>(SONAME_DTNULL_AFTER);
SonameAfterDtNull<ElfInterface32>();
}
TEST_F(ElfInterfaceTest, elf64_soname_after_dt_null) {
SonameAfterDtNull<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>(SONAME_DTNULL_AFTER);
SonameAfterDtNull<ElfInterface64>();
}
template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
template <typename ElfInterfaceType>
void ElfInterfaceTest::SonameSize() {
std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
Ehdr ehdr;
memset(&ehdr, 0, sizeof(ehdr));
ehdr.e_phoff = 0x100;
ehdr.e_phnum = 1;
ehdr.e_phentsize = sizeof(Phdr);
memory_.SetMemory(0, &ehdr, sizeof(ehdr));
Phdr phdr;
memset(&phdr, 0, sizeof(phdr));
phdr.p_type = PT_DYNAMIC;
phdr.p_offset = 0x2000;
phdr.p_memsz = sizeof(Dyn);
memory_.SetMemory(0x100, &phdr, sizeof(phdr));
Dyn dyn;
uint64_t offset = 0x2000;
dyn.d_tag = DT_STRTAB;
dyn.d_un.d_ptr = 0x10000;
memory_.SetMemory(offset, &dyn, sizeof(dyn));
offset += sizeof(dyn);
dyn.d_tag = DT_STRSZ;
dyn.d_un.d_val = 0x10;
memory_.SetMemory(offset, &dyn, sizeof(dyn));
offset += sizeof(dyn);
dyn.d_tag = DT_SONAME;
dyn.d_un.d_val = 0x10;
memory_.SetMemory(offset, &dyn, sizeof(dyn));
offset += sizeof(dyn);
dyn.d_tag = DT_NULL;
memory_.SetMemory(offset, &dyn, sizeof(dyn));
SetStringMemory(0x10010, "fake_soname.so");
uint64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
EXPECT_EQ(0U, load_bias);
@ -631,11 +600,37 @@ void ElfInterfaceTest::SonameSize() {
}
TEST_F(ElfInterfaceTest, elf32_soname_size) {
SonameSize<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn, ElfInterface32>();
SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>(SONAME_DTSIZE_SMALL);
SonameSize<ElfInterface32>();
}
TEST_F(ElfInterfaceTest, elf64_soname_size) {
SonameSize<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>(SONAME_DTSIZE_SMALL);
SonameSize<ElfInterface64>();
}
// Verify that there is no map from STRTAB in the dynamic section to a
// STRTAB entry in the section headers.
template <typename ElfInterfaceType>
void ElfInterfaceTest::SonameMissingMap() {
std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
uint64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
EXPECT_EQ(0U, load_bias);
std::string name;
ASSERT_FALSE(elf->GetSoname(&name));
}
TEST_F(ElfInterfaceTest, elf32_soname_missing_map) {
SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>(SONAME_MISSING_MAP);
SonameMissingMap<ElfInterface32>();
}
TEST_F(ElfInterfaceTest, elf64_soname_missing_map) {
SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>(SONAME_MISSING_MAP);
SonameMissingMap<ElfInterface64>();
}
template <typename ElfType>

View File

@ -120,6 +120,11 @@ int GetElfInfo(const char* file, uint64_t offset) {
return 1;
}
std::string soname;
if (elf.GetSoname(&soname)) {
printf("Soname: %s\n", soname.c_str());
}
ElfInterface* interface = elf.interface();
if (elf.machine_type() == EM_ARM) {
DumpArm(reinterpret_cast<ElfInterfaceArm*>(interface));

View File

@ -157,6 +157,11 @@ int GetInfo(const char* file, uint64_t pc) {
return 1;
}
std::string soname;
if (elf.GetSoname(&soname)) {
printf("Soname: %s\n\n", soname.c_str());
}
printf("PC 0x%" PRIx64 ":\n", pc);
DwarfSection* section = interface->eh_frame();

View File

@ -71,6 +71,11 @@ int main(int argc, char** argv) {
return 1;
}
std::string soname;
if (elf.GetSoname(&soname)) {
printf("Soname: %s\n\n", soname.c_str());
}
switch (elf.machine_type()) {
case EM_ARM:
printf("ABI: arm\n");