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

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

Merge "libunwindstack: Support signal frame CIEs."

parents f99f09ee 9b8f5459
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -296,6 +296,8 @@ cc_defaults {
        "tests/files/offline/shared_lib_in_apk_memory_only_arm64/*",
        "tests/files/offline/shared_lib_in_apk_single_map_arm64/*",
        "tests/files/offline/signal_load_bias_arm/*",
        "tests/files/offline/signal_fde_x86/*",
        "tests/files/offline/signal_fde_x86_64/*",
        "tests/files/offline/straddle_arm/*",
        "tests/files/offline/straddle_arm64/*",
    ],
+11 −3
Original line number Diff line number Diff line
@@ -37,7 +37,8 @@ namespace unwindstack {

DwarfSection::DwarfSection(Memory* memory) : memory_(memory) {}

bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished,
                        bool* is_signal_frame) {
  // Lookup the pc in the cache.
  auto it = loc_regs_.upper_bound(pc);
  if (it == loc_regs_.end() || pc < it->second.pc_start) {
@@ -59,6 +60,8 @@ bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* f
    it = loc_regs_.emplace(loc_regs.pc_end, std::move(loc_regs)).first;
  }

  *is_signal_frame = it->second.cie->is_signal_frame;

  // Now eval the actual registers.
  return Eval(it->second.cie, process_memory, it->second, regs, finished);
}
@@ -241,6 +244,9 @@ bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) {
          return false;
        }
        break;
      case 'S':
        cie->is_signal_frame = true;
        break;
    }
  }
  return true;
@@ -558,8 +564,10 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me
    cur_regs->set_pc((*cur_regs)[cie->return_address_register]);
  }

  // If the pc was set to zero, consider this the final frame.
  *finished = (cur_regs->pc() == 0) ? true : false;
  // If the pc was set to zero, consider this the final frame. Exception: if
  // this is the sigreturn frame, then we want to try to recover the real PC
  // using the return address (from LR or the stack), so keep going.
  *finished = (cur_regs->pc() == 0 && !cie->is_signal_frame) ? true : false;

  cur_regs->set_sp(eval_info.cfa);

+3 −2
Original line number Diff line number Diff line
@@ -188,14 +188,15 @@ bool Elf::StepIfSignalHandler(uint64_t rel_pc, Regs* regs, Memory* process_memor
}

// The relative pc is always relative to the start of the map from which it comes.
bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished) {
bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished,
               bool* is_signal_frame) {
  if (!valid_) {
    return false;
  }

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

bool Elf::IsValidElf(Memory* memory) {
+6 −4
Original line number Diff line number Diff line
@@ -499,25 +499,27 @@ bool ElfInterface::GetGlobalVariableWithTemplate(const std::string& name, uint64
  return false;
}

bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished,
                        bool* is_signal_frame) {
  last_error_.code = ERROR_NONE;
  last_error_.address = 0;

  // 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(pc, regs, process_memory, finished)) {
  if (debug_frame != nullptr &&
      debug_frame->Step(pc, regs, process_memory, finished, is_signal_frame)) {
    return true;
  }

  // Try the eh_frame next.
  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(pc, regs, process_memory, finished, is_signal_frame)) {
    return true;
  }

  if (gnu_debugdata_interface_ != nullptr &&
      gnu_debugdata_interface_->Step(pc, regs, process_memory, finished)) {
      gnu_debugdata_interface_->Step(pc, regs, process_memory, finished, is_signal_frame)) {
    return true;
  }

+3 −2
Original line number Diff line number Diff line
@@ -100,12 +100,13 @@ void ElfInterfaceArm::HandleUnknownType(uint32_t type, uint64_t ph_offset, uint6
  total_entries_ = ph_filesz / 8;
}

bool ElfInterfaceArm::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
bool ElfInterfaceArm::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished,
                           bool* is_signal_frame) {
  // 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) ||
  return ElfInterface32::Step(pc, regs, process_memory, finished, is_signal_frame) ||
         StepExidx(pc, regs, process_memory, finished);
}

Loading