Replace libbacktrace with libunwindstack directly.

Small modifications to the dump_stack method and added unit tests to
verify the output.

Bug: 120606663

Test: Unit tests pass, debuggerd run on processes on target.
Change-Id: Id385a915b751abda3dd6baebed6c3ce498c3bf6e
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 10f52f4..4a53a33 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -114,7 +114,6 @@
         "libasync_safe",
         "libbase",
         "libdebuggerd",
-        "libbacktrace",
         "libunwindstack",
         "libdexfile",  // libunwindstack dependency
         "libdexfile_external",  // libunwindstack dependency
@@ -124,7 +123,6 @@
     ],
     target: {
         recovery: {
-            cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
             exclude_static_libs: [
                 "libartbase",
                 "libdexfile",
@@ -164,7 +162,6 @@
 
     srcs: [
         "libdebuggerd/backtrace.cpp",
-        "libdebuggerd/elf_utils.cpp",
         "libdebuggerd/open_files_list.cpp",
         "libdebuggerd/tombstone.cpp",
         "libdebuggerd/utility.cpp",
@@ -177,7 +174,6 @@
     include_dirs: ["bionic/libc"],
 
     static_libs: [
-        "libbacktrace",
         "libdexfile_external",  // libunwindstack dependency
         "libdexfile_support",  // libunwindstack dependency
         "libunwindstack",
@@ -223,7 +219,6 @@
     },
 
     shared_libs: [
-        "libbacktrace",
         "libbase",
         "libcutils",
         "libdebuggerd_client",
@@ -291,7 +286,6 @@
     ],
 
     shared_libs: [
-        "libbacktrace",
         "libbase",
         "liblog",
         "libprocinfo",
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index d79d20b..82ba0a1 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -48,7 +48,12 @@
 #define ATRACE_TAG ATRACE_TAG_BIONIC
 #include <utils/Trace.h>
 
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/JitDebug.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
+#include <unwindstack/Unwinder.h>
 
 #include "libdebuggerd/backtrace.h"
 #include "libdebuggerd/tombstone.h"
@@ -63,8 +68,6 @@
 using android::base::unique_fd;
 using android::base::StringPrintf;
 
-using unwindstack::Regs;
-
 static bool pid_contains_tid(int pid_proc_fd, pid_t tid) {
   struct stat st;
   std::string task_path = StringPrintf("task/%d", tid);
@@ -287,7 +290,8 @@
     case 1:
       *abort_msg_address = crash_info->data.v1.abort_msg_address;
       *siginfo = crash_info->data.v1.siginfo;
-      regs->reset(Regs::CreateFromUcontext(Regs::CurrentArch(), &crash_info->data.v1.ucontext));
+      regs->reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(),
+                                                        &crash_info->data.v1.ucontext));
       break;
 
     default:
@@ -469,7 +473,7 @@
         info.siginfo = &siginfo;
         info.signo = info.siginfo->si_signo;
       } else {
-        info.registers.reset(Regs::RemoteGet(thread));
+        info.registers.reset(unwindstack::Regs::RemoteGet(thread));
         if (!info.registers) {
           PLOG(WARNING) << "failed to fetch registers for thread " << thread;
           ptrace(PTRACE_DETACH, thread, 0, 0);
@@ -562,30 +566,25 @@
   }
 
   // TODO: Use seccomp to lock ourselves down.
-  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(vm_pid, false));
-  if (!map) {
-    LOG(FATAL) << "failed to create backtrace map";
-  }
-
-  std::shared_ptr<unwindstack::Memory> process_memory = map->GetProcessMemory();
-  if (!process_memory) {
-    LOG(FATAL) << "failed to get unwindstack::Memory handle";
+  unwindstack::UnwinderFromPid unwinder(256, vm_pid);
+  if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
+    LOG(FATAL) << "Failed to init unwinder object.";
   }
 
   std::string amfd_data;
   if (backtrace) {
     ATRACE_NAME("dump_backtrace");
-    dump_backtrace(std::move(g_output_fd), map.get(), thread_info, g_target_thread);
+    dump_backtrace(std::move(g_output_fd), &unwinder, thread_info, g_target_thread);
   } else {
     {
       ATRACE_NAME("fdsan table dump");
-      populate_fdsan_table(&open_files, process_memory, fdsan_table_address);
+      populate_fdsan_table(&open_files, unwinder.GetProcessMemory(), fdsan_table_address);
     }
 
     {
       ATRACE_NAME("engrave_tombstone");
-      engrave_tombstone(std::move(g_output_fd), map.get(), process_memory.get(), thread_info,
-                        g_target_thread, abort_msg_address, &open_files, &amfd_data);
+      engrave_tombstone(std::move(g_output_fd), &unwinder, thread_info, g_target_thread,
+                        abort_msg_address, &open_files, &amfd_data);
     }
   }
 
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 15c0265..bbec612 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -42,9 +42,12 @@
 #include <android-base/file.h>
 #include <android-base/unique_fd.h>
 #include <async_safe/log.h>
-#include <backtrace/BacktraceMap.h>
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/JitDebug.h>
+#include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
+#include <unwindstack/Unwinder.h>
 
 #include "debuggerd/handler.h"
 #include "handler/fallback.h"
@@ -55,7 +58,6 @@
 #include "libdebuggerd/tombstone.h"
 
 using android::base::unique_fd;
-using unwindstack::Regs;
 
 extern "C" bool __linker_enable_fallback_allocator();
 extern "C" void __linker_disable_fallback_allocator();
@@ -73,17 +75,22 @@
   }
 
   {
-    std::unique_ptr<Regs> regs;
+    std::unique_ptr<unwindstack::Regs> regs;
 
     ThreadInfo thread;
     thread.pid = getpid();
     thread.tid = gettid();
     thread.thread_name = get_thread_name(gettid());
-    thread.registers.reset(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext));
+    unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch();
+    thread.registers.reset(unwindstack::Regs::CreateFromUcontext(arch, ucontext));
 
     // TODO: Create this once and store it in a global?
-    std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid()));
-    dump_backtrace_thread(output_fd, map.get(), thread);
+    unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid());
+    if (unwinder.Init(arch)) {
+      dump_backtrace_thread(output_fd, &unwinder, thread);
+    } else {
+      async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Unable to init unwinder.");
+    }
   }
   __linker_disable_fallback_allocator();
 }
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index f0a01f4..753ebcb 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -35,8 +35,8 @@
 #include <string>
 
 #include <android-base/unique_fd.h>
-#include <backtrace/Backtrace.h>
 #include <log/log.h>
+#include <unwindstack/Unwinder.h>
 
 #include "libdebuggerd/types.h"
 #include "libdebuggerd/utility.h"
@@ -59,25 +59,27 @@
   _LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid);
 }
 
