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

Commit f882a388 authored by Christopher Ferris's avatar Christopher Ferris
Browse files

Fix ARM program header values used for exidx.

Before, I was using p_vaddr to get the offset into the elf file where
the exidx frame starts. I changed that to use p_offset since this already
has the load bias offset in it and some elf files do not set p_vaddr
properly.

Also, use p_filesz instead of p_memsz, since again, some elf files do
not set p_memsz to the same as p_filesz.

Bug: 110704153

Test: All libbacktrace/libunwindstack unit tests pass.
Test: Randomly unwind process on a walleye.
Test: Verified that this properly dumps and unwinds the shared
Test: library that sets p_vaddr and p_memsz differently.
Change-Id: Ic7b1e5d07439f4636fa02cd884a8727a5737372b
parent 8ddd1055
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -211,7 +211,7 @@ bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias)
      return false;
      return false;
    }
    }


    if (HandleType(offset, phdr.p_type, *load_bias)) {
    if (HandleType(offset, phdr.p_type)) {
      continue;
      continue;
    }
    }


+9 −7
Original line number Original line Diff line number Diff line
@@ -87,20 +87,22 @@ bool ElfInterfaceArm::GetPrel31Addr(uint32_t offset, uint32_t* addr) {
#define PT_ARM_EXIDX 0x70000001
#define PT_ARM_EXIDX 0x70000001
#endif
#endif


bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type, uint64_t load_bias) {
bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type) {
  if (type != PT_ARM_EXIDX) {
  if (type != PT_ARM_EXIDX) {
    return false;
    return false;
  }
  }


  Elf32_Phdr phdr;
  Elf32_Phdr phdr;
  if (!memory_->ReadField(offset, &phdr, &phdr.p_vaddr, sizeof(phdr.p_vaddr))) {
  if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
    return true;
    return true;
  }
  }
  if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {

    return true;
  // The offset already takes into account the load bias.
  }
  start_offset_ = phdr.p_offset;
  start_offset_ = phdr.p_vaddr - load_bias;

  total_entries_ = phdr.p_memsz / 8;
  // Always use filesz instead of memsz. In most cases they are the same,
  // but some shared libraries wind up setting one correctly and not the other.
  total_entries_ = phdr.p_filesz / 8;
  return true;
  return true;
}
}


+1 −1
Original line number Original line Diff line number Diff line
@@ -70,7 +70,7 @@ class ElfInterfaceArm : public ElfInterface32 {


  bool FindEntry(uint32_t pc, uint64_t* entry_offset);
  bool FindEntry(uint32_t pc, uint64_t* entry_offset);


  bool HandleType(uint64_t offset, uint32_t type, uint64_t load_bias) override;
  bool HandleType(uint64_t offset, uint32_t type) override;


  bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) override;
  bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) override;


+1 −1
Original line number Original line Diff line number Diff line
@@ -118,7 +118,7 @@ class ElfInterface {
  template <typename SymType>
  template <typename SymType>
  bool GetGlobalVariableWithTemplate(const std::string& name, uint64_t* memory_address);
  bool GetGlobalVariableWithTemplate(const std::string& name, uint64_t* memory_address);


  virtual bool HandleType(uint64_t, uint32_t, uint64_t) { return false; }
  virtual bool HandleType(uint64_t, uint32_t) { return false; }


  template <typename EhdrType>
  template <typename EhdrType>
  static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size);
  static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size);
+20 −35
Original line number Original line Diff line number Diff line
@@ -245,56 +245,41 @@ TEST_F(ElfInterfaceArmTest, iterate) {
TEST_F(ElfInterfaceArmTest, HandleType_not_arm_exidx) {
TEST_F(ElfInterfaceArmTest, HandleType_not_arm_exidx) {
  ElfInterfaceArmFake interface(&memory_);
  ElfInterfaceArmFake interface(&memory_);


  ASSERT_FALSE(interface.HandleType(0x1000, PT_NULL, 0));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_NULL));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_LOAD, 0));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_LOAD));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_DYNAMIC, 0));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_DYNAMIC));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_INTERP, 0));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_INTERP));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_NOTE, 0));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_NOTE));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_SHLIB, 0));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_SHLIB));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_PHDR, 0));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_PHDR));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_TLS, 0));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_TLS));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_LOOS, 0));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_LOOS));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_HIOS, 0));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_HIOS));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_LOPROC, 0));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_LOPROC));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_HIPROC, 0));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_HIPROC));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_EH_FRAME, 0));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_EH_FRAME));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_STACK, 0));
  ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_STACK));
}
}


TEST_F(ElfInterfaceArmTest, HandleType_arm_exidx) {
TEST_F(ElfInterfaceArmTest, HandleType_arm_exidx) {
  ElfInterfaceArmFake interface(&memory_);
  ElfInterfaceArmFake interface(&memory_);


  Elf32_Phdr phdr;
  Elf32_Phdr phdr = {};
  interface.FakeSetStartOffset(0x1000);
  interface.FakeSetStartOffset(0x1000);
  interface.FakeSetTotalEntries(100);
  interface.FakeSetTotalEntries(100);
  phdr.p_vaddr = 0x2000;
  phdr.p_offset = 0x2000;
  phdr.p_memsz = 0xa00;
  phdr.p_filesz = 0xa00;


  // Verify that if reads fail, we don't set the values but still get true.
  // Verify that if reads fail, we don't set the values but still get true.
  ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0));
  ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
  ASSERT_EQ(0x1000U, interface.start_offset());
  ASSERT_EQ(100U, interface.total_entries());

  // Verify that if the second read fails, we still don't set the values.
  memory_.SetData32(
      0x1000 + reinterpret_cast<uint64_t>(&phdr.p_vaddr) - reinterpret_cast<uint64_t>(&phdr),
      phdr.p_vaddr);
  ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0));
  ASSERT_EQ(0x1000U, interface.start_offset());
  ASSERT_EQ(0x1000U, interface.start_offset());
  ASSERT_EQ(100U, interface.total_entries());
  ASSERT_EQ(100U, interface.total_entries());


  // Everything is correct and present.
  // Everything is correct and present.
  memory_.SetData32(
  memory_.SetMemory(0x1000, &phdr, sizeof(phdr));
      0x1000 + reinterpret_cast<uint64_t>(&phdr.p_memsz) - reinterpret_cast<uint64_t>(&phdr),
  ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
      phdr.p_memsz);
  ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0));
  ASSERT_EQ(0x2000U, interface.start_offset());
  ASSERT_EQ(0x2000U, interface.start_offset());
  ASSERT_EQ(320U, interface.total_entries());
  ASSERT_EQ(320U, interface.total_entries());

  // Non-zero load bias.
  ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0x1000));
  ASSERT_EQ(0x1000U, interface.start_offset());
  ASSERT_EQ(320U, interface.total_entries());
}
}


TEST_F(ElfInterfaceArmTest, StepExidx) {
TEST_F(ElfInterfaceArmTest, StepExidx) {
Loading