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

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

Fix issues in libunwindstack.

- Add a load_bias field in MapInfo so that it can be loaded offline,
  and also so it can be cached.
- Add an Add function to the Maps class so that it's possible to manually
  create a map.
- Remove the OfflineMaps class since I haven't found a reason for this to
  exist.
- Add a pointer to the gnu debugdata compressed section in the interface
  itself and modify the step path to try eh_frame, then debug_frame, then
  gnu_debugdata. This way arm can add exidx as the last step behind
  gnu_debugdata. Add an offline test to verify the order of unwind.
- Fix x86_64_ucontext_t since it was a different size on 32 bit and 64 bit
  systems.

Test: Pass new unit tests.
Change-Id: I978b70d6c244bd307c62a29886d24c1a8cb2af23
parent 3fca6751
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -167,6 +167,7 @@ cc_test {
    data: [
        "tests/files/elf32.xz",
        "tests/files/elf64.xz",
        "tests/files/offline/gnu_debugdata_arm32/*",
        "tests/files/offline/straddle_arm32/*",
        "tests/files/offline/straddle_arm64/*",
    ],
+2 −9
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ void Elf::InitGnuDebugdata() {
  uint64_t load_bias;
  if (gnu->Init(&load_bias)) {
    gnu->InitHeaders();
    interface_->SetGnuDebugdataInterface(gnu);
  } else {
    // Free all of the memory associated with the gnu_debugdata section.
    gnu_debugdata_memory_.reset(nullptr);
@@ -115,17 +116,9 @@ bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, uint64_t elf_offset, R
    return true;
  }

  // Adjust the load bias to get the real relative pc.
  if (adjusted_rel_pc < load_bias_) {
    return false;
  }
  adjusted_rel_pc -= load_bias_;

  // Lock during the step which can update information in the object.
  std::lock_guard<std::mutex> guard(lock_);
  return interface_->Step(adjusted_rel_pc, regs, process_memory, finished) ||
         (gnu_debugdata_interface_ &&
          gnu_debugdata_interface_->Step(adjusted_rel_pc, regs, process_memory, finished));
  return interface_->Step(adjusted_rel_pc, load_bias_, regs, process_memory, finished);
}

bool Elf::IsValidElf(Memory* memory) {
+16 −3
Original line number Diff line number Diff line
@@ -386,16 +386,29 @@ bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, uint64_t load_bias
  return false;
}

bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
bool ElfInterface::Step(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory,
                        bool* finished) {
  // Adjust the load bias to get the real relative pc.
  if (pc < load_bias) {
    return false;
  }
  uint64_t adjusted_pc = pc - load_bias;

  // Try the eh_frame first.
  DwarfSection* eh_frame = eh_frame_.get();
  if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory, finished)) {
  if (eh_frame != nullptr && eh_frame->Step(adjusted_pc, regs, process_memory, finished)) {
    return true;
  }

  // Try the debug_frame next.
  DwarfSection* debug_frame = debug_frame_.get();
  if (debug_frame != nullptr && debug_frame->Step(pc, regs, process_memory, finished)) {
  if (debug_frame != nullptr && debug_frame->Step(adjusted_pc, regs, process_memory, finished)) {
    return true;
  }

  // Finally try the gnu_debugdata interface, but always use a zero load bias.
  if (gnu_debugdata_interface_ != nullptr &&
      gnu_debugdata_interface_->Step(pc, 0, regs, process_memory, finished)) {
    return true;
  }
  return false;
+12 −4
Original line number Diff line number Diff line
@@ -92,16 +92,24 @@ bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type, uint64_t load_b
  return true;
}

bool ElfInterfaceArm::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
bool ElfInterfaceArm::Step(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory,
                           bool* finished) {
  // Dwarf unwind information is precise about whether a pc is covered or not,
  // but arm unwind information only has ranges of pc. In order to avoid
  // incorrectly doing a bad unwind using arm unwind information for a
  // different function, always try and unwind with the dwarf information first.
  return ElfInterface32::Step(pc, regs, process_memory, finished) ||
         StepExidx(pc, regs, process_memory, finished);
  return ElfInterface32::Step(pc, load_bias, regs, process_memory, finished) ||
         StepExidx(pc, load_bias, regs, process_memory, finished);
}

bool ElfInterfaceArm::StepExidx(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
bool ElfInterfaceArm::StepExidx(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory,
                                bool* finished) {
  // Adjust the load bias to get the real relative pc.
  if (pc < load_bias) {
    return false;
  }
  pc -= load_bias;

  RegsArm* regs_arm = reinterpret_cast<RegsArm*>(regs);
  uint64_t entry_offset;
  if (!FindEntry(pc, &entry_offset)) {
+4 −2
Original line number Diff line number Diff line
@@ -70,9 +70,11 @@ class ElfInterfaceArm : public ElfInterface32 {

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

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

  bool StepExidx(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished);
  bool StepExidx(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* process_memory,
                 bool* finished);

  uint64_t start_offset() { return start_offset_; }

Loading