-void dump_backtrace_thread(int output_fd, BacktraceMap* map, const ThreadInfo& thread) {
+void dump_backtrace_thread(int output_fd, unwindstack::Unwinder* unwinder,
+                           const ThreadInfo& thread) {
   log_t log;
   log.tfd = output_fd;
   log.amfd_data = nullptr;
 
   _LOG(&log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", thread.thread_name.c_str(), thread.tid);
 
-  std::vector<backtrace_frame_data_t> frames;
-  if (!Backtrace::Unwind(thread.registers.get(), map, &frames, 0, nullptr)) {
+  unwinder->SetRegs(thread.registers.get());
+  unwinder->Unwind();
+  if (unwinder->NumFrames() == 0) {
     _LOG(&log, logtype::THREAD, "Unwind failed: tid = %d", thread.tid);
     return;
   }
 
-  for (auto& frame : frames) {
-    _LOG(&log, logtype::BACKTRACE, "  %s\n", Backtrace::FormatFrameData(&frame).c_str());
+  for (size_t i = 0; i < unwinder->NumFrames(); i++) {
+    _LOG(&log, logtype::BACKTRACE, "  %s\n", unwinder->FormatFrame(i).c_str());
   }
 }
 
-void dump_backtrace(android::base::unique_fd output_fd, BacktraceMap* map,
+void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
                     const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread) {
   log_t log;
   log.tfd = output_fd.get();
@@ -91,10 +93,10 @@
 
   dump_process_header(&log, target->second.pid, target->second.process_name.c_str());
 
-  dump_backtrace_thread(output_fd.get(), map, target->second);
+  dump_backtrace_thread(output_fd.get(), unwinder, target->second);
   for (const auto& [tid, info] : thread_info) {
     if (tid != target_thread) {
-      dump_backtrace_thread(output_fd.get(), map, info);
+      dump_backtrace_thread(output_fd.get(), unwinder, info);
     }
   }
 
diff --git a/debuggerd/libdebuggerd/elf_utils.cpp b/debuggerd/libdebuggerd/elf_utils.cpp
deleted file mode 100644
index d7afc0b..0000000
--- a/debuggerd/libdebuggerd/elf_utils.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "DEBUG"
-
-#include "libdebuggerd/elf_utils.h"
-
-#include <elf.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <string>
-
-#include <android-base/stringprintf.h>
-#include <log/log.h>
-#include <unwindstack/Memory.h>
-
-#define NOTE_ALIGN(size)  (((size) + 3) & ~3)
-
-template <typename HdrType, typename PhdrType, typename NhdrType>
-static bool get_build_id(unwindstack::Memory* memory, uintptr_t base_addr, uint8_t* e_ident,
-                         std::string* build_id) {
-  HdrType hdr;
-
-  memcpy(&hdr.e_ident[0], e_ident, EI_NIDENT);
-
-  // First read the rest of the header.
-  if (memory->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT,
-                   sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) {
-    return false;
-  }
-
-  for (size_t i = 0; i < hdr.e_phnum; i++) {
-    PhdrType phdr;
-    if (memory->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize,
-                     reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(phdr)) {
-      return false;
-    }
-    // Looking for the .note.gnu.build-id note.
-    if (phdr.p_type == PT_NOTE) {
-      size_t hdr_size = phdr.p_filesz;
-      uintptr_t addr = base_addr + phdr.p_offset;
-      while (hdr_size >= sizeof(NhdrType)) {
-        NhdrType nhdr;
-        if (memory->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) {
-          return false;
-        }
-        addr += sizeof(nhdr);
-        if (nhdr.n_type == NT_GNU_BUILD_ID) {
-          // Skip the name (which is the owner and should be "GNU").
-          addr += NOTE_ALIGN(nhdr.n_namesz);
-          uint8_t build_id_data[160];
-          if (nhdr.n_descsz > sizeof(build_id_data)) {
-            ALOGE("Possible corrupted note, desc size value is too large: %u",
-                  nhdr.n_descsz);
-            return false;
-          }
-          if (memory->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) {
-            return false;
-          }
-
-          build_id->clear();
-          for (size_t bytes = 0; bytes < nhdr.n_descsz; bytes++) {
-            *build_id += android::base::StringPrintf("%02x", build_id_data[bytes]);
-          }
-
-          return true;
-        } else {
-          // Move past the extra note data.
-          hdr_size -= sizeof(nhdr);
-          size_t skip_bytes = NOTE_ALIGN(nhdr.n_namesz) + NOTE_ALIGN(nhdr.n_descsz);
-          addr += skip_bytes;
-          if (hdr_size < skip_bytes) {
-            break;
-          }
-          hdr_size -= skip_bytes;
-        }
-      }
-    }
-  }
-  return false;
-}
-
-bool elf_get_build_id(unwindstack::Memory* memory, uintptr_t addr, std::string* build_id) {
-  // Read and verify the elf magic number first.
-  uint8_t e_ident[EI_NIDENT];
-  if (memory->Read(addr, e_ident, SELFMAG) != SELFMAG) {
-    return false;
-  }
-
-  if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
-    return false;
-  }
-
-  // Read the rest of EI_NIDENT.
-  if (memory->Read(addr + SELFMAG, e_ident + SELFMAG, EI_NIDENT - SELFMAG) != EI_NIDENT - SELFMAG) {
-    return false;
-  }
-
-  if (e_ident[EI_CLASS] == ELFCLASS32) {
-    return get_build_id<Elf32_Ehdr, Elf32_Phdr, Elf32_Nhdr>(memory, addr, e_ident, build_id);
-  } else if (e_ident[EI_CLASS] == ELFCLASS64) {
-    return get_build_id<Elf64_Ehdr, Elf64_Phdr, Elf64_Nhdr>(memory, addr, e_ident, build_id);
-  }
-
-  return false;
-}
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
index 119e59b..c20d090 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
@@ -28,15 +28,19 @@
 #include "types.h"
 #include "utility.h"
 
-class BacktraceMap;
+// Forward delcaration
+namespace unwindstack {
+class Unwinder;
+}
 
 // Dumps a backtrace using a format similar to what Dalvik uses so that the result
 // can be intermixed in a bug report.
-void dump_backtrace(android::base::unique_fd output_fd, BacktraceMap* map,
+void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
                     const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread);
 
 void dump_backtrace_header(int output_fd);
-void dump_backtrace_thread(int output_fd, BacktraceMap* map, const ThreadInfo& thread);
+void dump_backtrace_thread(int output_fd, unwindstack::Unwinder* unwinder,
+                           const ThreadInfo& thread);
 void dump_backtrace_footer(int output_fd);
 
 #endif // _DEBUGGERD_BACKTRACE_H
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h b/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h
deleted file mode 100644
index 5d0d924..0000000
--- a/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _DEBUGGERD_ELF_UTILS_H
-#define _DEBUGGERD_ELF_UTILS_H
-
-#include <stdint.h>
-#include <string>
-
-namespace unwindstack {
-class Memory;
-}
-
-bool elf_get_build_id(unwindstack::Memory*, uintptr_t, std::string*);
-
-#endif // _DEBUGGERD_ELF_UTILS_H
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index be90d0f..7133f77 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -29,7 +29,13 @@
 #include "open_files_list.h"
 #include "types.h"
 
-class BacktraceMap;
+// Forward declarations
+namespace unwindstack {
+class Unwinder;
+}
+
+// The maximum number of frames to save when unwinding.
+constexpr size_t kMaxFrames = 256;
 
 /* Create and open a tombstone file for writing.
  * Returns a writable file descriptor, or -1 with errno set appropriately.
@@ -38,16 +44,15 @@
 int open_tombstone(std::string* path);
 
 /* Creates a tombstone file and writes the crash dump to it. */
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files,
-                       pid_t pid, pid_t tid, const std::string& process_name,
-                       const std::map<pid_t, std::string>& threads, uint64_t abort_msg_address,
-                       std::string* amfd_data);
+void engrave_tombstone(int tombstone_fd, unwindstack::Unwinder* unwinder,
+                       const OpenFilesList* open_files, pid_t pid, pid_t tid,
+                       const std::string& process_name, const std::map<pid_t, std::string>& threads,
+                       uint64_t abort_msg_address, std::string* amfd_data);
 
 void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, siginfo_t* siginfo,
                                 ucontext_t* ucontext);
 
-void engrave_tombstone(android::base::unique_fd output_fd, BacktraceMap* map,
-                       unwindstack::Memory* process_memory,
+void engrave_tombstone(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
                        const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread,
                        uint64_t abort_msg_address, OpenFilesList* open_files,
                        std::string* amfd_data);
diff --git a/debuggerd/libdebuggerd/test/BacktraceMock.h b/debuggerd/libdebuggerd/test/BacktraceMock.h
deleted file mode 100644
index e7dbed7..0000000
--- a/debuggerd/libdebuggerd/test/BacktraceMock.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _DEBUGGERD_TEST_BACKTRACE_MOCK_H
-#define _DEBUGGERD_TEST_BACKTRACE_MOCK_H
-
-#include <backtrace/BacktraceMap.h>
-
-class BacktraceMapMock : public BacktraceMap {
- public:
-  BacktraceMapMock() : BacktraceMap(0) {}
-  virtual ~BacktraceMapMock() {}
-
-  void AddMap(backtrace_map_t& map) {
-    maps_.push_back(map);
-  }
-};
-
-#endif //  _DEBUGGERD_TEST_BACKTRACE_MOCK_H
diff --git a/debuggerd/libdebuggerd/test/UnwinderMock.h b/debuggerd/libdebuggerd/test/UnwinderMock.h
new file mode 100644
index 0000000..023a578
--- /dev/null
+++ b/debuggerd/libdebuggerd/test/UnwinderMock.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Unwinder.h>
+
+class UnwinderMock : public unwindstack::Unwinder {
+ public:
+  UnwinderMock() : Unwinder(128, new unwindstack::Maps, nullptr) {}
+  virtual ~UnwinderMock() { delete GetMaps(); }
+
+  void MockAddMap(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, std::string name,
+                  uint64_t load_bias) {
+    GetMaps()->Add(start, end, offset, flags, name, load_bias);
+  }
+
+  void MockSetBuildID(uint64_t offset, const std::string& build_id) {
+    unwindstack::MapInfo* map_info = GetMaps()->Find(offset);
+    if (map_info != nullptr) {
+      std::string* new_build_id = new std::string(build_id);
+      map_info->build_id = reinterpret_cast<uintptr_t>(new_build_id);
+    }
+  }
+};
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index d24c887..eed5bd3 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -26,26 +26,16 @@
 
 #include "libdebuggerd/utility.h"
 
-#include "BacktraceMock.h"
-#include "elf_fake.h"
+#include "UnwinderMock.h"
 #include "host_signal_fixup.h"
 #include "log_fake.h"
 
 #include "tombstone.cpp"
 
-void dump_registers(log_t*, pid_t) {
-}
-
-void dump_memory_and_code(log_t*, Backtrace*) {
-}
-
-void dump_backtrace_to_log(Backtrace*, log_t*, char const*) {
-}
-
 class TombstoneTest : public ::testing::Test {
  protected:
   virtual void SetUp() {
-    map_mock_.reset(new BacktraceMapMock());
+    unwinder_mock_.reset(new UnwinderMock());
 
     char tmp_file[256];
     const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
@@ -71,7 +61,6 @@
     log_.should_retrieve_logcat = false;
 
     resetLogs();
-    elf_set_fake_build_id("");
   }
 
   virtual void TearDown() {
@@ -80,24 +69,20 @@
     }
   }
 
-  std::unique_ptr<BacktraceMapMock> map_mock_;
+  std::unique_ptr<UnwinderMock> unwinder_mock_;
 
   log_t log_;
   std::string amfd_data_;
 };
 
 TEST_F(TombstoneTest, single_map) {
-  backtrace_map_t map;
 #if defined(__LP64__)
-  map.start = 0x123456789abcd000UL;
-  map.end = 0x123456789abdf000UL;
+  unwinder_mock_->MockAddMap(0x123456789abcd000UL, 0x123456789abdf000UL, 0, 0, "", 0);
 #else
-  map.start = 0x1234000;
-  map.end = 0x1235000;
+  unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, 0, "", 0);
 #endif
-  map_mock_->AddMap(map);
 
-  dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
+  dump_all_maps(&log_, unwinder_mock_.get(), 0);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -119,20 +104,25 @@
 }
 
 TEST_F(TombstoneTest, single_map_elf_build_id) {
-  backtrace_map_t map;
+  uint64_t build_id_offset;
 #if defined(__LP64__)
-  map.start = 0x123456789abcd000UL;
-  map.end = 0x123456789abdf000UL;
+  build_id_offset = 0x123456789abcd000UL;
+  unwinder_mock_->MockAddMap(build_id_offset, 0x123456789abdf000UL, 0, PROT_READ,
+                             "/system/lib/libfake.so", 0);
 #else
-  map.start = 0x1234000;
-  map.end = 0x1235000;
+  build_id_offset = 0x1234000;
+  unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, PROT_READ, "/system/lib/libfake.so", 0);
 #endif
-  map.flags = PROT_READ;
-  map.name = "/system/lib/libfake.so";
-  map_mock_->AddMap(map);
 
-  elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
-  dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
+  unwinder_mock_->MockSetBuildID(
+      build_id_offset,
+      std::string{static_cast<char>(0xab), static_cast<char>(0xcd), static_cast<char>(0xef),
+                  static_cast<char>(0x12), static_cast<char>(0x34), static_cast<char>(0x56),
+                  static_cast<char>(0x78), static_cast<char>(0x90), static_cast<char>(0xab),
+                  static_cast<char>(0xcd), static_cast<char>(0xef), static_cast<char>(0x12),
+                  static_cast<char>(0x34), static_cast<char>(0x56), static_cast<char>(0x78),
+                  static_cast<char>(0x90)});
+  dump_all_maps(&log_, unwinder_mock_.get(), 0);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -153,83 +143,15 @@
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
-// Even though build id is present, it should not be printed in either of
-// these cases.
-TEST_F(TombstoneTest, single_map_no_build_id) {
-  backtrace_map_t map;
-#if defined(__LP64__)
-  map.start = 0x123456789abcd000UL;
-  map.end = 0x123456789abdf000UL;
-#else
-  map.start = 0x1234000;
-  map.end = 0x1235000;
-#endif
-  map.flags = PROT_WRITE;
-  map_mock_->AddMap(map);
-
-  map.name = "/system/lib/libfake.so";
-  map_mock_->AddMap(map);
-
-  elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
-  dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
-
-  std::string tombstone_contents;
-  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
-  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
-  const char* expected_dump = \
-"\nmemory map (2 entries):\n"
-#if defined(__LP64__)
-"    12345678'9abcd000-12345678'9abdefff -w-         0     12000\n"
-"    12345678'9abcd000-12345678'9abdefff -w-         0     12000  /system/lib/libfake.so\n";
-#else
-"    01234000-01234fff -w-         0      1000\n"
-"    01234000-01234fff -w-         0      1000  /system/lib/libfake.so\n";
-#endif
-  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
-
-  ASSERT_STREQ("", amfd_data_.c_str());
-
-  // Verify that the log buf is empty, and no error messages.
-  ASSERT_STREQ("", getFakeLogBuf().c_str());
-  ASSERT_STREQ("", getFakeLogPrint().c_str());
-}
-
 TEST_F(TombstoneTest, multiple_maps) {
-  backtrace_map_t map;
+  unwinder_mock_->MockAddMap(0xa234000, 0xa235000, 0, 0, "", 0);
+  unwinder_mock_->MockAddMap(0xa334000, 0xa335000, 0xf000, PROT_READ, "", 0);
+  unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+  unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+  unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                             "/system/lib/fake.so", 0);
 
-  map.start = 0xa234000;
-  map.end = 0xa235000;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa334000;
-  map.end = 0xa335000;
-  map.offset = 0xf000;
-  map.flags = PROT_READ;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa434000;
-  map.end = 0xa435000;
-  map.offset = 0x1000;
-  map.load_bias = 0xd000;
-  map.flags = PROT_WRITE;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa534000;
-  map.end = 0xa535000;
-  map.offset = 0x3000;
-  map.load_bias = 0x2000;
-  map.flags = PROT_EXEC;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa634000;
-  map.end = 0xa635000;
-  map.offset = 0;
-  map.load_bias = 0;
-  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
-  map.name = "/system/lib/fake.so";
-  map_mock_->AddMap(map);
-
-  dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
+  dump_all_maps(&log_, unwinder_mock_.get(), 0);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -259,31 +181,12 @@
 }
 
 TEST_F(TombstoneTest, multiple_maps_fault_address_before) {
-  backtrace_map_t map;
+  unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+  unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+  unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                             "/system/lib/fake.so", 0);
 
