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

Commit b9c072c5 authored by Mitch Phillips's avatar Mitch Phillips
Browse files

Move PC-only unwind frame generation to libunwindstack.

GWP-ASan uses frame-pointer based unwinding internally on
allocation/deallocation to collect stack traces that are used when
crashes are reported.

This should be generic, so pull it out into libunwindstack so it can be
used by MTE as well.

Bug: 152412331
Test: atest debuggerd_test
Change-Id: I27b32263aac63446f5fe398af108676b70cd3971
parent 1e413c8a
Loading
Loading
Loading
Loading
+4 −56
Original line number Original line Diff line number Diff line
@@ -157,60 +157,6 @@ void GwpAsanCrashData::DumpCause(log_t* log) const {
       error_string_, diff, byte_suffix, location_str, alloc_size, alloc_address);
       error_string_, diff, byte_suffix, location_str, alloc_size, alloc_address);
}
}


// Build a frame for symbolization using the maps from the provided unwinder.
// The constructed frame contains just enough information to be used to
// symbolize a GWP-ASan stack trace.
static unwindstack::FrameData BuildFrame(unwindstack::Unwinder* unwinder, uintptr_t pc,
                                         size_t frame_num) {
  unwindstack::FrameData frame;
  frame.num = frame_num;

  unwindstack::Maps* maps = unwinder->GetMaps();
  unwindstack::MapInfo* map_info = maps->Find(pc);
  if (!map_info) {
    frame.rel_pc = pc;
    return frame;
  }

  unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch();
  unwindstack::Elf* elf = map_info->GetElf(unwinder->GetProcessMemory(), arch);

  uint64_t relative_pc = elf->GetRelPc(pc, map_info);

  uint64_t pc_adjustment = unwindstack::GetPcAdjustment(relative_pc, elf, arch);
  relative_pc -= pc_adjustment;
  // The debug PC may be different if the PC comes from the JIT.
  uint64_t debug_pc = relative_pc;

  // If we don't have a valid ELF file, check the JIT.
  if (!elf->valid()) {
    unwindstack::JitDebug jit_debug(unwinder->GetProcessMemory());
    uint64_t jit_pc = pc - pc_adjustment;
    unwindstack::Elf* jit_elf = jit_debug.GetElf(maps, jit_pc);
    if (jit_elf != nullptr) {
      debug_pc = jit_pc;
      elf = jit_elf;
    }
  }

  // Copy all the things we need into the frame for symbolization.
  frame.rel_pc = relative_pc;
  frame.pc = pc - pc_adjustment;
  frame.map_name = map_info->name;
  frame.map_elf_start_offset = map_info->elf_start_offset;
  frame.map_exact_offset = map_info->offset;
  frame.map_start = map_info->start;
  frame.map_end = map_info->end;
  frame.map_flags = map_info->flags;
  frame.map_load_bias = elf->GetLoadBias();

  if (!elf->GetFunctionName(relative_pc, &frame.function_name, &frame.function_offset)) {
    frame.function_name = "";
    frame.function_offset = 0;
  }
  return frame;
}

constexpr size_t kMaxTraceLength = gwp_asan::AllocationMetadata::kMaxTraceLengthToCollect;
constexpr size_t kMaxTraceLength = gwp_asan::AllocationMetadata::kMaxTraceLengthToCollect;


