Merge "Fix soname reading code."
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index e413081..10afe33 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -19,6 +19,7 @@
#include <memory>
#include <string>
+#include <utility>
#include <7zCrc.h>
#include <Xz.h>
@@ -322,19 +323,13 @@
// 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 @@
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 @@
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 @@
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 @@
}
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 @@
}
}
- 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>
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index ea9ec9d..3a221bc 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -157,6 +157,7 @@
ElfInterface* gnu_debugdata_interface_ = nullptr;
std::vector<Symbols*> symbols_;
+ std::vector<std::pair<uint64_t, uint64_t>> strtabs_;
};
class ElfInterface32 : public ElfInterface {
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index 042c5fb..bf97e30 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -63,15 +63,28 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
}
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>
diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
index 7f2d11d..a0abcca 100644
--- a/libunwindstack/tools/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -120,6 +120,11 @@
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));
diff --git a/libunwindstack/tools/unwind_reg_info.cpp b/libunwindstack/tools/unwind_reg_info.cpp
index 4d89087..47a4f91 100644
--- a/libunwindstack/tools/unwind_reg_info.cpp
+++ b/libunwindstack/tools/unwind_reg_info.cpp
@@ -157,6 +157,11 @@
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 697e4cd..086dffe 100644
--- a/libunwindstack/tools/unwind_symbols.cpp
+++ b/libunwindstack/tools/unwind_symbols.cpp
@@ -71,6 +71,11 @@
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");