-  map.start = 0xa434000;
-  map.end = 0xa435000;
-  map.offset = 0x1000;
-  map.load_bias = 0xd000;
-  map.flags = PROT_WRITE;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa534000;
-  map.end = 0xa535000;
-  map.offset = 0x3000;
-  map.load_bias = 0x2000;
-  map.flags = PROT_EXEC;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa634000;
-  map.end = 0xa635000;
-  map.offset = 0;
-  map.load_bias = 0;
-  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
-  map.name = "/system/lib/fake.so";
-  map_mock_->AddMap(map);
-
-  dump_all_maps(&log_, map_mock_.get(), nullptr, 0x1000);
+  dump_all_maps(&log_, unwinder_mock_.get(), 0x1000);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -311,31 +214,12 @@
 }
 
 TEST_F(TombstoneTest, multiple_maps_fault_address_between) {
-  backtrace_map_t map;
+  unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+  unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+  unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                             "/system/lib/fake.so", 0);
 
-  map.start = 0xa434000;
-  map.end = 0xa435000;
-  map.offset = 0x1000;
-  map.load_bias = 0xd000;
-  map.flags = PROT_WRITE;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa534000;
-  map.end = 0xa535000;
-  map.offset = 0x3000;
-  map.load_bias = 0x2000;
-  map.flags = PROT_EXEC;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa634000;
-  map.end = 0xa635000;
-  map.offset = 0;
-  map.load_bias = 0;
-  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
-  map.name = "/system/lib/fake.so";
-  map_mock_->AddMap(map);
-
-  dump_all_maps(&log_, map_mock_.get(), nullptr, 0xa533000);
+  dump_all_maps(&log_, unwinder_mock_.get(), 0xa533000);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -363,31 +247,12 @@
 }
 
 TEST_F(TombstoneTest, multiple_maps_fault_address_in_map) {
-  backtrace_map_t map;
+  unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+  unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+  unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                             "/system/lib/fake.so", 0);
 
