diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp index e41308171..10afe33be 100644 --- a/libunwindstack/ElfInterface.cpp +++ b/libunwindstack/ElfInterface.cpp @@ -19,6 +19,7 @@ #include #include +#include #include <7zCrc.h> #include @@ -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(&shdr.sh_type) - reinterpret_cast(&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(&str_shdr.sh_type) - - reinterpret_cast(&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(&str_shdr.sh_offset) - - reinterpret_cast(&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(&str_shdr.sh_size) - - reinterpret_cast(&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(&shdr.sh_name) - - reinterpret_cast(&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(static_cast(shdr.sh_addr), + static_cast(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 diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h index ea9ec9dac..3a221bc2e 100644 --- a/libunwindstack/include/unwindstack/ElfInterface.h +++ b/libunwindstack/include/unwindstack/ElfInterface.h @@ -157,6 +157,7 @@ class ElfInterface { ElfInterface* gnu_debugdata_interface_ = nullptr; std::vector symbols_; + std::vector> strtabs_; }; class ElfInterface32 : public ElfInterface { diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp index 042c5fb3b..bf97e30bf 100644 --- a/libunwindstack/tests/ElfInterfaceTest.cpp +++ b/libunwindstack/tests/ElfInterfaceTest.cpp @@ -63,15 +63,28 @@ class ElfInterfaceTest : public ::testing::Test { template void ManyPhdrs(); - template + enum SonameTestEnum : uint8_t { + SONAME_NORMAL, + SONAME_DTNULL_AFTER, + SONAME_DTSIZE_SMALL, + SONAME_MISSING_MAP, + }; + + template + void SonameInit(SonameTestEnum test_type = SONAME_NORMAL); + + template void Soname(); - template + template void SonameAfterDtNull(); - template + template void SonameSize(); + template + void SonameMissingMap(); + template void InitHeadersEhFrameTest(); @@ -465,17 +478,29 @@ TEST_F(ElfInterfaceTest, elf32_arm) { ASSERT_EQ(2U, elf_arm.total_entries()); } -template -void ElfInterfaceTest::Soname() { - std::unique_ptr elf(new ElfInterfaceType(&memory_)); - +template +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 +void ElfInterfaceTest::Soname() { + std::unique_ptr 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(); + SonameInit(); + Soname(); } TEST_F(ElfInterfaceTest, elf64_soname) { - Soname(); + SonameInit(); + Soname(); } -template +template void ElfInterfaceTest::SonameAfterDtNull() { std::unique_ptr 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(); + SonameInit(SONAME_DTNULL_AFTER); + SonameAfterDtNull(); } TEST_F(ElfInterfaceTest, elf64_soname_after_dt_null) { - SonameAfterDtNull(); + SonameInit(SONAME_DTNULL_AFTER); + SonameAfterDtNull(); } -template +template void ElfInterfaceTest::SonameSize() { std::unique_ptr 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(); + SonameInit(SONAME_DTSIZE_SMALL); + SonameSize(); } TEST_F(ElfInterfaceTest, elf64_soname_size) { - SonameSize(); + SonameInit(SONAME_DTSIZE_SMALL); + SonameSize(); +} + +// Verify that there is no map from STRTAB in the dynamic section to a +// STRTAB entry in the section headers. +template +void ElfInterfaceTest::SonameMissingMap() { + std::unique_ptr 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(SONAME_MISSING_MAP); + SonameMissingMap(); +} + +TEST_F(ElfInterfaceTest, elf64_soname_missing_map) { + SonameInit(SONAME_MISSING_MAP); + SonameMissingMap(); } template diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp index 7f2d11d67..a0abccae2 100644 --- a/libunwindstack/tools/unwind_info.cpp +++ b/libunwindstack/tools/unwind_info.cpp @@ -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(interface)); diff --git a/libunwindstack/tools/unwind_reg_info.cpp b/libunwindstack/tools/unwind_reg_info.cpp index 4d890879f..47a4f912d 100644 --- a/libunwindstack/tools/unwind_reg_info.cpp +++ b/libunwindstack/tools/unwind_reg_info.cpp @@ -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(); diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp index 697e4cd9e..086dffef3 100644 --- a/libunwindstack/tools/unwind_symbols.cpp +++ b/libunwindstack/tools/unwind_symbols.cpp @@ -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");