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
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 560030e..2d867cd 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -395,4 +395,54 @@
   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
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 67762c0..4d49f23 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -114,6 +114,13 @@
   ErrorCode LastErrorCode() { return last_error_.code; }
   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:
   Unwinder(size_t max_frames) : max_frames_(max_frames) { frames_.reserve(max_frames); }