-  map.start = 0xa434000;
-  map.end = 0xa435000;
-  map.offset = 0x1000;
-  map.load_bias = 0xd000;
-  map.flags = PROT_WRITE;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa534000;
-  map.end = 0xa535000;
-  map.offset = 0x3000;
-  map.load_bias = 0x2000;
-  map.flags = PROT_EXEC;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa634000;
-  map.end = 0xa635000;
-  map.offset = 0;
-  map.load_bias = 0;
-  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
-  map.name = "/system/lib/fake.so";
-  map_mock_->AddMap(map);
-
-  dump_all_maps(&log_, map_mock_.get(), nullptr, 0xa534040);
+  dump_all_maps(&log_, unwinder_mock_.get(), 0xa534040);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -413,36 +278,17 @@
 }
 
 TEST_F(TombstoneTest, multiple_maps_fault_address_after) {
-  backtrace_map_t map;
-
-  map.start = 0xa434000;
-  map.end = 0xa435000;
-  map.offset = 0x1000;
-  map.load_bias = 0xd000;
-  map.flags = PROT_WRITE;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa534000;
-  map.end = 0xa535000;
-  map.offset = 0x3000;
-  map.load_bias = 0x2000;
-  map.flags = PROT_EXEC;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa634000;
-  map.end = 0xa635000;
-  map.offset = 0;
-  map.load_bias = 0;
-  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
-  map.name = "/system/lib/fake.so";
-  map_mock_->AddMap(map);
+  unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+  unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+  unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                             "/system/lib/fake.so", 0);
 
 #if defined(__LP64__)
   uint64_t addr = 0x12345a534040UL;
 #else
   uint64_t addr = 0xf534040UL;
 #endif
-  dump_all_maps(&log_, map_mock_.get(), nullptr, addr);
+  dump_all_maps(&log_, unwinder_mock_.get(), addr);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -502,3 +348,467 @@
   dump_timestamp(&log_, 0);
   ASSERT_STREQ("Timestamp: 1970-01-01 00:00:00+0000\n", amfd_data_.c_str());
 }