bool GwpAsanCrashData::HasDeallocationTrace() const {
bool GwpAsanCrashData::HasDeallocationTrace() const {
@@ -237,7 +183,8 @@ void GwpAsanCrashData::DumpDeallocationTrace(log_t* log, unwindstack::Unwinder*


  unwinder->SetDisplayBuildID(true);
  unwinder->SetDisplayBuildID(true);
  for (size_t i = 0; i < num_frames; ++i) {
  for (size_t i = 0; i < num_frames; ++i) {
    unwindstack::FrameData frame_data = BuildFrame(unwinder, frames.get()[i], i);
    unwindstack::FrameData frame_data = unwinder->BuildFrameFromPcOnly(frames.get()[i]);
    frame_data.num = i;
    _LOG(log, logtype::BACKTRACE, "    %s\n", unwinder->FormatFrame(frame_data).c_str());
    _LOG(log, logtype::BACKTRACE, "    %s\n", unwinder->FormatFrame(frame_data).c_str());
  }
  }
}
}
@@ -263,7 +210,8 @@ void GwpAsanCrashData::DumpAllocationTrace(log_t* log, unwindstack::Unwinder* un


  unwinder->SetDisplayBuildID(true);
  unwinder->SetDisplayBuildID(true);
  for (size_t i = 0; i < num_frames; ++i) {
  for (size_t i = 0; i < num_frames; ++i) {
    unwindstack::FrameData frame_data = BuildFrame(unwinder, frames.get()[i], i);
    unwindstack::FrameData frame_data = unwinder->BuildFrameFromPcOnly(frames.get()[i]);
    frame_data.num = i;
    _LOG(log, logtype::BACKTRACE, "    %s\n", unwinder->FormatFrame(frame_data).c_str());
    _LOG(log, logtype::BACKTRACE, "    %s\n", unwinder->FormatFrame(frame_data).c_str());
  }
  }
}
}
+50 −0
Original line number Original line Diff line number Diff line
@@ -395,4 +395,54 @@ bool UnwinderFromPid::Init(ArchEnum arch) {
  return true;
  return true;
}
}


FrameData Unwinder::BuildFrameFromPcOnly(uint64_t pc) {
  FrameData frame;

  Maps* maps = GetMaps();
  MapInfo* map_info = maps->Find(pc);
  if (!map_info) {
    frame.rel_pc = pc;
    return frame;
  }

  ArchEnum arch = Regs::CurrentArch();
  Elf* elf = map_info->GetElf(GetProcessMemory(), arch);

  uint64_t relative_pc = elf->GetRelPc(pc, map_info);

  uint64_t pc_adjustment = GetPcAdjustment(relative_pc, elf, arch);
  relative_pc -= pc_adjustment;
  // The debug PC may be different if the PC comes from the JIT.
  uint64_t debug_pc = relative_pc;

  // If we don't have a valid ELF file, check the JIT.
  if (!elf->valid()) {
    JitDebug jit_debug(GetProcessMemory());
    uint64_t jit_pc = pc - pc_adjustment;
    Elf* jit_elf = jit_debug.GetElf(maps, jit_pc);
    if (jit_elf != nullptr) {
      debug_pc = jit_pc;
      elf = jit_elf;
    }
  }

  // Copy all the things we need into the frame for symbolization.
  frame.rel_pc = relative_pc;
  frame.pc = pc - pc_adjustment;
  frame.map_name = map_info->name;
  frame.map_elf_start_offset = map_info->elf_start_offset;
  frame.map_exact_offset = map_info->offset;
  frame.map_start = map_info->start;
  frame.map_end = map_info->end;
  frame.map_flags = map_info->flags;
  frame.map_load_bias = elf->GetLoadBias();

  if (!resolve_names_ ||
      !elf->GetFunctionName(relative_pc, &frame.function_name, &frame.function_offset)) {
    frame.function_name = "";
    frame.function_offset = 0;
  }
  return frame;
}

}  // namespace unwindstack
}  // namespace unwindstack
+7 −0
Original line number Original line Diff line number Diff line
@@ -114,6 +114,13 @@ class Unwinder {
  ErrorCode LastErrorCode() { return last_error_.code; }
  ErrorCode LastErrorCode() { return last_error_.code; }
  uint64_t LastErrorAddress() { return last_error_.address; }
  uint64_t LastErrorAddress() { return last_error_.address; }


  // Builds a frame for symbolization using the maps from this unwinder. The
  // constructed frame contains just enough information to be used to symbolize
  // frames collected by frame-pointer unwinding that's done outside of
  // libunwindstack. This is used by tombstoned to symbolize frame pointer-based
  // stack traces that are collected by tools such as GWP-ASan and MTE.
  FrameData BuildFrameFromPcOnly(uint64_t pc);

 protected:
 protected:
  Unwinder(size_t max_frames) : max_frames_(max_frames) { frames_.reserve(max_frames); }
  Unwinder(size_t max_frames) : max_frames_(max_frames) { frames_.reserve(max_frames); }