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

Commit 1a141a09 authored by Christopher Ferris's avatar Christopher Ferris
Browse files

Small behavioral changes to the unwinder.

- Be a little more lenient when reading the cies/fdes. If next entry data
  winds up incorrect, don't fail, simply stop processing the entries. This
  only applies when reading all of the cies/fdes at once.
- Fail to init an eh_frame with no entries and fallback to assuming the
  eh_frame has no header instead.
- Change the step to always try debug_frame first which has the most
  accurate information.
- Add small unit tests and a couple of offline unit tests to verify
  this behavior.

These changes are needed to support offline unwinding since it depends
on this new behavior.

Bug: 65682279

Test: Ran new unit tests.
Change-Id: I3529f1b0c8e14cd7409494e5de2f3c9e78d0855e
parent 0ad42435
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -170,6 +170,8 @@ cc_test {
    data: [
        "tests/files/elf32.xz",
        "tests/files/elf64.xz",
        "tests/files/offline/bad_eh_frame_hdr_arm64/*",
        "tests/files/offline/debug_frame_first_x86/*",
        "tests/files/offline/jit_debug_arm32/*",
        "tests/files/offline/jit_debug_x86_32/*",
        "tests/files/offline/gnu_debugdata_arm32/*",
+5 −0
Original line number Diff line number Diff line
@@ -64,6 +64,11 @@ bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size) {
    return false;
  }

  if (fde_count_ == 0) {
    last_error_ = DWARF_ERROR_NO_FDES;
    return false;
  }

  entries_offset_ = memory_.cur_offset();
  entries_end_ = offset + size;
  entries_data_offset_ = offset;
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ enum DwarfError : uint8_t {
  DWARF_ERROR_TOO_MANY_ITERATIONS,
  DWARF_ERROR_CFA_NOT_DEFINED,
  DWARF_ERROR_UNSUPPORTED_VERSION,
  DWARF_ERROR_NO_FDES,
};

}  // namespace unwindstack
+2 −3
Original line number Diff line number Diff line
@@ -835,9 +835,8 @@ bool DwarfSectionImpl<AddressType>::CreateSortedFdeList() {
    }

    if (next_entry_offset < memory_.cur_offset()) {
      // This indicates some kind of corruption, or malformed section data.
      last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
      return false;
      // Simply consider the processing done in this case.
      break;
    }
    memory_.set_cur_offset(next_entry_offset);
  }
+19 −14
Original line number Diff line number Diff line
@@ -126,21 +126,25 @@ void ElfInterface::InitHeadersWithTemplate() {
  if (eh_frame_hdr_offset_ != 0) {
    eh_frame_.reset(new DwarfEhFrameWithHdr<AddressType>(memory_));
    if (!eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_)) {
      // Even if the eh_frame_offset_ is non-zero, do not bother
      // trying to read that since something has gone wrong.
      eh_frame_.reset(nullptr);
      eh_frame_hdr_offset_ = 0;
      eh_frame_hdr_size_ = static_cast<uint64_t>(-1);
    }
  } else if (eh_frame_offset_ != 0) {
    // If there is a eh_frame section without a eh_frame_hdr section.
  }

  if (eh_frame_.get() == nullptr && eh_frame_offset_ != 0) {
    // If there is an eh_frame section without an eh_frame_hdr section,
    // or using the frame hdr object failed to init.
    eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
    if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_)) {
      eh_frame_.reset(nullptr);
    }
  }

  if (eh_frame_.get() == nullptr) {
    eh_frame_hdr_offset_ = 0;
    eh_frame_hdr_size_ = static_cast<uint64_t>(-1);
    eh_frame_offset_ = 0;
    eh_frame_size_ = static_cast<uint64_t>(-1);
  }
  }

  if (debug_frame_offset_ != 0) {
    debug_frame_.reset(new DwarfDebugFrame<AddressType>(memory_));
@@ -436,15 +440,16 @@ bool ElfInterface::Step(uint64_t pc, uint64_t load_bias, Regs* regs, Memory* pro
  }
  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(adjusted_pc, regs, process_memory, finished)) {
  // Try the debug_frame first since it contains the most specific unwind
  // information.
  DwarfSection* debug_frame = debug_frame_.get();
  if (debug_frame != nullptr && debug_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(adjusted_pc, regs, process_memory, finished)) {
  // Try the eh_frame next.
  DwarfSection* eh_frame = eh_frame_.get();
  if (eh_frame != nullptr && eh_frame->Step(adjusted_pc, regs, process_memory, finished)) {
    return true;
  }

Loading