+
+class MemoryPattern : public unwindstack::Memory {
+ public:
+  MemoryPattern() = default;
+  virtual ~MemoryPattern() = default;
+
+  size_t Read(uint64_t, void* dst, size_t size) override {
+    uint8_t* data = reinterpret_cast<uint8_t*>(dst);
+    for (size_t i = 0; i < size; i++) {
+      data[i] = (i % 0xff);
+    }
+    return size;
+  }
+};
+
+TEST_F(TombstoneTest, dump_stack_single_frame) {
+  std::vector<unwindstack::FrameData> frames;
+  unwindstack::Maps maps;
+  MemoryPattern memory;
+
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
+  dump_stack(&log_, frames, &maps, &memory);
+
+  std::string contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));
+
+  std::string expected =
+#if defined(__LP64__)
+      "         0000000000001f80  0706050403020100\n"
+      "         0000000000001f88  0f0e0d0c0b0a0908\n"
+      "         0000000000001f90  1716151413121110\n"
+      "         0000000000001f98  1f1e1d1c1b1a1918\n"
+      "         0000000000001fa0  2726252423222120\n"
+      "         0000000000001fa8  2f2e2d2c2b2a2928\n"
+      "         0000000000001fb0  3736353433323130\n"
+      "         0000000000001fb8  3f3e3d3c3b3a3938\n"
+      "         0000000000001fc0  4746454443424140\n"
+      "         0000000000001fc8  4f4e4d4c4b4a4948\n"
+      "         0000000000001fd0  5756555453525150\n"
+      "         0000000000001fd8  5f5e5d5c5b5a5958\n"
+      "         0000000000001fe0  6766656463626160\n"
+      "         0000000000001fe8  6f6e6d6c6b6a6968\n"
+      "         0000000000001ff0  7776757473727170\n"
+      "         0000000000001ff8  7f7e7d7c7b7a7978\n"
+      "    #00  0000000000002000  0706050403020100\n"
+      "         0000000000002008  0f0e0d0c0b0a0908\n"
+      "         0000000000002010  1716151413121110\n"
+      "         0000000000002018  1f1e1d1c1b1a1918\n"
+      "         0000000000002020  2726252423222120\n"
+      "         0000000000002028  2f2e2d2c2b2a2928\n"
+      "         0000000000002030  3736353433323130\n"
+      "         0000000000002038  3f3e3d3c3b3a3938\n"
+      "         0000000000002040  4746454443424140\n"
+      "         0000000000002048  4f4e4d4c4b4a4948\n"
+      "         0000000000002050  5756555453525150\n"
+      "         0000000000002058  5f5e5d5c5b5a5958\n"
+      "         0000000000002060  6766656463626160\n"
+      "         0000000000002068  6f6e6d6c6b6a6968\n"
+      "         0000000000002070  7776757473727170\n"
+      "         0000000000002078  7f7e7d7c7b7a7978\n";
+#else
+      "         00001fc0  03020100\n"
+      "         00001fc4  07060504\n"
+      "         00001fc8  0b0a0908\n"
+      "         00001fcc  0f0e0d0c\n"
+      "         00001fd0  13121110\n"
+      "         00001fd4  17161514\n"
+      "         00001fd8  1b1a1918\n"
+      "         00001fdc  1f1e1d1c\n"
+      "         00001fe0  23222120\n"
+      "         00001fe4  27262524\n"
+      "         00001fe8  2b2a2928\n"
+      "         00001fec  2f2e2d2c\n"
+      "         00001ff0  33323130\n"
+      "         00001ff4  37363534\n"
+      "         00001ff8  3b3a3938\n"
+      "         00001ffc  3f3e3d3c\n"
+      "    #00  00002000  03020100\n"
+      "         00002004  07060504\n"
+      "         00002008  0b0a0908\n"
+      "         0000200c  0f0e0d0c\n"
+      "         00002010  13121110\n"
+      "         00002014  17161514\n"
+      "         00002018  1b1a1918\n"
+      "         0000201c  1f1e1d1c\n"
+      "         00002020  23222120\n"
+      "         00002024  27262524\n"
+      "         00002028  2b2a2928\n"
+      "         0000202c  2f2e2d2c\n"
+      "         00002030  33323130\n"
+      "         00002034  37363534\n"
+      "         00002038  3b3a3938\n"
+      "         0000203c  3f3e3d3c\n";
+#endif
+  EXPECT_EQ(expected, contents);
+}
+
+TEST_F(TombstoneTest, dump_stack_multiple_frames_same_sp) {
+  std::vector<unwindstack::FrameData> frames;
+  unwindstack::Maps maps;
+  MemoryPattern memory;
+
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2000});
+  dump_stack(&log_, frames, &maps, &memory);
+
+  std::string contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));
+
+  std::string expected =
+#if defined(__LP64__)
+      "         0000000000001f80  0706050403020100\n"
+      "         0000000000001f88  0f0e0d0c0b0a0908\n"
+      "         0000000000001f90  1716151413121110\n"
+      "         0000000000001f98  1f1e1d1c1b1a1918\n"
+      "         0000000000001fa0  2726252423222120\n"
+      "         0000000000001fa8  2f2e2d2c2b2a2928\n"
+      "         0000000000001fb0  3736353433323130\n"
+      "         0000000000001fb8  3f3e3d3c3b3a3938\n"
+      "         0000000000001fc0  4746454443424140\n"
+      "         0000000000001fc8  4f4e4d4c4b4a4948\n"
+      "         0000000000001fd0  5756555453525150\n"
+      "         0000000000001fd8  5f5e5d5c5b5a5958\n"
+      "         0000000000001fe0  6766656463626160\n"
+      "         0000000000001fe8  6f6e6d6c6b6a6968\n"
+      "         0000000000001ff0  7776757473727170\n"
+      "         0000000000001ff8  7f7e7d7c7b7a7978\n"
+      "    #00  0000000000002000  0706050403020100\n"
+      "         ................  ................\n"
+      "    #01  0000000000002000  0706050403020100\n"
+      "         0000000000002008  0f0e0d0c0b0a0908\n"
+      "         0000000000002010  1716151413121110\n"
+      "         0000000000002018  1f1e1d1c1b1a1918\n"
+      "         0000000000002020  2726252423222120\n"
+      "         0000000000002028  2f2e2d2c2b2a2928\n"
+      "         0000000000002030  3736353433323130\n"
+      "         0000000000002038  3f3e3d3c3b3a3938\n"
+      "         0000000000002040  4746454443424140\n"
+      "         0000000000002048  4f4e4d4c4b4a4948\n"
+      "         0000000000002050  5756555453525150\n"
+      "         0000000000002058  5f5e5d5c5b5a5958\n"
+      "         0000000000002060  6766656463626160\n"
+      "         0000000000002068  6f6e6d6c6b6a6968\n"
+      "         0000000000002070  7776757473727170\n"
+      "         0000000000002078  7f7e7d7c7b7a7978\n";
+#else
+      "         00001fc0  03020100\n"
+      "         00001fc4  07060504\n"
+      "         00001fc8  0b0a0908\n"
+      "         00001fcc  0f0e0d0c\n"
+      "         00001fd0  13121110\n"
+      "         00001fd4  17161514\n"
+      "         00001fd8  1b1a1918\n"
+      "         00001fdc  1f1e1d1c\n"
+      "         00001fe0  23222120\n"
+      "         00001fe4  27262524\n"
+      "         00001fe8  2b2a2928\n"
+      "         00001fec  2f2e2d2c\n"
+      "         00001ff0  33323130\n"
+      "         00001ff4  37363534\n"
+      "         00001ff8  3b3a3938\n"
+      "         00001ffc  3f3e3d3c\n"
+      "    #00  00002000  03020100\n"
+      "         ........  ........\n"
+      "    #01  00002000  03020100\n"
+      "         00002004  07060504\n"
+      "         00002008  0b0a0908\n"
+      "         0000200c  0f0e0d0c\n"
+      "         00002010  13121110\n"
+      "         00002014  17161514\n"
+      "         00002018  1b1a1918\n"
+      "         0000201c  1f1e1d1c\n"
+      "         00002020  23222120\n"
+      "         00002024  27262524\n"
+      "         00002028  2b2a2928\n"
+      "         0000202c  2f2e2d2c\n"
+      "         00002030  33323130\n"
+      "         00002034  37363534\n"
+      "         00002038  3b3a3938\n"
+      "         0000203c  3f3e3d3c\n";
+#endif
+  EXPECT_EQ(expected, contents);
+}
+
+TEST_F(TombstoneTest, dump_stack_multiple_frames) {
+  std::vector<unwindstack::FrameData> frames;
+  unwindstack::Maps maps;
+  MemoryPattern memory;
+
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2010});
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2100});
+  dump_stack(&log_, frames, &maps, &memory);
+
+  std::string contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));
+
+  std::string expected =
+#if defined(__LP64__)
+      "         0000000000001f80  0706050403020100\n"
+      "         0000000000001f88  0f0e0d0c0b0a0908\n"
+      "         0000000000001f90  1716151413121110\n"
+      "         0000000000001f98  1f1e1d1c1b1a1918\n"
+      "         0000000000001fa0  2726252423222120\n"
+      "         0000000000001fa8  2f2e2d2c2b2a2928\n"
+      "         0000000000001fb0  3736353433323130\n"
+      "         0000000000001fb8  3f3e3d3c3b3a3938\n"
+      "         0000000000001fc0  4746454443424140\n"
+      "         0000000000001fc8  4f4e4d4c4b4a4948\n"
+      "         0000000000001fd0  5756555453525150\n"
+      "         0000000000001fd8  5f5e5d5c5b5a5958\n"
+      "         0000000000001fe0  6766656463626160\n"
+      "         0000000000001fe8  6f6e6d6c6b6a6968\n"
+      "         0000000000001ff0  7776757473727170\n"
+      "         0000000000001ff8  7f7e7d7c7b7a7978\n"
+      "    #00  0000000000002000  0706050403020100\n"
+      "         0000000000002008  0f0e0d0c0b0a0908\n"
+      "    #01  0000000000002010  0706050403020100\n"
+      "         0000000000002018  0f0e0d0c0b0a0908\n"
+      "         0000000000002020  1716151413121110\n"
+      "         0000000000002028  1f1e1d1c1b1a1918\n"
+      "         0000000000002030  2726252423222120\n"
+      "         0000000000002038  2f2e2d2c2b2a2928\n"
+      "         0000000000002040  3736353433323130\n"
+      "         0000000000002048  3f3e3d3c3b3a3938\n"
+      "         0000000000002050  4746454443424140\n"
+      "         0000000000002058  4f4e4d4c4b4a4948\n"
+      "         0000000000002060  5756555453525150\n"
+      "         0000000000002068  5f5e5d5c5b5a5958\n"
+      "         0000000000002070  6766656463626160\n"
+      "         0000000000002078  6f6e6d6c6b6a6968\n"
+      "         0000000000002080  7776757473727170\n"
+      "         0000000000002088  7f7e7d7c7b7a7978\n"
+      "         ................  ................\n"
+      "    #02  0000000000002100  0706050403020100\n"
+      "         0000000000002108  0f0e0d0c0b0a0908\n"
+      "         0000000000002110  1716151413121110\n"
+      "         0000000000002118  1f1e1d1c1b1a1918\n"
+      "         0000000000002120  2726252423222120\n"
+      "         0000000000002128  2f2e2d2c2b2a2928\n"
+      "         0000000000002130  3736353433323130\n"
+      "         0000000000002138  3f3e3d3c3b3a3938\n"
+      "         0000000000002140  4746454443424140\n"
+      "         0000000000002148  4f4e4d4c4b4a4948\n"
+      "         0000000000002150  5756555453525150\n"
+      "         0000000000002158  5f5e5d5c5b5a5958\n"
+      "         0000000000002160  6766656463626160\n"
+      "         0000000000002168  6f6e6d6c6b6a6968\n"
+      "         0000000000002170  7776757473727170\n"
+      "         0000000000002178  7f7e7d7c7b7a7978\n";
+#else
+      "         00001fc0  03020100\n"
+      "         00001fc4  07060504\n"
+      "         00001fc8  0b0a0908\n"
+      "         00001fcc  0f0e0d0c\n"
+      "         00001fd0  13121110\n"
+      "         00001fd4  17161514\n"
+      "         00001fd8  1b1a1918\n"
+      "         00001fdc  1f1e1d1c\n"
+      "         00001fe0  23222120\n"
+      "         00001fe4  27262524\n"
+      "         00001fe8  2b2a2928\n"
+      "         00001fec  2f2e2d2c\n"
+      "         00001ff0  33323130\n"
+      "         00001ff4  37363534\n"
+      "         00001ff8  3b3a3938\n"
+      "         00001ffc  3f3e3d3c\n"
+      "    #00  00002000  03020100\n"
+      "         00002004  07060504\n"
+      "         00002008  0b0a0908\n"
+      "         0000200c  0f0e0d0c\n"
+      "    #01  00002010  03020100\n"
+      "         00002014  07060504\n"
+      "         00002018  0b0a0908\n"
+      "         0000201c  0f0e0d0c\n"
+      "         00002020  13121110\n"
+      "         00002024  17161514\n"
+      "         00002028  1b1a1918\n"
+      "         0000202c  1f1e1d1c\n"
+      "         00002030  23222120\n"
+      "         00002034  27262524\n"
+      "         00002038  2b2a2928\n"
+      "         0000203c  2f2e2d2c\n"
+      "         00002040  33323130\n"
+      "         00002044  37363534\n"
+      "         00002048  3b3a3938\n"
+      "         0000204c  3f3e3d3c\n"
+      "         ........  ........\n"
+      "    #02  00002100  03020100\n"
+      "         00002104  07060504\n"
+      "         00002108  0b0a0908\n"
+      "         0000210c  0f0e0d0c\n"
+      "         00002110  13121110\n"
+      "         00002114  17161514\n"
+      "         00002118  1b1a1918\n"
+      "         0000211c  1f1e1d1c\n"
+      "         00002120  23222120\n"
+      "         00002124  27262524\n"
+      "         00002128  2b2a2928\n"
+      "         0000212c  2f2e2d2c\n"
+      "         00002130  33323130\n"
+      "         00002134  37363534\n"
+      "         00002138  3b3a3938\n"
+      "         0000213c  3f3e3d3c\n";
+#endif
+  EXPECT_EQ(expected, contents);
+}
+
+TEST_F(TombstoneTest, dump_stack_multiple_frames_disjoint_frames) {
+  std::vector<unwindstack::FrameData> frames;
+  unwindstack::Maps maps;
+  MemoryPattern memory;
+
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2010});
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x1000});
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x1030});
+  dump_stack(&log_, frames, &maps, &memory);
+
+  std::string contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));
+
+  std::string expected =
+#if defined(__LP64__)
+      "         0000000000001f80  0706050403020100\n"
+      "         0000000000001f88  0f0e0d0c0b0a0908\n"
+      "         0000000000001f90  1716151413121110\n"
+      "         0000000000001f98  1f1e1d1c1b1a1918\n"
+      "         0000000000001fa0  2726252423222120\n"
+      "         0000000000001fa8  2f2e2d2c2b2a2928\n"
+      "         0000000000001fb0  3736353433323130\n"
+      "         0000000000001fb8  3f3e3d3c3b3a3938\n"
+      "         0000000000001fc0  4746454443424140\n"
+      "         0000000000001fc8  4f4e4d4c4b4a4948\n"
+      "         0000000000001fd0  5756555453525150\n"
+      "         0000000000001fd8  5f5e5d5c5b5a5958\n"
+      "         0000000000001fe0  6766656463626160\n"
+      "         0000000000001fe8  6f6e6d6c6b6a6968\n"
+      "         0000000000001ff0  7776757473727170\n"
+      "         0000000000001ff8  7f7e7d7c7b7a7978\n"
+      "    #00  0000000000002000  0706050403020100\n"
+      "         0000000000002008  0f0e0d0c0b0a0908\n"
+      "    #01  0000000000002010  0706050403020100\n"
+      "         0000000000002018  0f0e0d0c0b0a0908\n"
+      "         0000000000002020  1716151413121110\n"
+      "         0000000000002028  1f1e1d1c1b1a1918\n"
+      "         0000000000002030  2726252423222120\n"
+      "         0000000000002038  2f2e2d2c2b2a2928\n"
+      "         0000000000002040  3736353433323130\n"
+      "         0000000000002048  3f3e3d3c3b3a3938\n"
+      "         0000000000002050  4746454443424140\n"
+      "         0000000000002058  4f4e4d4c4b4a4948\n"
+      "         0000000000002060  5756555453525150\n"
+      "         0000000000002068  5f5e5d5c5b5a5958\n"
+      "         0000000000002070  6766656463626160\n"
+      "         0000000000002078  6f6e6d6c6b6a6968\n"
+      "         0000000000002080  7776757473727170\n"
+      "         0000000000002088  7f7e7d7c7b7a7978\n"
+      "         ................  ................\n"
+      "    #02  0000000000001000  0706050403020100\n"
+      "         0000000000001008  0f0e0d0c0b0a0908\n"
+      "         0000000000001010  1716151413121110\n"
+      "         0000000000001018  1f1e1d1c1b1a1918\n"
+      "         0000000000001020  2726252423222120\n"
+      "         0000000000001028  2f2e2d2c2b2a2928\n"
+      "    #03  0000000000001030  0706050403020100\n"
+      "         0000000000001038  0f0e0d0c0b0a0908\n"
+      "         0000000000001040  1716151413121110\n"
+      "         0000000000001048  1f1e1d1c1b1a1918\n"
+      "         0000000000001050  2726252423222120\n"
+      "         0000000000001058  2f2e2d2c2b2a2928\n"
+      "         0000000000001060  3736353433323130\n"
+      "         0000000000001068  3f3e3d3c3b3a3938\n"
+      "         0000000000001070  4746454443424140\n"
+      "         0000000000001078  4f4e4d4c4b4a4948\n"
+      "         0000000000001080  5756555453525150\n"
+      "         0000000000001088  5f5e5d5c5b5a5958\n"
+      "         0000000000001090  6766656463626160\n"
+      "         0000000000001098  6f6e6d6c6b6a6968\n"
+      "         00000000000010a0  7776757473727170\n"
+      "         00000000000010a8  7f7e7d7c7b7a7978\n";
+#else
+      "         00001fc0  03020100\n"
+      "         00001fc4  07060504\n"
+      "         00001fc8  0b0a0908\n"
+      "         00001fcc  0f0e0d0c\n"
+      "         00001fd0  13121110\n"
+      "         00001fd4  17161514\n"
+      "         00001fd8  1b1a1918\n"
+      "         00001fdc  1f1e1d1c\n"
+      "         00001fe0  23222120\n"
+      "         00001fe4  27262524\n"
+      "         00001fe8  2b2a2928\n"
+      "         00001fec  2f2e2d2c\n"
+      "         00001ff0  33323130\n"
+      "         00001ff4  37363534\n"
+      "         00001ff8  3b3a3938\n"
+      "         00001ffc  3f3e3d3c\n"
+      "    #00  00002000  03020100\n"
+      "         00002004  07060504\n"
+      "         00002008  0b0a0908\n"
+      "         0000200c  0f0e0d0c\n"
+      "    #01  00002010  03020100\n"
+      "         00002014  07060504\n"
+      "         00002018  0b0a0908\n"
+      "         0000201c  0f0e0d0c\n"
+      "         00002020  13121110\n"
+      "         00002024  17161514\n"
+      "         00002028  1b1a1918\n"
+      "         0000202c  1f1e1d1c\n"
+      "         00002030  23222120\n"
+      "         00002034  27262524\n"
+      "         00002038  2b2a2928\n"
+      "         0000203c  2f2e2d2c\n"
+      "         00002040  33323130\n"
+      "         00002044  37363534\n"
+      "         00002048  3b3a3938\n"
+      "         0000204c  3f3e3d3c\n"
+      "         ........  ........\n"
+      "    #02  00001000  03020100\n"
+      "         00001004  07060504\n"
+      "         00001008  0b0a0908\n"
+      "         0000100c  0f0e0d0c\n"
+      "         00001010  13121110\n"
+      "         00001014  17161514\n"
+      "         00001018  1b1a1918\n"
+      "         0000101c  1f1e1d1c\n"
+      "         00001020  23222120\n"
+      "         00001024  27262524\n"
+      "         00001028  2b2a2928\n"
+      "         0000102c  2f2e2d2c\n"
+      "    #03  00001030  03020100\n"
+      "         00001034  07060504\n"
+      "         00001038  0b0a0908\n"
+      "         0000103c  0f0e0d0c\n"
+      "         00001040  13121110\n"
+      "         00001044  17161514\n"
+      "         00001048  1b1a1918\n"
+      "         0000104c  1f1e1d1c\n"
+      "         00001050  23222120\n"
+      "         00001054  27262524\n"
+      "         00001058  2b2a2928\n"
+      "         0000105c  2f2e2d2c\n"
+      "         00001060  33323130\n"
+      "         00001064  37363534\n"
+      "         00001068  3b3a3938\n"
+      "         0000106c  3f3e3d3c\n";
+#endif
+  EXPECT_EQ(expected, contents);
+}
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index b20014f..8798ad3 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -41,19 +41,20 @@
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <android/log.h>
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
 #include <log/log.h>
 #include <log/logprint.h>
 #include <private/android_filesystem_config.h>
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/JitDebug.h>
+#include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
+#include <unwindstack/Unwinder.h>
 
 // Needed to get DEBUGGER_SIGNAL.
 #include "debuggerd/handler.h"
 
 #include "libdebuggerd/backtrace.h"
