Fix soname reading code.

The dynamic section contained an address, not an offset into the elf
file to indicate where the soname exists. Changed to use the strtab
entries in the section headers to map this address to the actual offset.

Refactor the soname test a bit to make it easier to verify the code.

Bug: 73499044

Test: Passes new unit tests.
Test: Ran unwind_info on the failing shared elf and verified the soinfo
Test: is correct.
Change-Id: I16ba148389bcb9aadd3566fb442dac27f89fe894
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");