Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 76eda07f authored by Christopher Ferris's avatar Christopher Ferris Committed by Gerrit Code Review
Browse files

Merge "Fix soname reading code."

parents ffe12c60 beae42bc
Loading
Loading
Loading
Loading
+27 −44
Original line number Diff line number Diff line
@@ -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,8 +422,11 @@ bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
    }
  }

  soname_offset += strtab_offset;
  if (soname_offset >= strtab_offset + strtab_size) {
  // 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_)) {
@@ -456,6 +436,9 @@ bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
      *soname = soname_;
      return true;
    }
  }
  return false;
}

template <typename SymType>
bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, uint64_t load_bias, std::string* name,
+1 −0
Original line number Diff line number Diff line
@@ -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 {
+84 −89
Original line number Diff line number Diff line
@@ -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,14 +512,24 @@ 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;
  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;
@@ -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,53 +578,42 @@ 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);
  uint64_t load_bias = 0;
  ASSERT_TRUE(elf->Init(&load_bias));
  EXPECT_EQ(0U, load_bias);

  dyn.d_tag = DT_STRSZ;
  dyn.d_un.d_val = 0x10;
  memory_.SetMemory(offset, &dyn, sizeof(dyn));
  offset += sizeof(dyn);
  std::string name;
  ASSERT_FALSE(elf->GetSoname(&name));
}

  dyn.d_tag = DT_SONAME;
  dyn.d_un.d_val = 0x10;
  memory_.SetMemory(offset, &dyn, sizeof(dyn));
  offset += sizeof(dyn);
TEST_F(ElfInterfaceTest, elf32_soname_size) {
  SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>(SONAME_DTSIZE_SMALL);
  SonameSize<ElfInterface32>();
}

  dyn.d_tag = DT_NULL;
  memory_.SetMemory(offset, &dyn, sizeof(dyn));
TEST_F(ElfInterfaceTest, elf64_soname_size) {
  SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>(SONAME_DTSIZE_SMALL);
  SonameSize<ElfInterface64>();
}

  SetStringMemory(0x10010, "fake_soname.so");
// 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));
@@ -630,12 +623,14 @@ void ElfInterfaceTest::SonameSize() {
  ASSERT_FALSE(elf->GetSoname(&name));
}

TEST_F(ElfInterfaceTest, elf32_soname_size) {
  SonameSize<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn, ElfInterface32>();
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_size) {
  SonameSize<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
TEST_F(ElfInterfaceTest, elf64_soname_missing_map) {
  SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>(SONAME_MISSING_MAP);
  SonameMissingMap<ElfInterface64>();
}

template <typename ElfType>
+5 −0
Original line number Diff line number Diff line
@@ -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));
+5 −0
Original line number Diff line number Diff line
@@ -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();
Loading