-#include "libdebuggerd/elf_utils.h"
 #include "libdebuggerd/open_files_list.h"
 #include "libdebuggerd/utility.h"
 
@@ -62,9 +63,6 @@
 using android::base::StringPrintf;
 using android::base::unique_fd;
 
-using unwindstack::Memory;
-using unwindstack::Regs;
-
 using namespace std::literals::string_literals;
 
 #define STACK_WORDS 16
@@ -87,7 +85,7 @@
   _LOG(log, logtype::HEADER, "Timestamp: %s\n", buf);
 }
 
-static void dump_probable_cause(log_t* log, const siginfo_t* si, BacktraceMap* map) {
+static void dump_probable_cause(log_t* log, const siginfo_t* si, unwindstack::Maps* maps) {
   std::string cause;
   if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) {
     if (si->si_addr < reinterpret_cast<void*>(4096)) {
@@ -104,12 +102,9 @@
       cause = "call to kuser_cmpxchg64";
     }
   } else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) {
-    for (auto it = map->begin(); it != map->end(); ++it) {
-      const backtrace_map_t* entry = *it;
-      if (si->si_addr >= reinterpret_cast<void*>(entry->start) &&
-          si->si_addr < reinterpret_cast<void*>(entry->end) && entry->flags == PROT_EXEC) {
-        cause = "execute-only (no-read) memory access error; likely due to data in .text.";
-      }
+    unwindstack::MapInfo* map_info = maps->Find(reinterpret_cast<uint64_t>(si->si_addr));
+    if (map_info != nullptr && map_info->flags == PROT_EXEC) {
+      cause = "execute-only (no-read) memory access error; likely due to data in .text.";
     }
   } else if (si->si_signo == SIGSYS && si->si_code == SYS_SECCOMP) {
     cause = StringPrintf("seccomp prevented call to disallowed %s system call %d", ABI_STRING,
@@ -119,7 +114,8 @@
   if (!cause.empty()) _LOG(log, logtype::HEADER, "Cause: %s\n", cause.c_str());
 }
 
-static void dump_signal_info(log_t* log, const ThreadInfo& thread_info, Memory* process_memory) {
+static void dump_signal_info(log_t* log, const ThreadInfo& thread_info,
+                             unwindstack::Memory* process_memory) {
   char addr_desc[64];  // ", fault addr 0x1234"
   if (signal_has_si_addr(thread_info.siginfo)) {
     void* addr = thread_info.siginfo->si_addr;
@@ -156,14 +152,14 @@
        thread_info.tid, thread_info.thread_name.c_str(), thread_info.process_name.c_str());
 }
 
-static void dump_stack_segment(log_t* log, BacktraceMap* backtrace_map, Memory* process_memory,
+static void dump_stack_segment(log_t* log, unwindstack::Maps* maps, unwindstack::Memory* memory,
                                uint64_t* sp, size_t words, int label) {
   // Read the data all at once.
   word_t stack_data[words];
 
   // TODO: Do we need to word align this for crashes caused by a misaligned sp?
   //       The process_vm_readv implementation of Memory should handle this appropriately?
-  size_t bytes_read = process_memory->Read(*sp, stack_data, sizeof(word_t) * words);
+  size_t bytes_read = memory->Read(*sp, stack_data, sizeof(word_t) * words);
   words = bytes_read / sizeof(word_t);
   std::string line;
   for (size_t i = 0; i < words; i++) {
@@ -176,17 +172,15 @@
     }
     line += StringPrintf("%" PRIPTR "  %" PRIPTR, *sp, static_cast<uint64_t>(stack_data[i]));
 
-    backtrace_map_t map;
-    backtrace_map->FillIn(stack_data[i], &map);
-    std::string map_name{map.Name()};
-    if (BacktraceMap::IsValid(map) && !map_name.empty()) {
-      line += "  " + map_name;
-      uint64_t offset = 0;
-      std::string func_name = backtrace_map->GetFunctionName(stack_data[i], &offset);
-      if (!func_name.empty()) {
+    unwindstack::MapInfo* map_info = maps->Find(stack_data[i]);
+    if (map_info != nullptr && !map_info->name.empty()) {
+      line += "  " + map_info->name;
+      std::string func_name;
+      uint64_t func_offset = 0;
+      if (map_info->GetFunctionName(stack_data[i], &func_name, &func_offset)) {
         line += " (" + func_name;
-        if (offset) {
-          line += StringPrintf("+%" PRIu64, offset);
+        if (func_offset) {
+          line += StringPrintf("+%" PRIu64, func_offset);
         }
         line += ')';
       }
@@ -197,12 +191,11 @@
   }
 }
 
-static void dump_stack(log_t* log, BacktraceMap* backtrace_map, Memory* process_memory,
-                       std::vector<backtrace_frame_data_t>& frames) {
+static void dump_stack(log_t* log, const std::vector<unwindstack::FrameData>& frames,
+                       unwindstack::Maps* maps, unwindstack::Memory* memory) {
   size_t first = 0, last;
   for (size_t i = 0; i < frames.size(); i++) {
-    const backtrace_frame_data_t& frame = frames[i];
-    if (frame.sp) {
+    if (frames[i].sp) {
       if (!first) {
         first = i+1;
       }
@@ -217,29 +210,44 @@
 
   // Dump a few words before the first frame.
   uint64_t sp = frames[first].sp - STACK_WORDS * sizeof(word_t);
-  dump_stack_segment(log, backtrace_map, process_memory, &sp, STACK_WORDS, -1);
+  dump_stack_segment(log, maps, memory, &sp, STACK_WORDS, -1);
+
+#if defined(__LP64__)
+  static constexpr const char delimiter[] = "         ................  ................\n";
+#else
+  static constexpr const char delimiter[] = "         ........  ........\n";
+#endif
 
   // Dump a few words from all successive frames.
-  // Only log the first 3 frames, put the rest in the tombstone.
   for (size_t i = first; i <= last; i++) {
-    const backtrace_frame_data_t* frame = &frames[i];
+    auto* frame = &frames[i];
     if (sp != frame->sp) {
-      _LOG(log, logtype::STACK, "         ........  ........\n");
+      _LOG(log, logtype::STACK, delimiter);
       sp = frame->sp;
     }
-    if (i == last) {
-      dump_stack_segment(log, backtrace_map, process_memory, &sp, STACK_WORDS, i);
-      if (sp < frame->sp + frame->stack_size) {
-        _LOG(log, logtype::STACK, "         ........  ........\n");
-      }
-    } else {
-      size_t words = frame->stack_size / sizeof(word_t);
-      if (words == 0) {
-        words = 1;
-      } else if (words > STACK_WORDS) {
+    if (i != last) {
+      // Print stack data up to the stack from the next frame.
+      size_t words;
+      uint64_t next_sp = frames[i + 1].sp;
+      if (next_sp < sp) {
+        // The next frame is probably using a completely different stack,
+        // so dump the max from this stack.
         words = STACK_WORDS;
+      } else {
+        words = (next_sp - sp) / sizeof(word_t);
+        if (words == 0) {
+          // The sp is the same as the next frame, print at least
+          // one line for this frame.
+          words = 1;
+        } else if (words > STACK_WORDS) {
+          words = STACK_WORDS;
+        }
       }
-      dump_stack_segment(log, backtrace_map, process_memory, &sp, words, i);
+      dump_stack_segment(log, maps, memory, &sp, words, i);
+    } else {
+      // Print some number of words past the last stack frame since we
+      // don't know how large the stack is.
+      dump_stack_segment(log, maps, memory, &sp, STACK_WORDS, i);
     }
   }
 }
@@ -256,7 +264,7 @@
   return addr_str;
 }
 
-static void dump_abort_message(log_t* log, Memory* process_memory, uint64_t address) {
+static void dump_abort_message(log_t* log, unwindstack::Memory* process_memory, uint64_t address) {
   if (address == 0) {
     return;
   }
@@ -285,16 +293,16 @@
   _LOG(log, logtype::HEADER, "Abort message: '%s'\n", &msg[0]);
 }
 
-static void dump_all_maps(log_t* log, BacktraceMap* map, Memory* process_memory, uint64_t addr) {
+static void dump_all_maps(log_t* log, unwindstack::Unwinder* unwinder, uint64_t addr) {
   bool print_fault_address_marker = addr;
 
-  ScopedBacktraceMapIteratorLock lock(map);
+  unwindstack::Maps* maps = unwinder->GetMaps();
   _LOG(log, logtype::MAPS,
        "\n"
        "memory map (%zu entr%s):",
-       map->size(), map->size() == 1 ? "y" : "ies");
+       maps->Total(), maps->Total() == 1 ? "y" : "ies");
   if (print_fault_address_marker) {
-    if (map->begin() != map->end() && addr < (*map->begin())->start) {
+    if (maps->Total() != 0 && addr < maps->Get(0)->start) {
       _LOG(log, logtype::MAPS, "\n--->Fault address falls at %s before any mapped regions\n",
            get_addr_string(addr).c_str());
       print_fault_address_marker = false;
@@ -305,51 +313,54 @@
     _LOG(log, logtype::MAPS, "\n");
   }
 
+  std::shared_ptr<unwindstack::Memory>& process_memory = unwinder->GetProcessMemory();
+
   std::string line;
-  for (auto it = map->begin(); it != map->end(); ++it) {
-    const backtrace_map_t* entry = *it;
+  for (unwindstack::MapInfo* map_info : *maps) {
     line = "    ";
     if (print_fault_address_marker) {
-      if (addr < entry->start) {
+      if (addr < map_info->start) {
         _LOG(log, logtype::MAPS, "--->Fault address falls at %s between mapped regions\n",
              get_addr_string(addr).c_str());
         print_fault_address_marker = false;
-      } else if (addr >= entry->start && addr < entry->end) {
+      } else if (addr >= map_info->start && addr < map_info->end) {
         line = "--->";
         print_fault_address_marker = false;
       }
     }
-    line += get_addr_string(entry->start) + '-' + get_addr_string(entry->end - 1) + ' ';
-    if (entry->flags & PROT_READ) {
+    line += get_addr_string(map_info->start) + '-' + get_addr_string(map_info->end - 1) + ' ';
+    if (map_info->flags & PROT_READ) {
       line += 'r';
     } else {
       line += '-';
     }
-    if (entry->flags & PROT_WRITE) {
+    if (map_info->flags & PROT_WRITE) {
       line += 'w';
     } else {
       line += '-';
     }
-    if (entry->flags & PROT_EXEC) {
+    if (map_info->flags & PROT_EXEC) {
       line += 'x';
     } else {
       line += '-';
     }
-    line += StringPrintf("  %8" PRIx64 "  %8" PRIx64, entry->offset, entry->end - entry->start);
+    line += StringPrintf("  %8" PRIx64 "  %8" PRIx64, map_info->offset,
+                         map_info->end - map_info->start);
     bool space_needed = true;
-    if (entry->name.length() > 0) {
+    if (!map_info->name.empty()) {
       space_needed = false;
-      line += "  " + entry->name;
-      std::string build_id;
-      if ((entry->flags & PROT_READ) && elf_get_build_id(process_memory, entry->start, &build_id)) {
+      line += "  " + map_info->name;
+      std::string build_id = map_info->GetPrintableBuildID();
+      if (!build_id.empty()) {
         line += " (BuildId: " + build_id + ")";
       }
     }
-    if (entry->load_bias != 0) {
+    uint64_t load_bias = map_info->GetLoadBias(process_memory);
+    if (load_bias != 0) {
       if (space_needed) {
         line += ' ';
       }
-      line += StringPrintf(" (load bias 0x%" PRIx64 ")", entry->load_bias);
+      line += StringPrintf(" (load bias 0x%" PRIx64 ")", load_bias);
     }
     _LOG(log, logtype::MAPS, "%s\n", line.c_str());
   }
@@ -359,9 +370,9 @@
   }
 }
 
-void dump_backtrace(log_t* log, std::vector<backtrace_frame_data_t>& frames, const char* prefix) {
-  for (auto& frame : frames) {
-    _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, Backtrace::FormatFrameData(&frame).c_str());
+void dump_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
+  for (size_t i = 0; i < unwinder->NumFrames(); i++) {
+    _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
   }
 }
 
@@ -377,7 +388,7 @@
   _LOG(log, logtype::REGISTERS, "  %s\n", output.c_str());
 }
 
-void dump_registers(log_t* log, Regs* regs) {
+void dump_registers(log_t* log, unwindstack::Regs* regs) {
   // Split lr/sp/pc into their own special row.
   static constexpr size_t column_count = 4;
   std::vector<std::pair<std::string, uint64_t>> current_row;
@@ -416,23 +427,22 @@
   print_register_row(log, special_row);
 }
 
-void dump_memory_and_code(log_t* log, BacktraceMap* map, Memory* memory, Regs* regs) {
-  regs->IterateRegisters([log, map, memory](const char* reg_name, uint64_t reg_value) {
+void dump_memory_and_code(log_t* log, unwindstack::Maps* maps, unwindstack::Memory* memory,
+                          unwindstack::Regs* regs) {
+  regs->IterateRegisters([log, maps, memory](const char* reg_name, uint64_t reg_value) {
     std::string label{"memory near "s + reg_name};
-    if (map) {
-      backtrace_map_t map_info;
-      map->FillIn(reg_value, &map_info);
-      std::string map_name{map_info.Name()};
-      if (!map_name.empty()) label += " (" + map_info.Name() + ")";
+    if (maps) {
+      unwindstack::MapInfo* map_info = maps->Find(reg_value);
+      if (map_info != nullptr && !map_info->name.empty()) {
+        label += " (" + map_info->name + ")";
+      }
     }
     dump_memory(log, memory, reg_value, label);
   });
 }
 
-static bool dump_thread(log_t* log, BacktraceMap* map, Memory* process_memory,
-                        const ThreadInfo& thread_info, uint64_t abort_msg_address,
-                        bool primary_thread) {
-  UNUSED(process_memory);
+static bool dump_thread(log_t* log, unwindstack::Unwinder* unwinder, const ThreadInfo& thread_info,
+                        uint64_t abort_msg_address, bool primary_thread) {
   log->current_tid = thread_info.tid;
   if (!primary_thread) {
     _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
@@ -440,41 +450,41 @@
   dump_thread_info(log, thread_info);
 
   if (thread_info.siginfo) {
-    dump_signal_info(log, thread_info, process_memory);
-    dump_probable_cause(log, thread_info.siginfo, map);
+    dump_signal_info(log, thread_info, unwinder->GetProcessMemory().get());
+    dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps());
   }
 
   if (primary_thread) {
-    dump_abort_message(log, process_memory, abort_msg_address);
+    dump_abort_message(log, unwinder->GetProcessMemory().get(), abort_msg_address);
   }
 
   dump_registers(log, thread_info.registers.get());
 
   // Unwind will mutate the registers, so make a copy first.
-  std::unique_ptr<Regs> regs_copy(thread_info.registers->Clone());
-  std::vector<backtrace_frame_data_t> frames;
-  if (!Backtrace::Unwind(regs_copy.get(), map, &frames, 0, nullptr)) {
+  std::unique_ptr<unwindstack::Regs> regs_copy(thread_info.registers->Clone());
+  unwinder->SetRegs(regs_copy.get());
+  unwinder->Unwind();
+  if (unwinder->NumFrames() == 0) {
     _LOG(log, logtype::THREAD, "Failed to unwind");
-    return false;
-  }
-
-  if (!frames.empty()) {
+  } else {
     _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
-    dump_backtrace(log, frames, "    ");
+    dump_backtrace(log, unwinder, "    ");
 
     _LOG(log, logtype::STACK, "\nstack:\n");
-    dump_stack(log, map, process_memory, frames);
+    dump_stack(log, unwinder->frames(), unwinder->GetMaps(), unwinder->GetProcessMemory().get());
   }
 
   if (primary_thread) {
-    dump_memory_and_code(log, map, process_memory, thread_info.registers.get());
-    if (map) {
+    unwindstack::Maps* maps = unwinder->GetMaps();
+    dump_memory_and_code(log, maps, unwinder->GetProcessMemory().get(),
+                         thread_info.registers.get());
+    if (maps != nullptr) {
       uint64_t addr = 0;
       siginfo_t* si = thread_info.siginfo;
       if (signal_has_si_addr(si)) {
         addr = reinterpret_cast<uint64_t>(si->si_addr);
       }
-      dump_all_maps(log, map, process_memory, addr);
+      dump_all_maps(log, unwinder, addr);
     }
   }
 
@@ -625,7 +635,8 @@
   read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), "<unknown>");
   read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>");
 
-  std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext));
+  std::unique_ptr<unwindstack::Regs> regs(
+      unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
 
   std::map<pid_t, ThreadInfo> threads;
   threads[gettid()] = ThreadInfo{
@@ -637,18 +648,16 @@
       .siginfo = siginfo,
   };
 
-  std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(getpid(), false));
-  if (!backtrace_map) {
-    ALOGE("failed to create backtrace map");
-    _exit(1);
+  unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid);
+  if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
+    LOG(FATAL) << "Failed to init unwinder object.";
   }
 
-  std::shared_ptr<Memory> process_memory = backtrace_map->GetProcessMemory();
-  engrave_tombstone(unique_fd(dup(tombstone_fd)), backtrace_map.get(), process_memory.get(),
-                    threads, tid, abort_msg_address, nullptr, nullptr);
+  engrave_tombstone(unique_fd(dup(tombstone_fd)), &unwinder, threads, tid, abort_msg_address,
+                    nullptr, nullptr);
 }
 
-void engrave_tombstone(unique_fd output_fd, BacktraceMap* map, Memory* process_memory,
+void engrave_tombstone(unique_fd output_fd, unwindstack::Unwinder* unwinder,
                        const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
                        uint64_t abort_msg_address, OpenFilesList* open_files,
                        std::string* amfd_data) {
@@ -669,7 +678,7 @@
   if (it == threads.end()) {
     LOG(FATAL) << "failed to find target thread";
   }
-  dump_thread(&log, map, process_memory, it->second, abort_msg_address, true);
+  dump_thread(&log, unwinder, it->second, abort_msg_address, true);
 
   if (want_logs) {
     dump_logs(&log, it->second.pid, 50);
@@ -680,7 +689,7 @@
       continue;
     }
 
-    dump_thread(&log, map, process_memory, thread_info, 0, false);
+    dump_thread(&log, unwinder, thread_info, 0, false);
   }
 
   if (open_files) {