Merge "Fix soname reading code."
am: 76eda07ff6

Change-Id: I659a84ac44940ac38a8d31f9a5c3cb102435da07
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");