Merge "avb_ops: support reading from a logical partition" into qt-dev
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 8c33ca5..3b29ab5 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -57,11 +57,12 @@
 // We can't find out whether we have support for AIO on ffs endpoints until we submit a read.
 static std::optional<bool> gFfsAioSupported;
 
+// Not all USB controllers support operations larger than 16k, so don't go above that.
 static constexpr size_t kUsbReadQueueDepth = 32;
-static constexpr size_t kUsbReadSize = 8 * PAGE_SIZE;
+static constexpr size_t kUsbReadSize = 4 * PAGE_SIZE;
 
 static constexpr size_t kUsbWriteQueueDepth = 32;
-static constexpr size_t kUsbWriteSize = 8 * PAGE_SIZE;
+static constexpr size_t kUsbWriteSize = 4 * PAGE_SIZE;
 
 static const char* to_string(enum usb_functionfs_event_type type) {
     switch (type) {
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 0cf3378..2e226da 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -183,6 +183,12 @@
             ],
         },
     },
+
+    product_variables: {
+        debuggable: {
+            cflags: ["-DROOT_POSSIBLE"],
+        },
+    },
 }
 
 cc_test {
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 437450c..c608a8c 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -48,6 +48,7 @@
 #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>
@@ -362,6 +363,12 @@
   DefuseSignalHandlers();
   InstallSigPipeHandler();
 
+  // There appears to be a bug in the kernel where our death causes SIGHUP to
+  // be sent to our process group if we exit while it has stopped jobs (e.g.
+  // because of wait_for_gdb). Use setsid to create a new process group to
+  // avoid hitting this.
+  setsid();
+
   atrace_begin(ATRACE_TAG, "before reparent");
   pid_t target_process = getppid();
 
@@ -566,7 +573,7 @@
 
   // TODO: Use seccomp to lock ourselves down.
   unwindstack::UnwinderFromPid unwinder(256, vm_pid);
-  if (!unwinder.Init()) {
+  if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
     LOG(FATAL) << "Failed to init unwinder object.";
   }
 
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 5f7ebc3..bbec612 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -42,6 +42,7 @@
 #include <android-base/file.h>
 #include <android-base/unique_fd.h>
 #include <async_safe/log.h>
+#include <unwindstack/DexFiles.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
@@ -80,12 +81,12 @@
     thread.pid = getpid();
     thread.tid = gettid();
     thread.thread_name = get_thread_name(gettid());
-    thread.registers.reset(
-        unwindstack::Regs::CreateFromUcontext(unwindstack::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?
     unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid());
-    if (unwinder.Init()) {
+    if (unwinder.Init(arch)) {
       dump_backtrace_thread(output_fd, &unwinder, thread);
     } else {
       async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Unable to init unwinder.");
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index bca5e36..598ea85 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -268,8 +268,15 @@
       _exit(errno);
     }
 
-    // Exit immediately on both sides of the fork.
-    // crash_dump is ptracing us, so it'll get to do whatever it wants in between.
+    // crash_dump is ptracing both sides of the fork; it'll let the parent exit,
+    // but keep the orphan stopped to peek at its memory.
+
+    // There appears to be a bug in the kernel where our death causes SIGHUP to
+    // be sent to our process group if we exit while it has stopped jobs (e.g.
+    // because of wait_for_gdb). Use setsid to create a new process group to
+    // avoid hitting this.
+    setsid();
+
     _exit(0);
   }
 
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index 94fcfb2..c606970 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -74,10 +74,7 @@
     return;
   }
 
-  unwinder->SetDisplayBuildID(true);
-  for (size_t i = 0; i < unwinder->NumFrames(); i++) {
-    _LOG(&log, logtype::BACKTRACE, "  %s\n", unwinder->FormatFrame(i).c_str());
-  }
+  log_backtrace(&log, unwinder, "  ");
 }
 
 void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 238c00c..f189c45 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -73,9 +73,12 @@
 void _LOG(log_t* log, logtype ltype, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
 
 namespace unwindstack {
+class Unwinder;
 class Memory;
 }
 
+void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix);
+
 void dump_memory(log_t* log, unwindstack::Memory* backtrace, uint64_t addr, const std::string&);
 
 void read_with_default(const char* path, char* buf, size_t len, const char* default_value);
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 4c1d633..d1726cd 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -45,6 +45,7 @@
 #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>
@@ -370,13 +371,6 @@
   }
 }
 
-void dump_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
-  unwinder->SetDisplayBuildID(true);
-  for (size_t i = 0; i < unwinder->NumFrames(); i++) {
-    _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
-  }
-}
-
 static void print_register_row(log_t* log,
                                const std::vector<std::pair<std::string, uint64_t>>& registers) {
   std::string output;
@@ -469,7 +463,7 @@
     _LOG(log, logtype::THREAD, "Failed to unwind");
   } else {
     _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
-    dump_backtrace(log, unwinder, "    ");
+    log_backtrace(log, unwinder, "    ");
 
     _LOG(log, logtype::STACK, "\nstack:\n");
     dump_stack(log, unwinder->frames(), unwinder->GetMaps(), unwinder->GetProcessMemory().get());
@@ -650,7 +644,7 @@
   };
 
   unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid);
-  if (!unwinder.Init()) {
+  if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
     LOG(FATAL) << "Failed to init unwinder object.";
   }
 
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 7aebea8..9b2779a 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -38,6 +38,7 @@
 #include <debuggerd/handler.h>
 #include <log/log.h>
 #include <unwindstack/Memory.h>
+#include <unwindstack/Unwinder.h>
 
 using android::base::unique_fd;
 
@@ -422,3 +423,22 @@
   // Then give up...
   return "?";
 }
+
+void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
+  if (unwinder->elf_from_memory_not_file()) {
+    _LOG(log, logtype::BACKTRACE,
+         "%sNOTE: Function names and BuildId information is missing for some frames due\n", prefix);
+    _LOG(log, logtype::BACKTRACE,
+         "%sNOTE: to unreadable libraries. For unwinds of apps, only shared libraries\n", prefix);
+    _LOG(log, logtype::BACKTRACE, "%sNOTE: found under the lib/ directory are readable.\n", prefix);
+#if defined(ROOT_POSSIBLE)
+    _LOG(log, logtype::BACKTRACE,
+         "%sNOTE: On this device, run setenforce 0 to make the libraries readable.\n", prefix);
+#endif
+  }
+
+  unwinder->SetDisplayBuildID(true);
+  for (size_t i = 0; i < unwinder->NumFrames(); i++) {
+    _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
+  }
+}
diff --git a/fastboot/fuzzy_fastboot/fixtures.cpp b/fastboot/fuzzy_fastboot/fixtures.cpp
index c23da01..bc13a8c 100644
--- a/fastboot/fuzzy_fastboot/fixtures.cpp
+++ b/fastboot/fuzzy_fastboot/fixtures.cpp
@@ -59,7 +59,7 @@
 
 namespace fastboot {
 
-int FastBootTest::MatchFastboot(usb_ifc_info* info, const char* local_serial) {
+int FastBootTest::MatchFastboot(usb_ifc_info* info, const std::string& local_serial) {
     if (info->ifc_class != 0xff || info->ifc_subclass != 0x42 || info->ifc_protocol != 0x03) {
         return -1;
     }
@@ -68,8 +68,8 @@
 
     // require matching serial number or device path if requested
     // at the command line with the -s option.
-    if (local_serial && (strcmp(local_serial, info->serial_number) != 0 &&
-                         strcmp(local_serial, info->device_path) != 0))
+    if (!local_serial.empty() && local_serial != info->serial_number &&
+        local_serial != info->device_path)
         return -1;
     return 0;
 }
@@ -113,7 +113,9 @@
         ASSERT_TRUE(UsbStillAvailible());  // The device disconnected
     }
 
-    const auto matcher = [](usb_ifc_info* info) -> int { return MatchFastboot(info, nullptr); };
+    const auto matcher = [](usb_ifc_info* info) -> int {
+        return MatchFastboot(info, device_serial);
+    };
     for (int i = 0; i < MAX_USB_TRIES && !transport; i++) {
         std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
         if (usb)
@@ -172,7 +174,9 @@
         ;
     printf("WAITING FOR DEVICE\n");
     // Need to wait for device
-    const auto matcher = [](usb_ifc_info* info) -> int { return MatchFastboot(info, nullptr); };
+    const auto matcher = [](usb_ifc_info* info) -> int {
+        return MatchFastboot(info, device_serial);
+    };
     while (!transport) {
         std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
         if (usb) {
@@ -238,6 +242,7 @@
 std::string FastBootTest::cb_scratch = "";
 std::string FastBootTest::initial_slot = "";
 int FastBootTest::serial_port = 0;
+std::string FastBootTest::device_serial = "";
 
 template <bool UNLOCKED>
 void ModeTest<UNLOCKED>::SetUp() {
diff --git a/fastboot/fuzzy_fastboot/fixtures.h b/fastboot/fuzzy_fastboot/fixtures.h
index 7c8d54d..c71c897 100644
--- a/fastboot/fuzzy_fastboot/fixtures.h
+++ b/fastboot/fuzzy_fastboot/fixtures.h
@@ -43,9 +43,10 @@
 class FastBootTest : public testing::Test {
   public:
     static int serial_port;
+    static std::string device_serial;
     static constexpr int MAX_USB_TRIES = 10;
 
-    static int MatchFastboot(usb_ifc_info* info, const char* local_serial = nullptr);
+    static int MatchFastboot(usb_ifc_info* info, const std::string& local_serial = "");
     bool UsbStillAvailible();
     bool UserSpaceFastboot();
     void ReconnectFastbootDevice();
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index a40bc27..ff918a7 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -162,7 +162,7 @@
 // Test that USB even works
 TEST(USBFunctionality, USBConnect) {
     const auto matcher = [](usb_ifc_info* info) -> int {
-        return FastBootTest::MatchFastboot(info, nullptr);
+        return FastBootTest::MatchFastboot(info, fastboot::FastBootTest::device_serial);
     };
     Transport* transport = nullptr;
     for (int i = 0; i < FastBootTest::MAX_USB_TRIES && !transport; i++) {
@@ -1738,10 +1738,14 @@
         fastboot::GenerateXmlTests(fastboot::config);
     }
 
+    if (args.find("serial") != args.end()) {
+        fastboot::FastBootTest::device_serial = args.at("serial");
+    }
+
     setbuf(stdout, NULL);  // no buffering
     printf("<Waiting for Device>\n");
     const auto matcher = [](usb_ifc_info* info) -> int {
-        return fastboot::FastBootTest::MatchFastboot(info, nullptr);
+        return fastboot::FastBootTest::MatchFastboot(info, fastboot::FastBootTest::device_serial);
     };
     Transport* transport = nullptr;
     while (!transport) {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 045bb48..c1aafda 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1268,6 +1268,46 @@
     }
 }
 
+int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab) {
+    AvbUniquePtr avb_handle(nullptr);
+    int ret = FsMgrUmountStatus::SUCCESS;
+    for (auto& current_entry : *fstab) {
+        if (!IsMountPointMounted(current_entry.mount_point)) {
+            continue;
+        }
+
+        if (umount(current_entry.mount_point.c_str()) == -1) {
+            PERROR << "Failed to umount " << current_entry.mount_point;
+            ret |= FsMgrUmountStatus::ERROR_UMOUNT;
+            continue;
+        }
+
+        if (current_entry.fs_mgr_flags.logical) {
+            if (!fs_mgr_update_logical_partition(&current_entry)) {
+                LERROR << "Could not get logical partition blk_device, skipping!";
+                ret |= FsMgrUmountStatus::ERROR_DEVICE_MAPPER;
+                continue;
+            }
+        }
+
+        if (current_entry.fs_mgr_flags.avb || !current_entry.avb_keys.empty()) {
+            if (!AvbHandle::TearDownAvbHashtree(&current_entry, true /* wait */)) {
+                LERROR << "Failed to tear down AVB on mount point: " << current_entry.mount_point;
+                ret |= FsMgrUmountStatus::ERROR_VERITY;
+                continue;
+            }
+        } else if ((current_entry.fs_mgr_flags.verify)) {
+            if (!fs_mgr_teardown_verity(&current_entry, true /* wait */)) {
+                LERROR << "Failed to tear down verified partition on mount point: "
+                       << current_entry.mount_point;
+                ret |= FsMgrUmountStatus::ERROR_VERITY;
+                continue;
+            }
+        }
+    }
+    return ret;
+}
+
 // wrapper to __mount() and expects a fully prepared fstab_rec,
 // unlike fs_mgr_do_mount which does more things with avb / verity etc.
 int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& mount_point) {
@@ -1655,11 +1695,12 @@
 
 std::string fs_mgr_get_super_partition_name(int slot) {
     // Devices upgrading to dynamic partitions are allowed to specify a super
-    // partition name, assumed to be A/B (non-A/B retrofit is not supported).
-    // For devices launching with dynamic partition support, the partition
-    // name must be "super".
+    // partition name. This includes cuttlefish, which is a non-A/B device.
     std::string super_partition;
     if (fs_mgr_get_boot_config_from_kernel_cmdline("super_partition", &super_partition)) {
+        if (fs_mgr_get_slot_suffix().empty()) {
+            return super_partition;
+        }
         std::string suffix;
         if (slot == 0) {
             suffix = "_a";
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index 45cbff3..ee6ffdb 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -193,7 +193,7 @@
                                   timeout_ms, path);
 }
 
-bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
+bool UnmapDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
     DeviceMapper& dm = DeviceMapper::Instance();
     std::string path;
     if (timeout_ms > std::chrono::milliseconds::zero()) {
@@ -206,6 +206,13 @@
         LERROR << "Timed out waiting for device path to unlink: " << path;
         return false;
     }
+    return true;
+}
+
+bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
+    if (!UnmapDevice(name, timeout_ms)) {
+        return false;
+    }
     LINFO << "Unmapped logical partition " << name;
     return true;
 }
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 11602ea..70abf5b 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -103,3 +103,11 @@
 
 bool fs_mgr_is_ext4(const std::string& blk_device);
 bool fs_mgr_is_f2fs(const std::string& blk_device);
+
+bool fs_mgr_teardown_verity(android::fs_mgr::FstabEntry* fstab, bool wait);
+
+namespace android {
+namespace fs_mgr {
+bool UnmapDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms);
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index c53e866..3f09157 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -44,6 +44,7 @@
 #include "fec/io.h"
 
 #include "fs_mgr.h"
+#include "fs_mgr_dm_linear.h"
 #include "fs_mgr_priv.h"
 
 // Realistically, this file should be part of the android::fs_mgr namespace;
@@ -882,3 +883,12 @@
 
     return retval;
 }
+
+bool fs_mgr_teardown_verity(FstabEntry* entry, bool wait) {
+    const std::string mount_point(basename(entry->mount_point.c_str()));
+    if (!android::fs_mgr::UnmapDevice(mount_point, wait ? 1000ms : 0ms)) {
+        return false;
+    }
+    LINFO << "Unmapped verity device " << mount_point;
+    return true;
+}
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 8abe609..88b2f8f 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -93,3 +93,14 @@
 // specified, the super partition for the corresponding metadata slot will be
 // returned. Otherwise, it will use the current slot.
 std::string fs_mgr_get_super_partition_name(int slot = -1);
+
+enum FsMgrUmountStatus : int {
+    SUCCESS = 0,
+    ERROR_UNKNOWN = 1 << 0,
+    ERROR_UMOUNT = 1 << 1,
+    ERROR_VERITY = 1 << 2,
+    ERROR_DEVICE_MAPPER = 1 << 3,
+};
+// fs_mgr_umount_all() is the reverse of fs_mgr_mount_all. In particular,
+// it destroys verity devices from device mapper after the device is unmounted.
+int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab);
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index f0767dc..04776ed 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -449,6 +449,29 @@
     return AvbHashtreeResult::kSuccess;
 }
 
+bool AvbHandle::TearDownAvbHashtree(FstabEntry* fstab_entry, bool wait) {
+    if (!fstab_entry) {
+        return false;
+    }
+
+    const std::string device_name(GetVerityDeviceName(*fstab_entry));
+
+    // TODO: remove duplicated code with UnmapDevice()
+    android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
+    std::string path;
+    if (wait) {
+        dm.GetDmDevicePathByName(device_name, &path);
+    }
+    if (!dm.DeleteDevice(device_name)) {
+        return false;
+    }
+    if (!path.empty() && !WaitForFile(path, 1000ms, FileWaitMode::DoesNotExist)) {
+        return false;
+    }
+
+    return true;
+}
+
 std::string AvbHandle::GetSecurityPatchLevel(const FstabEntry& fstab_entry) const {
     if (vbmeta_images_.size() < 1) {
         return "";
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
index 7127fa6..521f2d5 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
@@ -110,6 +110,11 @@
     static AvbHashtreeResult SetUpStandaloneAvbHashtree(FstabEntry* fstab_entry,
                                                         bool wait_for_verity_dev = true);
 
+    // Tear down dm devices created by SetUp[Standalone]AvbHashtree
+    // The 'wait' parameter makes this function wait for the verity device to get destroyed
+    // before return.
+    static bool TearDownAvbHashtree(FstabEntry* fstab_entry, bool wait);
+
     static bool IsDeviceUnlocked();
 
     std::string GetSecurityPatchLevel(const FstabEntry& fstab_entry) const;
diff --git a/fs_mgr/libfs_avb/tests/util_test.cpp b/fs_mgr/libfs_avb/tests/util_test.cpp
index 9e37d22..12b5acb 100644
--- a/fs_mgr/libfs_avb/tests/util_test.cpp
+++ b/fs_mgr/libfs_avb/tests/util_test.cpp
@@ -27,6 +27,7 @@
 
 // Target functions to test:
 using android::fs_mgr::BytesToHex;
+using android::fs_mgr::FileWaitMode;
 using android::fs_mgr::HexToBytes;
 using android::fs_mgr::NibbleValue;
 using android::fs_mgr::WaitForFile;
@@ -175,7 +176,7 @@
     // Waits this path.
     base::FilePath wait_path = tmp_dir.Append("libfs_avb-test-exist-dir");
     ASSERT_TRUE(base::DeleteFile(wait_path, false /* resursive */));
-    auto wait_file = std::async(WaitForFile, wait_path.value(), 500ms);
+    auto wait_file = std::async(WaitForFile, wait_path.value(), 500ms, FileWaitMode::Exists);
 
     // Sleeps 100ms before creating the wait_path.
     std::this_thread::sleep_for(100ms);
@@ -196,7 +197,7 @@
     // Waits this path.
     base::FilePath wait_path = tmp_dir.Append("libfs_avb-test-exist-dir");
     ASSERT_TRUE(base::DeleteFile(wait_path, false /* resursive */));
-    auto wait_file = std::async(WaitForFile, wait_path.value(), 50ms);
+    auto wait_file = std::async(WaitForFile, wait_path.value(), 50ms, FileWaitMode::Exists);
 
     // Sleeps 100ms before creating the wait_path.
     std::this_thread::sleep_for(100ms);
diff --git a/fs_mgr/libfs_avb/util.cpp b/fs_mgr/libfs_avb/util.cpp
index 9d4f05f..d214b5b 100644
--- a/fs_mgr/libfs_avb/util.cpp
+++ b/fs_mgr/libfs_avb/util.cpp
@@ -82,12 +82,17 @@
     return hex;
 }
 
-bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout) {
+// TODO: remove duplicate code with fs_mgr_wait_for_file
+bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout,
+                 FileWaitMode file_wait_mode) {
     auto start_time = std::chrono::steady_clock::now();
 
     while (true) {
-        if (0 == access(filename.c_str(), F_OK) || errno != ENOENT) {
-            return true;
+        int rv = access(filename.c_str(), F_OK);
+        if (file_wait_mode == FileWaitMode::Exists) {
+            if (!rv || errno != ENOENT) return true;
+        } else if (file_wait_mode == FileWaitMode::DoesNotExist) {
+            if (rv && errno == ENOENT) return true;
         }
 
         std::this_thread::sleep_for(50ms);
diff --git a/fs_mgr/libfs_avb/util.h b/fs_mgr/libfs_avb/util.h
index cb861f4..7763da5 100644
--- a/fs_mgr/libfs_avb/util.h
+++ b/fs_mgr/libfs_avb/util.h
@@ -52,7 +52,9 @@
 
 std::string BytesToHex(const uint8_t* bytes, size_t bytes_len);
 
-bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout);
+enum class FileWaitMode { Exists, DoesNotExist };
+bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout,
+                 FileWaitMode wait_mode = FileWaitMode::Exists);
 
 bool IsDeviceUnlocked();
 
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 8437e37..fc75072 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -451,13 +451,13 @@
     if (false) DumpState();
 }
 
-/* mount_fstab
+/* handle_fstab
  *
- *  Call fs_mgr_mount_all() to mount the given fstab
+ *  Read the given fstab file and execute func on it.
  */
-static Result<int> mount_fstab(const char* fstabfile, int mount_mode) {
+static Result<int> handle_fstab(const std::string& fstabfile, std::function<int(Fstab*)> func) {
     /*
-     * Call fs_mgr_mount_all() to mount all filesystems.  We fork(2) and
+     * Call fs_mgr_[u]mount_all() to [u]mount all filesystems.  We fork(2) and
      * do the call in the child to provide protection to the main init
      * process if anything goes wrong (crash or memory leak), and wait for
      * the child to finish in the parent.
@@ -478,25 +478,51 @@
             return Error() << "child aborted";
         }
     } else if (pid == 0) {
-        /* child, call fs_mgr_mount_all() */
+        /* child, call fs_mgr_[u]mount_all() */
 
-        // So we can always see what fs_mgr_mount_all() does.
+        // So we can always see what fs_mgr_[u]mount_all() does.
         // Only needed if someone explicitly changes the default log level in their init.rc.
         android::base::ScopedLogSeverity info(android::base::INFO);
 
         Fstab fstab;
         ReadFstabFromFile(fstabfile, &fstab);
 
-        int child_ret = fs_mgr_mount_all(&fstab, mount_mode);
-        if (child_ret == -1) {
-            PLOG(ERROR) << "fs_mgr_mount_all returned an error";
-        }
+        int child_ret = func(&fstab);
+
         _exit(child_ret);
     } else {
         return Error() << "fork() failed";
     }
 }
 
+/* mount_fstab
+ *
+ *  Call fs_mgr_mount_all() to mount the given fstab
+ */
+static Result<int> mount_fstab(const std::string& fstabfile, int mount_mode) {
+    return handle_fstab(fstabfile, [mount_mode](Fstab* fstab) {
+        int ret = fs_mgr_mount_all(fstab, mount_mode);
+        if (ret == -1) {
+            PLOG(ERROR) << "fs_mgr_mount_all returned an error";
+        }
+        return ret;
+    });
+}
+
+/* umount_fstab
+ *
+ *  Call fs_mgr_umount_all() to umount the given fstab
+ */
+static Result<int> umount_fstab(const std::string& fstabfile) {
+    return handle_fstab(fstabfile, [](Fstab* fstab) {
+        int ret = fs_mgr_umount_all(fstab);
+        if (ret != 0) {
+            PLOG(ERROR) << "fs_mgr_umount_all returned " << ret;
+        }
+        return ret;
+    });
+}
+
 /* Queue event based on fs_mgr return code.
  *
  * code: return code of fs_mgr_mount_all
@@ -583,7 +609,7 @@
     bool import_rc = true;
     bool queue_event = true;
     int mount_mode = MOUNT_MODE_DEFAULT;
-    const char* fstabfile = args[1].c_str();
+    const auto& fstabfile = args[1];
     std::size_t path_arg_end = args.size();
     const char* prop_post_fix = "default";
 
@@ -626,6 +652,15 @@
     return Success();
 }
 
+/* umount_all <fstab> */
+static Result<Success> do_umount_all(const BuiltinArguments& args) {
+    auto umount_fstab_return_code = umount_fstab(args[1]);
+    if (!umount_fstab_return_code) {
+        return Error() << "umount_fstab() failed " << umount_fstab_return_code.error();
+    }
+    return Success();
+}
+
 static Result<Success> do_swapon_all(const BuiltinArguments& args) {
     Fstab fstab;
     if (!ReadFstabFromFile(args[1], &fstab)) {
@@ -1165,6 +1200,7 @@
         {"mount",                   {3,     kMax, {false,  do_mount}}},
         {"parse_apex_configs",      {0,     0,    {false,  do_parse_apex_configs}}},
         {"umount",                  {1,     1,    {false,  do_umount}}},
+        {"umount_all",              {1,     1,    {false,  do_umount_all}}},
         {"readahead",               {1,     2,    {true,   do_readahead}}},
         {"restart",                 {1,     1,    {false,  do_restart}}},
         {"restorecon",              {1,     kMax, {true,   do_restorecon}}},
diff --git a/init/init.cpp b/init/init.cpp
index 0f44efd..ac0e67a 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -630,6 +630,11 @@
     InitKernelLogging(argv, InitAborter);
     LOG(INFO) << "init second stage started!";
 
+    // Set init and its forked children's oom_adj.
+    if (auto result = WriteFile("/proc/1/oom_score_adj", "-1000"); !result) {
+        LOG(ERROR) << "Unable to write -1000 to /proc/1/oom_score_adj: " << result.error();
+    }
+
     // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
     GlobalSeccomp();
 
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 6bec63c..71980d7 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -170,5 +170,7 @@
       return "Failed to unwind due to invalid unwind information";
     case BACKTRACE_UNWIND_ERROR_REPEATED_FRAME:
       return "Failed to unwind due to same sp/pc repeating";
+    case BACKTRACE_UNWIND_ERROR_INVALID_ELF:
+      return "Failed to unwind due to invalid elf";
   }
 }
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index ff19833..36640cd 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -32,6 +32,9 @@
 #include <unwindstack/Regs.h>
 #include <unwindstack/RegsGetLocal.h>
 
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
 #include <unwindstack/Unwinder.h>
 
 #include "BacktraceLog.h"
@@ -47,6 +50,14 @@
                                  regs, stack_map->process_memory());
   unwinder.SetResolveNames(stack_map->ResolveNames());
   stack_map->SetArch(regs->Arch());
+  if (stack_map->GetJitDebug() != nullptr) {
+    unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
+  }
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  if (stack_map->GetDexFiles() != nullptr) {
+    unwinder.SetDexFiles(stack_map->GetDexFiles(), regs->Arch());
+  }
+#endif
   unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore());
   if (error != nullptr) {
     switch (unwinder.LastErrorCode()) {
@@ -78,6 +89,10 @@
       case unwindstack::ERROR_REPEATED_FRAME:
         error->error_code = BACKTRACE_UNWIND_ERROR_REPEATED_FRAME;
         break;
+
+      case unwindstack::ERROR_INVALID_ELF:
+        error->error_code = BACKTRACE_UNWIND_ERROR_INVALID_ELF;
+        break;
     }
   }
 
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 726fdfa..4518891 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -43,6 +43,13 @@
   // Create the process memory object.
   process_memory_ = unwindstack::Memory::CreateProcessMemory(pid_);
 
+  // Create a JitDebug object for getting jit unwind information.
+  std::vector<std::string> search_libs_{"libart.so", "libartd.so"};
+  jit_debug_.reset(new unwindstack::JitDebug(process_memory_, search_libs_));
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  dex_files_.reset(new unwindstack::DexFiles(process_memory_, search_libs_));
+#endif
+
   if (!stack_maps_->Parse()) {
     return false;
   }
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index 9bb9709..e19b605 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -27,6 +27,9 @@
 
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
 #include <unwindstack/Elf.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
@@ -50,6 +53,12 @@
 
   const std::shared_ptr<unwindstack::Memory>& process_memory() { return process_memory_; }
 
+  unwindstack::JitDebug* GetJitDebug() { return jit_debug_.get(); }
+
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  unwindstack::DexFiles* GetDexFiles() { return dex_files_.get(); }
+#endif
+
   void SetArch(unwindstack::ArchEnum arch) { arch_ = arch; }
 
  protected:
@@ -57,6 +66,11 @@
 
   std::unique_ptr<unwindstack::Maps> stack_maps_;
   std::shared_ptr<unwindstack::Memory> process_memory_;
+  std::unique_ptr<unwindstack::JitDebug> jit_debug_;
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  std::unique_ptr<unwindstack::DexFiles> dex_files_;
+#endif
+
   unwindstack::ArchEnum arch_ = unwindstack::ARCH_UNKNOWN;
 };
 
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 10e790b..404e7e8 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -64,6 +64,8 @@
   BACKTRACE_UNWIND_ERROR_UNWIND_INFO,
   // Unwind information stopped due to sp/pc repeating.
   BACKTRACE_UNWIND_ERROR_REPEATED_FRAME,
+  // Unwind information stopped due to invalid elf.
+  BACKTRACE_UNWIND_ERROR_INVALID_ELF,
 };
 
 struct BacktraceUnwindError {
diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
index c7d0cca..ab0f1ca 100644
--- a/libprocessgroup/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -126,24 +126,15 @@
 
     switch (policy) {
         case SP_BACKGROUND:
-            return SetTaskProfiles(tid, {"HighEnergySaving", "LowIoPriority", "TimerSlackHigh"})
-                           ? 0
-                           : -1;
+            return SetTaskProfiles(tid, {"HighEnergySaving", "TimerSlackHigh"}) ? 0 : -1;
         case SP_FOREGROUND:
         case SP_AUDIO_APP:
         case SP_AUDIO_SYS:
-            return SetTaskProfiles(tid, {"HighPerformance", "HighIoPriority", "TimerSlackNormal"})
-                           ? 0
-                           : -1;
+            return SetTaskProfiles(tid, {"HighPerformance", "TimerSlackNormal"}) ? 0 : -1;
         case SP_TOP_APP:
-            return SetTaskProfiles(tid, {"MaxPerformance", "MaxIoPriority", "TimerSlackNormal"})
-                           ? 0
-                           : -1;
+            return SetTaskProfiles(tid, {"MaxPerformance", "TimerSlackNormal"}) ? 0 : -1;
         case SP_RT_APP:
-            return SetTaskProfiles(tid,
-                                   {"RealtimePerformance", "MaxIoPriority", "TimerSlackNormal"})
-                           ? 0
-                           : -1;
+            return SetTaskProfiles(tid, {"RealtimePerformance", "TimerSlackNormal"}) ? 0 : -1;
         default:
             return SetTaskProfiles(tid, {"TimerSlackNormal"}) ? 0 : -1;
     }
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index ce25108..b7650a1 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -49,6 +49,7 @@
     srcs: [
         "ArmExidx.cpp",
         "DexFile.cpp",
+        "DexFiles.cpp",
         "DwarfCfa.cpp",
         "DwarfEhFrameWithHdr.cpp",
         "DwarfMemory.cpp",
@@ -91,6 +92,7 @@
             cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
             exclude_srcs: [
                 "DexFile.cpp",
+                "DexFiles.cpp",
             ],
             exclude_shared_libs: [
                 "libdexfile_support",
@@ -100,6 +102,7 @@
             cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
             exclude_srcs: [
                 "DexFile.cpp",
+                "DexFiles.cpp",
             ],
             exclude_shared_libs: [
                 "libdexfile_support",
diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp
index d8d5a24..eaf867f 100644
--- a/libunwindstack/DexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -35,31 +35,22 @@
 std::unique_ptr<DexFile> DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory,
                                          MapInfo* info) {
   if (!info->name.empty()) {
-    std::unique_ptr<DexFile> dex_file_from_file =
+    std::unique_ptr<DexFile> dex_file =
         DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name);
-    if (dex_file_from_file) {
-      dex_file_from_file->addr_ = dex_file_offset_in_memory;
-      return dex_file_from_file;
+    if (dex_file) {
+      return dex_file;
     }
   }
-  std::unique_ptr<DexFile> dex_file_from_memory =
-      DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name);
-  if (dex_file_from_memory) {
-    dex_file_from_memory->addr_ = dex_file_offset_in_memory;
-    return dex_file_from_memory;
-  }
-  return nullptr;
+  return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name);
 }
 
-bool DexFile::GetFunctionName(uint64_t dex_pc, std::string* method_name, uint64_t* method_offset) {
-  uint64_t dex_offset = dex_pc - addr_;
+bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
+                                   uint64_t* method_offset) {
   art_api::dex::MethodInfo method_info = GetMethodInfoForOffset(dex_offset, false);
   if (method_info.offset == 0) {
     return false;
   }
-  if (method_name != nullptr) {
-    *method_name = method_info.name;
-  }
+  *method_name = method_info.name;
   *method_offset = dex_offset - method_info.offset;
   return true;
 }
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
index 1448a4b..ca658e6 100644
--- a/libunwindstack/DexFile.h
+++ b/libunwindstack/DexFile.h
@@ -29,22 +29,17 @@
 
 namespace unwindstack {
 
-class Memory;
-struct MapInfo;
-
 class DexFile : protected art_api::dex::DexFile {
  public:
   virtual ~DexFile() = default;
 
-  bool GetFunctionName(uint64_t dex_pc, std::string* method_name, uint64_t* method_offset);
+  bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
 
   static std::unique_ptr<DexFile> Create(uint64_t dex_file_offset_in_memory, Memory* memory,
                                          MapInfo* info);
 
  protected:
   DexFile(art_api::dex::DexFile&& art_dex_file) : art_api::dex::DexFile(std::move(art_dex_file)) {}
-
-  uint64_t addr_ = 0;
 };
 
 class DexFileFromFile : public DexFile {
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
new file mode 100644
index 0000000..63a77e5
--- /dev/null
+++ b/libunwindstack/DexFiles.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+#include "DexFile.h"
+
+namespace unwindstack {
+
+struct DEXFileEntry32 {
+  uint32_t next;
+  uint32_t prev;
+  uint32_t dex_file;
+};
+
+struct DEXFileEntry64 {
+  uint64_t next;
+  uint64_t prev;
+  uint64_t dex_file;
+};
+
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : Global(memory) {}
+
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
+    : Global(memory, search_libs) {}
+
+DexFiles::~DexFiles() {}
+
+void DexFiles::ProcessArch() {
+  switch (arch()) {
+    case ARCH_ARM:
+    case ARCH_MIPS:
+    case ARCH_X86:
+      read_entry_ptr_func_ = &DexFiles::ReadEntryPtr32;
+      read_entry_func_ = &DexFiles::ReadEntry32;
+      break;
+
+    case ARCH_ARM64:
+    case ARCH_MIPS64:
+    case ARCH_X86_64:
+      read_entry_ptr_func_ = &DexFiles::ReadEntryPtr64;
+      read_entry_func_ = &DexFiles::ReadEntry64;
+      break;
+
+    case ARCH_UNKNOWN:
+      abort();
+  }
+}
+
+uint64_t DexFiles::ReadEntryPtr32(uint64_t addr) {
+  uint32_t entry;
+  const uint32_t field_offset = 12;  // offset of first_entry_ in the descriptor struct.
+  if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) {
+    return 0;
+  }
+  return entry;
+}
+
+uint64_t DexFiles::ReadEntryPtr64(uint64_t addr) {
+  uint64_t entry;
+  const uint32_t field_offset = 16;  // offset of first_entry_ in the descriptor struct.
+  if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) {
+    return 0;
+  }
+  return entry;
+}
+
+bool DexFiles::ReadEntry32() {
+  DEXFileEntry32 entry;
+  if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) {
+    entry_addr_ = 0;
+    return false;
+  }
+
+  addrs_.push_back(entry.dex_file);
+  entry_addr_ = entry.next;
+  return true;
+}
+
+bool DexFiles::ReadEntry64() {
+  DEXFileEntry64 entry;
+  if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) {
+    entry_addr_ = 0;
+    return false;
+  }
+
+  addrs_.push_back(entry.dex_file);
+  entry_addr_ = entry.next;
+  return true;
+}
+
+bool DexFiles::ReadVariableData(uint64_t ptr_offset) {
+  entry_addr_ = (this->*read_entry_ptr_func_)(ptr_offset);
+  return entry_addr_ != 0;
+}
+
+void DexFiles::Init(Maps* maps) {
+  if (initialized_) {
+    return;
+  }
+  initialized_ = true;
+  entry_addr_ = 0;
+
+  FindAndReadVariable(maps, "__dex_debug_descriptor");
+}
+
+DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) {
+  // Lock while processing the data.
+  DexFile* dex_file;
+  auto entry = files_.find(dex_file_offset);
+  if (entry == files_.end()) {
+    std::unique_ptr<DexFile> new_dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
+    dex_file = new_dex_file.get();
+    files_[dex_file_offset] = std::move(new_dex_file);
+  } else {
+    dex_file = entry->second.get();
+  }
+  return dex_file;
+}
+
+bool DexFiles::GetAddr(size_t index, uint64_t* addr) {
+  if (index < addrs_.size()) {
+    *addr = addrs_[index];
+    return true;
+  }
+  if (entry_addr_ != 0 && (this->*read_entry_func_)()) {
+    *addr = addrs_.back();
+    return true;
+  }
+  return false;
+}
+
+void DexFiles::GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc,
+                                    std::string* method_name, uint64_t* method_offset) {
+  std::lock_guard<std::mutex> guard(lock_);
+  if (!initialized_) {
+    Init(maps);
+  }
+
+  size_t index = 0;
+  uint64_t addr;
+  while (GetAddr(index++, &addr)) {
+    if (addr < info->start || addr >= info->end) {
+      continue;
+    }
+
+    DexFile* dex_file = GetDexFile(addr, info);
+    if (dex_file != nullptr &&
+        dex_file->GetMethodInformation(dex_pc - addr, method_name, method_offset)) {
+      break;
+    }
+  }
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 5b402ed..3454913 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -160,7 +160,7 @@
   if (valid_) {
     return interface_->LastErrorCode();
   }
-  return ERROR_NONE;
+  return ERROR_INVALID_ELF;
 }
 
 uint64_t Elf::GetLastErrorAddress() {
@@ -170,22 +170,23 @@
   return 0;
 }
 
+// The relative pc expectd by this function is relative to the start of the elf.
+bool Elf::StepIfSignalHandler(uint64_t rel_pc, Regs* regs, Memory* process_memory) {
+  if (!valid_) {
+    return false;
+  }
+  return regs->StepIfSignalHandler(rel_pc, this, process_memory);
+}
+
 // The relative pc is always relative to the start of the map from which it comes.
-bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, Regs* regs, Memory* process_memory,
-               bool* finished) {
+bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished) {
   if (!valid_) {
     return false;
   }
 
-  // The relative pc expectd by StepIfSignalHandler is relative to the start of the elf.
-  if (regs->StepIfSignalHandler(rel_pc, this, process_memory)) {
-    *finished = false;
-    return true;
-  }
-
   // Lock during the step which can update information in the object.
   std::lock_guard<std::mutex> guard(lock_);
-  return interface_->Step(adjusted_rel_pc, regs, process_memory, finished);
+  return interface_->Step(rel_pc, regs, process_memory, finished);
 }
 
 bool Elf::IsValidElf(Memory* memory) {
@@ -243,24 +244,6 @@
   return false;
 }
 
-bool Elf::GetTextRange(uint64_t* addr, uint64_t* size) {
-  if (!valid_) {
-    return false;
-  }
-
-  if (interface_->GetTextRange(addr, size)) {
-    *addr += load_bias_;
-    return true;
-  }
-
-  if (gnu_debugdata_interface_ != nullptr && gnu_debugdata_interface_->GetTextRange(addr, size)) {
-    *addr += load_bias_;
-    return true;
-  }
-
-  return false;
-}
-
 ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) {
   if (!IsValidElf(memory)) {
     return nullptr;
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 32c637f..dee8eb3 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -69,15 +69,6 @@
   return false;
 }
 
-bool ElfInterface::GetTextRange(uint64_t* addr, uint64_t* size) {
-  if (text_size_ != 0) {
-    *addr = text_addr_;
-    *size = text_size_;
-    return true;
-  }
-  return false;
-}
-
 Memory* ElfInterface::CreateGnuDebugdataMemory() {
   if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) {
     return nullptr;
@@ -339,26 +330,29 @@
       }
       symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
                                      str_shdr.sh_offset, str_shdr.sh_size));
-    } else if (shdr.sh_type == SHT_PROGBITS || shdr.sh_type == SHT_NOBITS) {
+    } else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) {
       // Look for the .debug_frame and .gnu_debugdata.
       if (shdr.sh_name < sec_size) {
         std::string name;
         if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) {
+          uint64_t* offset_ptr = nullptr;
+          uint64_t* size_ptr = nullptr;
           if (name == ".debug_frame") {
-            debug_frame_offset_ = shdr.sh_offset;
-            debug_frame_size_ = shdr.sh_size;
+            offset_ptr = &debug_frame_offset_;
+            size_ptr = &debug_frame_size_;
           } else if (name == ".gnu_debugdata") {
-            gnu_debugdata_offset_ = shdr.sh_offset;
-            gnu_debugdata_size_ = shdr.sh_size;
+            offset_ptr = &gnu_debugdata_offset_;
+            size_ptr = &gnu_debugdata_size_;
           } else if (name == ".eh_frame") {
-            eh_frame_offset_ = shdr.sh_offset;
-            eh_frame_size_ = shdr.sh_size;
+            offset_ptr = &eh_frame_offset_;
+            size_ptr = &eh_frame_size_;
           } else if (eh_frame_hdr_offset_ == 0 && name == ".eh_frame_hdr") {
-            eh_frame_hdr_offset_ = shdr.sh_offset;
-            eh_frame_hdr_size_ = shdr.sh_size;
-          } else if (name == ".text") {
-            text_addr_ = shdr.sh_addr;
-            text_size_ = shdr.sh_size;
+            offset_ptr = &eh_frame_hdr_offset_;
+            size_ptr = &eh_frame_hdr_size_;
+          }
+          if (offset_ptr != nullptr) {
+            *offset_ptr = shdr.sh_offset;
+            *size_ptr = shdr.sh_size;
           }
         }
       }
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp
index 71665a1..20bc4b9 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -16,13 +16,8 @@
 
 #include <stdint.h>
 #include <sys/mman.h>
-#include <cstddef>
 
-#include <atomic>
-#include <deque>
-#include <map>
 #include <memory>
-#include <unordered_set>
 #include <vector>
 
 #include <unwindstack/Elf.h>
@@ -30,334 +25,197 @@
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
 
-#if !defined(NO_LIBDEXFILE_SUPPORT)
-#include <DexFile.h>
-#endif
-
 // This implements the JIT Compilation Interface.
 // See https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html
 
 namespace unwindstack {
 
-// 32-bit platforms may differ in alignment of uint64_t.
-struct Uint64_P {
-  uint64_t value;
+struct JITCodeEntry32Pack {
+  uint32_t next;
+  uint32_t prev;
+  uint32_t symfile_addr;
+  uint64_t symfile_size;
 } __attribute__((packed));
-struct Uint64_A {
-  uint64_t value;
-} __attribute__((aligned(8)));
 
-// Wrapper around other memory object which protects us against data races.
-// It will check seqlock after every read, and fail if the seqlock changed.
-// This ensues that the read memory has not been partially modified.
-struct JitMemory : public Memory {
-  size_t Read(uint64_t addr, void* dst, size_t size) override;
-
-  Memory* parent_ = nullptr;
-  uint64_t seqlock_addr_ = 0;
-  uint32_t expected_seqlock_ = 0;
-  bool failed_due_to_race_ = false;
+struct JITCodeEntry32Pad {
+  uint32_t next;
+  uint32_t prev;
+  uint32_t symfile_addr;
+  uint32_t pad;
+  uint64_t symfile_size;
 };
 
-template <typename Symfile>
-struct JitCacheEntry {
-  // PC memory range described by this entry.
-  uint64_t addr_ = 0;
-  uint64_t size_ = 0;
-  std::unique_ptr<Symfile> symfile_;
-
-  bool Init(Maps* maps, JitMemory* memory, uint64_t addr, uint64_t size);
+struct JITCodeEntry64 {
+  uint64_t next;
+  uint64_t prev;
+  uint64_t symfile_addr;
+  uint64_t symfile_size;
 };
 
-template <typename Symfile, typename PointerT, typename Uint64_T>
-class JitDebugImpl : public JitDebug<Symfile>, public Global {
- public:
-  static constexpr const char* kDescriptorExtMagic = "Android1";
-  static constexpr int kMaxRaceRetries = 16;
+struct JITDescriptorHeader {
+  uint32_t version;
+  uint32_t action_flag;
+};
 
-  struct JITCodeEntry {
-    PointerT next;
-    PointerT prev;
-    PointerT symfile_addr;
-    Uint64_T symfile_size;
-  };
+struct JITDescriptor32 {
+  JITDescriptorHeader header;
+  uint32_t relevant_entry;
+  uint32_t first_entry;
+};
 
-  struct JITDescriptor {
-    uint32_t version;
-    uint32_t action_flag;
-    PointerT relevant_entry;
-    PointerT first_entry;
-  };
+struct JITDescriptor64 {
+  JITDescriptorHeader header;
+  uint64_t relevant_entry;
+  uint64_t first_entry;
+};
 
-  // Android-specific extensions.
-  struct JITDescriptorExt {
-    JITDescriptor desc;
-    uint8_t magic[8];
-    uint32_t flags;
-    uint32_t sizeof_descriptor;
-    uint32_t sizeof_entry;
-    uint32_t action_seqlock;
-    uint64_t action_timestamp;
-  };
+JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : Global(memory) {}
 
-  JitDebugImpl(ArchEnum arch, std::shared_ptr<Memory>& memory,
-               std::vector<std::string>& search_libs)
-      : Global(memory, search_libs) {
-    SetArch(arch);
+JitDebug::JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
+    : Global(memory, search_libs) {}
+
+JitDebug::~JitDebug() {
+  for (auto* elf : elf_list_) {
+    delete elf;
+  }
+}
+
+uint64_t JitDebug::ReadDescriptor32(uint64_t addr) {
+  JITDescriptor32 desc;
+  if (!memory_->ReadFully(addr, &desc, sizeof(desc))) {
+    return 0;
   }
 
-  Symfile* Get(Maps* maps, uint64_t pc) override;
-  virtual bool ReadVariableData(uint64_t offset);
-  virtual void ProcessArch() {}
-  bool Update(Maps* maps);
-  bool Read(Maps* maps, JitMemory* memory);
+  if (desc.header.version != 1 || desc.first_entry == 0) {
+    // Either unknown version, or no jit entries.
+    return 0;
+  }
 
-  bool initialized_ = false;
-  uint64_t descriptor_addr_ = 0;  // Non-zero if we have found (non-empty) descriptor.
-  uint64_t seqlock_addr_ = 0;     // Re-read entries if the value at this address changes.
-  uint32_t last_seqlock_ = ~0u;   // The value of seqlock when we last read the entries.
+  return desc.first_entry;
+}
 
-  std::deque<JitCacheEntry<Symfile>> entries_;
+uint64_t JitDebug::ReadDescriptor64(uint64_t addr) {
+  JITDescriptor64 desc;
+  if (!memory_->ReadFully(addr, &desc, sizeof(desc))) {
+    return 0;
+  }
 
-  std::mutex lock_;
-};
+  if (desc.header.version != 1 || desc.first_entry == 0) {
+    // Either unknown version, or no jit entries.
+    return 0;
+  }
 
-template <typename Symfile>
-std::unique_ptr<JitDebug<Symfile>> JitDebug<Symfile>::Create(ArchEnum arch,
-                                                             std::shared_ptr<Memory>& memory,
-                                                             std::vector<std::string> search_libs) {
-  typedef JitDebugImpl<Symfile, uint32_t, Uint64_P> JitDebugImpl32P;
-  typedef JitDebugImpl<Symfile, uint32_t, Uint64_A> JitDebugImpl32A;
-  typedef JitDebugImpl<Symfile, uint64_t, Uint64_A> JitDebugImpl64A;
-  switch (arch) {
+  return desc.first_entry;
+}
+
+uint64_t JitDebug::ReadEntry32Pack(uint64_t* start, uint64_t* size) {
+  JITCodeEntry32Pack code;
+  if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) {
+    return 0;
+  }
+
+  *start = code.symfile_addr;
+  *size = code.symfile_size;
+  return code.next;
+}
+
+uint64_t JitDebug::ReadEntry32Pad(uint64_t* start, uint64_t* size) {
+  JITCodeEntry32Pad code;
+  if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) {
+    return 0;
+  }
+
+  *start = code.symfile_addr;
+  *size = code.symfile_size;
+  return code.next;
+}
+
+uint64_t JitDebug::ReadEntry64(uint64_t* start, uint64_t* size) {
+  JITCodeEntry64 code;
+  if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) {
+    return 0;
+  }
+
+  *start = code.symfile_addr;
+  *size = code.symfile_size;
+  return code.next;
+}
+
+void JitDebug::ProcessArch() {
+  switch (arch()) {
     case ARCH_X86:
-      static_assert(sizeof(typename JitDebugImpl32P::JITCodeEntry) == 20, "layout");
-      static_assert(sizeof(typename JitDebugImpl32P::JITDescriptor) == 16, "layout");
-      static_assert(sizeof(typename JitDebugImpl32P::JITDescriptorExt) == 48, "layout");
-      return std::unique_ptr<JitDebug>(new JitDebugImpl32P(arch, memory, search_libs));
+      read_descriptor_func_ = &JitDebug::ReadDescriptor32;
+      read_entry_func_ = &JitDebug::ReadEntry32Pack;
       break;
+
     case ARCH_ARM:
     case ARCH_MIPS:
-      static_assert(sizeof(typename JitDebugImpl32A::JITCodeEntry) == 24, "layout");
-      static_assert(sizeof(typename JitDebugImpl32A::JITDescriptor) == 16, "layout");
-      static_assert(sizeof(typename JitDebugImpl32A::JITDescriptorExt) == 48, "layout");
-      return std::unique_ptr<JitDebug>(new JitDebugImpl32A(arch, memory, search_libs));
+      read_descriptor_func_ = &JitDebug::ReadDescriptor32;
+      read_entry_func_ = &JitDebug::ReadEntry32Pad;
       break;
+
     case ARCH_ARM64:
     case ARCH_X86_64:
     case ARCH_MIPS64:
-      static_assert(sizeof(typename JitDebugImpl64A::JITCodeEntry) == 32, "layout");
-      static_assert(sizeof(typename JitDebugImpl64A::JITDescriptor) == 24, "layout");
-      static_assert(sizeof(typename JitDebugImpl64A::JITDescriptorExt) == 56, "layout");
-      return std::unique_ptr<JitDebug>(new JitDebugImpl64A(arch, memory, search_libs));
+      read_descriptor_func_ = &JitDebug::ReadDescriptor64;
+      read_entry_func_ = &JitDebug::ReadEntry64;
       break;
-    default:
+    case ARCH_UNKNOWN:
       abort();
   }
 }
 
-size_t JitMemory::Read(uint64_t addr, void* dst, size_t size) {
-  if (!parent_->ReadFully(addr, dst, size)) {
-    return 0;
-  }
-  // This is required for memory synchronization if the we are working with local memory.
-  // For other types of memory (e.g. remote) this is no-op and has no significant effect.
-  std::atomic_thread_fence(std::memory_order_acquire);
-  uint32_t seen_seqlock;
-  if (!parent_->Read32(seqlock_addr_, &seen_seqlock)) {
-    return 0;
-  }
-  if (seen_seqlock != expected_seqlock_) {
-    failed_due_to_race_ = true;
-    return 0;
-  }
-  return size;
+bool JitDebug::ReadVariableData(uint64_t ptr) {
+  entry_addr_ = (this->*read_descriptor_func_)(ptr);
+  return entry_addr_ != 0;
 }
 
-template <typename Symfile, typename PointerT, typename Uint64_T>
-bool JitDebugImpl<Symfile, PointerT, Uint64_T>::ReadVariableData(uint64_t addr) {
-  JITDescriptor desc;
-  if (!this->memory_->ReadFully(addr, &desc, sizeof(desc))) {
-    return false;
+void JitDebug::Init(Maps* maps) {
+  if (initialized_) {
+    return;
   }
-  if (desc.version != 1) {
-    return false;
-  }
-  if (desc.first_entry == 0) {
-    return false;  // There could be multiple descriptors. Ignore empty ones.
-  }
-  descriptor_addr_ = addr;
-  JITDescriptorExt desc_ext;
-  if (this->memory_->ReadFully(addr, &desc_ext, sizeof(desc_ext)) &&
-      memcmp(desc_ext.magic, kDescriptorExtMagic, 8) == 0) {
-    seqlock_addr_ = descriptor_addr_ + offsetof(JITDescriptorExt, action_seqlock);
-  } else {
-    // In the absence of Android-specific fields, use the head pointer instead.
-    seqlock_addr_ = descriptor_addr_ + offsetof(JITDescriptor, first_entry);
-  }
-  return true;
+  // Regardless of what happens below, consider the init finished.
+  initialized_ = true;
+
+  FindAndReadVariable(maps, "__jit_debug_descriptor");
 }
 
-template <typename Symfile>
-static const char* GetDescriptorName();
-
-template <>
-const char* GetDescriptorName<Elf>() {
-  return "__jit_debug_descriptor";
-}
-
-template <typename Symfile, typename PointerT, typename Uint64_T>
-Symfile* JitDebugImpl<Symfile, PointerT, Uint64_T>::Get(Maps* maps, uint64_t pc) {
+Elf* JitDebug::GetElf(Maps* maps, uint64_t pc) {
+  // Use a single lock, this object should be used so infrequently that
+  // a fine grain lock is unnecessary.
   std::lock_guard<std::mutex> guard(lock_);
   if (!initialized_) {
-    FindAndReadVariable(maps, GetDescriptorName<Symfile>());
-    initialized_ = true;
+    Init(maps);
   }
 
-  if (descriptor_addr_ == 0) {
-    return nullptr;
-  }
-
-  if (!Update(maps)) {
-    return nullptr;
-  }
-
-  Symfile* fallback = nullptr;
-  for (auto& entry : entries_) {
-    // Skip entries which are obviously not relevant (if we know the PC range).
-    if (entry.size_ == 0 || (entry.addr_ <= pc && (pc - entry.addr_) < entry.size_)) {
-      // Double check the entry contains the PC in case there are overlapping entries.
-      // This is might happen for native-code due to GC and for DEX due to data sharing.
-      std::string method_name;
-      uint64_t method_offset;
-      if (entry.symfile_->GetFunctionName(pc, &method_name, &method_offset)) {
-        return entry.symfile_.get();
-      }
-      fallback = entry.symfile_.get();  // Tests don't have any symbols.
-    }
-  }
-  return fallback;  // Not found.
-}
-
-// Update JIT entries if needed.  It will retry if there are data races.
-template <typename Symfile, typename PointerT, typename Uint64_T>
-bool JitDebugImpl<Symfile, PointerT, Uint64_T>::Update(Maps* maps) {
-  // We might need to retry the whole read in the presence of data races.
-  for (int i = 0; i < kMaxRaceRetries; i++) {
-    // Read the seqlock (counter which is incremented before and after any modification).
-    uint32_t seqlock = 0;
-    if (!this->memory_->Read32(seqlock_addr_, &seqlock)) {
-      return false;  // Failed to read seqlock.
-    }
-
-    // Check if anything changed since the last time we checked.
-    if (last_seqlock_ != seqlock) {
-      // Create memory wrapper to allow us to read the entries safely even in a live process.
-      JitMemory safe_memory;
-      safe_memory.parent_ = this->memory_.get();
-      safe_memory.seqlock_addr_ = seqlock_addr_;
-      safe_memory.expected_seqlock_ = seqlock;
-      std::atomic_thread_fence(std::memory_order_acquire);
-
-      // Add all entries to our cache.
-      if (!Read(maps, &safe_memory)) {
-        if (safe_memory.failed_due_to_race_) {
-          sleep(0);
-          continue;  // Try again (there was a data race).
-        } else {
-          return false;  // Proper failure (we could not read the data).
-        }
-      }
-      last_seqlock_ = seqlock;
-    }
-    return true;
-  }
-  return false;  // Too many retries.
-}
-
-// Read all JIT entries.  It might randomly fail due to data races.
-template <typename Symfile, typename PointerT, typename Uint64_T>
-bool JitDebugImpl<Symfile, PointerT, Uint64_T>::Read(Maps* maps, JitMemory* memory) {
-  std::unordered_set<uint64_t> seen_entry_addr;
-
-  // Read and verify the descriptor (must be after we have read the initial seqlock).
-  JITDescriptor desc;
-  if (!(memory->ReadFully(descriptor_addr_, &desc, sizeof(desc)))) {
-    return false;
-  }
-
-  entries_.clear();
-  JITCodeEntry entry;
-  for (uint64_t entry_addr = desc.first_entry; entry_addr != 0; entry_addr = entry.next) {
-    // Check for infinite loops in the lined list.
-    if (!seen_entry_addr.emplace(entry_addr).second) {
-      return true;  // TODO: Fail when seening infinite loop.
-    }
-
-    // Read the entry (while checking for data races).
-    if (!memory->ReadFully(entry_addr, &entry, sizeof(entry))) {
-      return false;
-    }
-
-    // Copy and load the symfile.
-    entries_.emplace_back(JitCacheEntry<Symfile>());
-    if (!entries_.back().Init(maps, memory, entry.symfile_addr, entry.symfile_size.value)) {
-      return false;
+  // Search the existing elf object first.
+  for (Elf* elf : elf_list_) {
+    if (elf->IsValidPc(pc)) {
+      return elf;
     }
   }
 
-  return true;
-}
+  while (entry_addr_ != 0) {
+    uint64_t start;
+    uint64_t size;
+    entry_addr_ = (this->*read_entry_func_)(&start, &size);
 
-// Copy and load ELF file.
-template <>
-bool JitCacheEntry<Elf>::Init(Maps*, JitMemory* memory, uint64_t addr, uint64_t size) {
-  // Make a copy of the in-memory symbol file (while checking for data races).
-  std::unique_ptr<MemoryBuffer> buffer(new MemoryBuffer());
-  buffer->Resize(size);
-  if (!memory->ReadFully(addr, buffer->GetPtr(0), buffer->Size())) {
-    return false;
+    Elf* elf = new Elf(new MemoryRange(memory_, start, size, 0));
+    elf->Init();
+    if (!elf->valid()) {
+      // The data is not formatted in a way we understand, do not attempt
+      // to process any other entries.
+      entry_addr_ = 0;
+      delete elf;
+      return nullptr;
+    }
+    elf_list_.push_back(elf);
+
+    if (elf->IsValidPc(pc)) {
+      return elf;
+    }
   }
-
-  // Load and validate the ELF file.
-  symfile_.reset(new Elf(buffer.release()));
-  symfile_->Init();
-  if (!symfile_->valid()) {
-    return false;
-  }
-
-  symfile_->GetTextRange(&addr_, &size_);
-  return true;
+  return nullptr;
 }
 
-template std::unique_ptr<JitDebug<Elf>> JitDebug<Elf>::Create(ArchEnum, std::shared_ptr<Memory>&,
-                                                              std::vector<std::string>);
-
-#if !defined(NO_LIBDEXFILE_SUPPORT)
-
-template <>
-const char* GetDescriptorName<DexFile>() {
-  return "__dex_debug_descriptor";
-}
-
-// Copy and load DEX file.
-template <>
-bool JitCacheEntry<DexFile>::Init(Maps* maps, JitMemory* memory, uint64_t addr, uint64_t) {
-  MapInfo* info = maps->Find(addr);
-  if (info == nullptr) {
-    return false;
-  }
-  symfile_ = DexFile::Create(addr, memory, info);
-  if (symfile_ == nullptr) {
-    return false;
-  }
-  return true;
-}
-
-template std::unique_ptr<JitDebug<DexFile>> JitDebug<DexFile>::Create(ArchEnum,
-                                                                      std::shared_ptr<Memory>&,
-                                                                      std::vector<std::string>);
-
-#endif
-
 }  // namespace unwindstack
diff --git a/libunwindstack/LocalUnwinder.cpp b/libunwindstack/LocalUnwinder.cpp
index 5b2fadf..5d81200 100644
--- a/libunwindstack/LocalUnwinder.cpp
+++ b/libunwindstack/LocalUnwinder.cpp
@@ -111,6 +111,14 @@
       pc_adjustment = 0;
     }
     step_pc -= pc_adjustment;
+
+    bool finished = false;
+    if (elf->StepIfSignalHandler(rel_pc, regs.get(), process_memory_.get())) {
+      step_pc = rel_pc;
+    } else if (!elf->Step(step_pc, regs.get(), process_memory_.get(), &finished)) {
+      finished = true;
+    }
+
     // Skip any locations that are within this library.
     if (num_frames != 0 || !ShouldSkipLibrary(map_info->name)) {
       // Add frame information.
@@ -124,22 +132,12 @@
       }
       num_frames++;
     }
-    if (!elf->valid()) {
-      break;
-    }
-    if (frame_info->size() == max_frames) {
-      break;
-    }
 
+    if (finished || frame_info->size() == max_frames ||
+        (cur_pc == regs->pc() && cur_sp == regs->sp())) {
+      break;
+    }
     adjust_pc = true;
-    bool finished;
-    if (!elf->Step(rel_pc, step_pc, regs.get(), process_memory_.get(), &finished) || finished) {
-      break;
-    }
-    // pc and sp are the same, terminate the unwind.
-    if (cur_pc == regs->pc() && cur_sp == regs->sp()) {
-      break;
-    }
   }
   return num_frames != 0;
 }
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 28373b2..03658b4 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -161,6 +161,7 @@
   // option is used.
   std::unique_ptr<MemoryRange> memory(new MemoryRange(process_memory, start, end - start, 0));
   if (Elf::IsValidElf(memory.get())) {
+    memory_backed_elf = true;
     return memory.release();
   }
 
@@ -184,6 +185,7 @@
       new MemoryRange(process_memory, prev_map->start, prev_map->end - prev_map->start, 0));
   ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset));
 
+  memory_backed_elf = true;
   return ranges;
 }
 
@@ -237,6 +239,7 @@
     std::lock_guard<std::mutex> guard(prev_map->mutex_);
     if (prev_map->elf.get() == nullptr) {
       prev_map->elf = elf;
+      prev_map->memory_backed_elf = memory_backed_elf;
     }
   }
   return elf.get();
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 73c5a04..26626b5 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -36,38 +36,11 @@
 #include <unwindstack/Unwinder.h>
 
 #if !defined(NO_LIBDEXFILE_SUPPORT)
-#include <DexFile.h>
+#include <unwindstack/DexFiles.h>
 #endif
 
 namespace unwindstack {
 
-Unwinder::Unwinder(size_t max_frames, Maps* maps, Regs* regs,
-                   std::shared_ptr<Memory> process_memory)
-    : max_frames_(max_frames), maps_(maps), regs_(regs), process_memory_(process_memory) {
-  frames_.reserve(max_frames);
-  if (regs != nullptr) {
-    ArchEnum arch = regs_->Arch();
-
-    jit_debug_ = JitDebug<Elf>::Create(arch, process_memory_);
-#if !defined(NO_LIBDEXFILE_SUPPORT)
-    dex_files_ = JitDebug<DexFile>::Create(arch, process_memory_);
-#endif
-  }
-}
-
-void Unwinder::SetRegs(Regs* regs) {
-  regs_ = regs;
-
-  if (jit_debug_ == nullptr) {
-    ArchEnum arch = regs_->Arch();
-
-    jit_debug_ = JitDebug<Elf>::Create(arch, process_memory_);
-#if !defined(NO_LIBDEXFILE_SUPPORT)
-    dex_files_ = JitDebug<DexFile>::Create(arch, process_memory_);
-#endif
-  }
-}
-
 // Inject extra 'virtual' frame that represents the dex pc data.
 // The dex pc is a magic register defined in the Mterp interpreter,
 // and thus it will be restored/observed in the frame after it.
@@ -111,12 +84,13 @@
     return;
   }
 
-  dex_files_->GetFunctionName(maps_, dex_pc, &frame->function_name, &frame->function_offset);
+  dex_files_->GetMethodInformation(maps_, info, dex_pc, &frame->function_name,
+                                   &frame->function_offset);
 #endif
 }
 
-void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t func_pc,
-                           uint64_t pc_adjustment) {
+FrameData* Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc,
+                                 uint64_t pc_adjustment) {
   size_t frame_num = frames_.size();
   frames_.resize(frame_num + 1);
   FrameData* frame = &frames_.at(frame_num);
@@ -126,7 +100,8 @@
   frame->pc = regs_->pc() - pc_adjustment;
 
   if (map_info == nullptr) {
-    return;
+    // Nothing else to update.
+    return nullptr;
   }
 
   if (resolve_names_) {
@@ -144,12 +119,7 @@
   frame->map_end = map_info->end;
   frame->map_flags = map_info->flags;
   frame->map_load_bias = elf->GetLoadBias();
-
-  if (!resolve_names_ ||
-      !elf->GetFunctionName(func_pc, &frame->function_name, &frame->function_offset)) {
-    frame->function_name = "";
-    frame->function_offset = 0;
-  }
+  return frame;
 }
 
 static bool ShouldStop(const std::vector<std::string>* map_suffixes_to_ignore,
@@ -171,6 +141,7 @@
   frames_.clear();
   last_error_.code = ERROR_NONE;
   last_error_.address = 0;
+  elf_from_memory_not_file_ = false;
 
   ArchEnum arch = regs_->Arch();
 
@@ -194,6 +165,12 @@
         break;
       }
       elf = map_info->GetElf(process_memory_, arch);
+      // If this elf is memory backed, and there is a valid file, then set
+      // an indicator that we couldn't open the file.
+      if (!elf_from_memory_not_file_ && map_info->memory_backed_elf && !map_info->name.empty() &&
+          map_info->name[0] != '[') {
+        elf_from_memory_not_file_ = true;
+      }
       step_pc = regs_->pc();
       rel_pc = elf->GetRelPc(step_pc, map_info);
       // Everyone except elf data in gdb jit debug maps uses the relative pc.
@@ -211,7 +188,7 @@
       // using the jit debug information.
       if (!elf->valid() && jit_debug_ != nullptr) {
         uint64_t adjusted_jit_pc = regs_->pc() - pc_adjustment;
-        Elf* jit_elf = jit_debug_->Get(maps_, adjusted_jit_pc);
+        Elf* jit_elf = jit_debug_->GetElf(maps_, adjusted_jit_pc);
         if (jit_elf != nullptr) {
           // The jit debug information requires a non relative adjusted pc.
           step_pc = adjusted_jit_pc;
@@ -220,6 +197,7 @@
       }
     }
 
+    FrameData* frame = nullptr;
     if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
         std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
                   basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) {
@@ -236,23 +214,21 @@
         }
       }
 
-      FillInFrame(map_info, elf, rel_pc, step_pc, pc_adjustment);
+      frame = FillInFrame(map_info, elf, rel_pc, pc_adjustment);
 
       // Once a frame is added, stop skipping frames.
       initial_map_names_to_skip = nullptr;
     }
     adjust_pc = true;
 
-    bool stepped;
+    bool stepped = false;
     bool in_device_map = false;
-    if (map_info == nullptr) {
-      stepped = false;
-    } else {
+    bool finished = false;
+    if (map_info != nullptr) {
       if (map_info->flags & MAPS_FLAGS_DEVICE_MAP) {
         // Do not stop here, fall through in case we are
         // in the speculative unwind path and need to remove
         // some of the speculative frames.
-        stepped = false;
         in_device_map = true;
       } else {
         MapInfo* sp_info = maps_->Find(regs_->sp());
@@ -260,19 +236,37 @@
           // Do not stop here, fall through in case we are
           // in the speculative unwind path and need to remove
           // some of the speculative frames.
-          stepped = false;
           in_device_map = true;
         } else {
-          bool finished;
-          stepped = elf->Step(rel_pc, step_pc, regs_, process_memory_.get(), &finished);
-          elf->GetLastError(&last_error_);
-          if (stepped && finished) {
-            break;
+          if (elf->StepIfSignalHandler(rel_pc, regs_, process_memory_.get())) {
+            stepped = true;
+            if (frame != nullptr) {
+              // Need to adjust the relative pc because the signal handler
+              // pc should not be adjusted.
+              frame->rel_pc = rel_pc;
+              frame->pc += pc_adjustment;
+              step_pc = rel_pc;
+            }
+          } else if (elf->Step(step_pc, regs_, process_memory_.get(), &finished)) {
+            stepped = true;
           }
+          elf->GetLastError(&last_error_);
         }
       }
     }
 
+    if (frame != nullptr) {
+      if (!resolve_names_ ||
+          !elf->GetFunctionName(step_pc, &frame->function_name, &frame->function_offset)) {
+        frame->function_name = "";
+        frame->function_offset = 0;
+      }
+    }
+
+    if (finished) {
+      break;
+    }
+
     if (!stepped) {
       if (return_address_attempt) {
         // Only remove the speculative frame if there are more than two frames
@@ -356,7 +350,19 @@
   return FormatFrame(frames_[frame_num]);
 }
 
-bool UnwinderFromPid::Init() {
+void Unwinder::SetJitDebug(JitDebug* jit_debug, ArchEnum arch) {
+  jit_debug->SetArch(arch);
+  jit_debug_ = jit_debug;
+}
+
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+void Unwinder::SetDexFiles(DexFiles* dex_files, ArchEnum arch) {
+  dex_files->SetArch(arch);
+  dex_files_ = dex_files;
+}
+#endif
+
+bool UnwinderFromPid::Init(ArchEnum arch) {
   if (pid_ == getpid()) {
     maps_ptr_.reset(new LocalMaps());
   } else {
@@ -369,6 +375,15 @@
 
   process_memory_ = Memory::CreateProcessMemoryCached(pid_);
 
+  jit_debug_ptr_.reset(new JitDebug(process_memory_));
+  jit_debug_ = jit_debug_ptr_.get();
+  SetJitDebug(jit_debug_, arch);
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  dex_files_ptr_.reset(new DexFiles(process_memory_));
+  dex_files_ = dex_files_ptr_.get();
+  SetDexFiles(dex_files_, arch);
+#endif
+
   return true;
 }
 
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
new file mode 100644
index 0000000..67a9640
--- /dev/null
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 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 _LIBUNWINDSTACK_DEX_FILES_H
+#define _LIBUNWINDSTACK_DEX_FILES_H
+
+#include <stdint.h>
+
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <unwindstack/Global.h>
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class DexFile;
+class Maps;
+struct MapInfo;
+enum ArchEnum : uint8_t;
+
+class DexFiles : public Global {
+ public:
+  explicit DexFiles(std::shared_ptr<Memory>& memory);
+  DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
+  virtual ~DexFiles();
+
+  DexFile* GetDexFile(uint64_t dex_file_offset, MapInfo* info);
+
+  void GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc, std::string* method_name,
+                            uint64_t* method_offset);
+
+ private:
+  void Init(Maps* maps);
+
+  bool GetAddr(size_t index, uint64_t* addr);
+
+  uint64_t ReadEntryPtr32(uint64_t addr);
+
+  uint64_t ReadEntryPtr64(uint64_t addr);
+
+  bool ReadEntry32();
+
+  bool ReadEntry64();
+
+  bool ReadVariableData(uint64_t ptr_offset) override;
+
+  void ProcessArch() override;
+
+  std::mutex lock_;
+  bool initialized_ = false;
+  std::unordered_map<uint64_t, std::unique_ptr<DexFile>> files_;
+
+  uint64_t entry_addr_ = 0;
+  uint64_t (DexFiles::*read_entry_ptr_func_)(uint64_t) = nullptr;
+  bool (DexFiles::*read_entry_func_)() = nullptr;
+  std::vector<uint64_t> addrs_;
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_DEX_FILES_H
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 25a665d..56bf318 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -67,8 +67,9 @@
 
   uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
 
-  bool Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, Regs* regs, Memory* process_memory,
-            bool* finished);
+  bool StepIfSignalHandler(uint64_t rel_pc, Regs* regs, Memory* process_memory);
+
+  bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
 
   ElfInterface* CreateInterfaceFromMemory(Memory* memory);
 
@@ -78,8 +79,6 @@
 
   bool IsValidPc(uint64_t pc);
 
-  bool GetTextRange(uint64_t* addr, uint64_t* size);
-
   void GetLastError(ErrorData* data);
   ErrorCode GetLastErrorCode();
   uint64_t GetLastErrorAddress();
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 945c277..dbd917d 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -68,8 +68,6 @@
 
   virtual bool IsValidPc(uint64_t pc);
 
-  bool GetTextRange(uint64_t* addr, uint64_t* size);
-
   Memory* CreateGnuDebugdataMemory();
 
   Memory* memory() { return memory_; }
@@ -158,9 +156,6 @@
   uint64_t gnu_build_id_offset_ = 0;
   uint64_t gnu_build_id_size_ = 0;
 
-  uint64_t text_addr_ = 0;
-  uint64_t text_size_ = 0;
-
   uint8_t soname_type_ = SONAME_UNKNOWN;
   std::string soname_;
 
diff --git a/libunwindstack/include/unwindstack/Error.h b/libunwindstack/include/unwindstack/Error.h
index 6ed0e0f..72ec454 100644
--- a/libunwindstack/include/unwindstack/Error.h
+++ b/libunwindstack/include/unwindstack/Error.h
@@ -29,6 +29,7 @@
   ERROR_INVALID_MAP,          // Unwind in an invalid map.
   ERROR_MAX_FRAMES_EXCEEDED,  // The number of frames exceed the total allowed.
   ERROR_REPEATED_FRAME,       // The last frame has the same pc/sp as the next.
+  ERROR_INVALID_ELF,          // Unwind in an invalid elf.
 };
 
 struct ErrorData {
diff --git a/libunwindstack/include/unwindstack/JitDebug.h b/libunwindstack/include/unwindstack/JitDebug.h
index 0c3ded9..8b7b4b5 100644
--- a/libunwindstack/include/unwindstack/JitDebug.h
+++ b/libunwindstack/include/unwindstack/JitDebug.h
@@ -19,7 +19,6 @@
 
 #include <stdint.h>
 
-#include <map>
 #include <memory>
 #include <mutex>
 #include <string>
@@ -31,24 +30,40 @@
 namespace unwindstack {
 
 // Forward declarations.
+class Elf;
 class Maps;
 enum ArchEnum : uint8_t;
 
-template <typename Symfile>
-class JitDebug {
+class JitDebug : public Global {
  public:
-  static std::unique_ptr<JitDebug> Create(ArchEnum arch, std::shared_ptr<Memory>& memory,
-                                          std::vector<std::string> search_libs = {});
-  virtual ~JitDebug() {}
+  explicit JitDebug(std::shared_ptr<Memory>& memory);
+  JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
+  virtual ~JitDebug();
 
-  // Find symbol file for given pc.
-  virtual Symfile* Get(Maps* maps, uint64_t pc) = 0;
+  Elf* GetElf(Maps* maps, uint64_t pc);
 
-  // Find symbol for given pc.
-  bool GetFunctionName(Maps* maps, uint64_t pc, std::string* name, uint64_t* offset) {
-    Symfile* file = Get(maps, pc);
-    return file != nullptr && file->GetFunctionName(pc, name, offset);
-  }
+ private:
+  void Init(Maps* maps);
+
+  uint64_t (JitDebug::*read_descriptor_func_)(uint64_t) = nullptr;
+  uint64_t (JitDebug::*read_entry_func_)(uint64_t*, uint64_t*) = nullptr;
+
+  uint64_t ReadDescriptor32(uint64_t);
+  uint64_t ReadDescriptor64(uint64_t);
+
+  uint64_t ReadEntry32Pack(uint64_t* start, uint64_t* size);
+  uint64_t ReadEntry32Pad(uint64_t* start, uint64_t* size);
+  uint64_t ReadEntry64(uint64_t* start, uint64_t* size);
+
+  bool ReadVariableData(uint64_t ptr_offset) override;
+
+  void ProcessArch() override;
+
+  uint64_t entry_addr_ = 0;
+  bool initialized_ = false;
+  std::vector<Elf*> elf_list_;
+
+  std::mutex lock_;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index e938986..025fd98 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -75,6 +75,9 @@
   // make it easier to move to a fine grained lock in the future.
   std::atomic_uintptr_t build_id;
 
+  // Set to true if the elf file data is coming from memory.
+  bool memory_backed_elf = false;
+
   // This function guarantees it will never return nullptr.
   Elf* GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch);
 
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index a04d7c3..52b3578 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -24,6 +24,7 @@
 #include <string>
 #include <vector>
 
+#include <unwindstack/DexFiles.h>
 #include <unwindstack/Error.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
@@ -33,7 +34,6 @@
 namespace unwindstack {
 
 // Forward declarations.
-class DexFile;
 class Elf;
 enum ArchEnum : uint8_t;
 
@@ -63,14 +63,14 @@
 
 class Unwinder {
  public:
-  Unwinder(size_t max_frames, Maps* maps, Regs* regs, std::shared_ptr<Memory> process_memory);
+  Unwinder(size_t max_frames, Maps* maps, Regs* regs, std::shared_ptr<Memory> process_memory)
+      : max_frames_(max_frames), maps_(maps), regs_(regs), process_memory_(process_memory) {
+    frames_.reserve(max_frames);
+  }
   Unwinder(size_t max_frames, Maps* maps, std::shared_ptr<Memory> process_memory)
-      : Unwinder(max_frames, maps, nullptr, process_memory) {}
-
-  Unwinder(const Unwinder&) = delete;
-  Unwinder& operator=(const Unwinder&) = delete;
-  Unwinder(Unwinder&&) = default;
-  Unwinder& operator=(Unwinder&&) = default;
+      : max_frames_(max_frames), maps_(maps), process_memory_(process_memory) {
+    frames_.reserve(max_frames);
+  }
 
   virtual ~Unwinder() = default;
 
@@ -90,7 +90,9 @@
   std::string FormatFrame(size_t frame_num);
   std::string FormatFrame(const FrameData& frame);
 
-  void SetRegs(Regs* regs);
+  void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
+
+  void SetRegs(Regs* regs) { regs_ = regs; }
   Maps* GetMaps() { return maps_; }
   std::shared_ptr<Memory>& GetProcessMemory() { return process_memory_; }
 
@@ -105,6 +107,12 @@
 
   void SetDisplayBuildID(bool display_build_id) { display_build_id_ = display_build_id; }
 
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
+#endif
+
+  bool elf_from_memory_not_file() { return elf_from_memory_not_file_; }
+
   ErrorCode LastErrorCode() { return last_error_.code; }
   uint64_t LastErrorAddress() { return last_error_.address; }
 
@@ -112,21 +120,23 @@
   Unwinder(size_t max_frames) : max_frames_(max_frames) { frames_.reserve(max_frames); }
 
   void FillInDexFrame();
-  void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t func_pc,
-                   uint64_t pc_adjustment);
+  FrameData* FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t pc_adjustment);
 
   size_t max_frames_;
   Maps* maps_;
   Regs* regs_;
   std::vector<FrameData> frames_;
   std::shared_ptr<Memory> process_memory_;
-  std::unique_ptr<JitDebug<Elf>> jit_debug_;
+  JitDebug* jit_debug_ = nullptr;
 #if !defined(NO_LIBDEXFILE_SUPPORT)
-  std::unique_ptr<JitDebug<DexFile>> dex_files_;
+  DexFiles* dex_files_ = nullptr;
 #endif
   bool resolve_names_ = true;
   bool embedded_soname_ = true;
   bool display_build_id_ = false;
+  // True if at least one elf file is coming from memory and not the related
+  // file. This is only true if there is an actual file backing up the elf.
+  bool elf_from_memory_not_file_ = false;
   ErrorData last_error_;
 };
 
@@ -135,11 +145,15 @@
   UnwinderFromPid(size_t max_frames, pid_t pid) : Unwinder(max_frames), pid_(pid) {}
   virtual ~UnwinderFromPid() = default;
 
-  bool Init();
+  bool Init(ArchEnum arch);
 
  private:
   pid_t pid_;
   std::unique_ptr<Maps> maps_ptr_;
+  std::unique_ptr<JitDebug> jit_debug_ptr_;
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  std::unique_ptr<DexFiles> dex_files_ptr_;
+#endif
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
index df7b31d..0149a42 100644
--- a/libunwindstack/tests/DexFileTest.cpp
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -177,11 +177,11 @@
 
   std::string method;
   uint64_t method_offset;
-  ASSERT_TRUE(dex_file->GetFunctionName(0x4102, &method, &method_offset));
+  ASSERT_TRUE(dex_file->GetMethodInformation(0x102, &method, &method_offset));
   EXPECT_EQ("Main.<init>", method);
   EXPECT_EQ(2U, method_offset);
 
-  ASSERT_TRUE(dex_file->GetFunctionName(0x4118, &method, &method_offset));
+  ASSERT_TRUE(dex_file->GetMethodInformation(0x118, &method, &method_offset));
   EXPECT_EQ("Main.main", method);
   EXPECT_EQ(0U, method_offset);
 }
@@ -195,9 +195,9 @@
 
   std::string method;
   uint64_t method_offset;
-  EXPECT_FALSE(dex_file->GetFunctionName(0x100000, &method, &method_offset));
+  EXPECT_FALSE(dex_file->GetMethodInformation(0x100000, &method, &method_offset));
 
-  EXPECT_FALSE(dex_file->GetFunctionName(0x98, &method, &method_offset));
+  EXPECT_FALSE(dex_file->GetMethodInformation(0x98, &method, &method_offset));
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp
index 655dcc8..1ea9e5c 100644
--- a/libunwindstack/tests/DexFilesTest.cpp
+++ b/libunwindstack/tests/DexFilesTest.cpp
@@ -22,8 +22,8 @@
 
 #include <gtest/gtest.h>
 
+#include <unwindstack/DexFiles.h>
 #include <unwindstack/Elf.h>
-#include <unwindstack/JitDebug.h>
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
@@ -32,10 +32,6 @@
 #include "ElfFake.h"
 #include "MemoryFake.h"
 
-#if !defined(NO_LIBDEXFILE_SUPPORT)
-#include <DexFile.h>
-#endif
-
 namespace unwindstack {
 
 class DexFilesTest : public ::testing::Test {
@@ -52,7 +48,8 @@
   }
 
   void Init(ArchEnum arch) {
-    dex_files_ = JitDebug<DexFile>::Create(arch, process_memory_);
+    dex_files_.reset(new DexFiles(process_memory_));
+    dex_files_->SetArch(arch);
 
     maps_.reset(
         new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n"
@@ -89,11 +86,10 @@
     Init(ARCH_ARM);
   }
 
-  void WriteDescriptor32(uint64_t addr, uint32_t entry);
-  void WriteDescriptor64(uint64_t addr, uint64_t entry);
-  void WriteEntry32Pack(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex);
-  void WriteEntry32Pad(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex);
-  void WriteEntry64(uint64_t addr, uint64_t next, uint64_t prev, uint64_t dex);
+  void WriteDescriptor32(uint64_t addr, uint32_t head);
+  void WriteDescriptor64(uint64_t addr, uint64_t head);
+  void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file);
+  void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file);
   void WriteDex(uint64_t dex_file);
 
   static constexpr size_t kMapGlobalNonReadable = 2;
@@ -105,70 +101,40 @@
 
   std::shared_ptr<Memory> process_memory_;
   MemoryFake* memory_;
-  std::unique_ptr<JitDebug<DexFile>> dex_files_;
+  std::unique_ptr<DexFiles> dex_files_;
   std::unique_ptr<BufferMaps> maps_;
 };
 
-void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t entry) {
-  // Format of the 32 bit JITDescriptor structure:
-  //   uint32_t version
-  memory_->SetData32(addr, 1);
-  //   uint32_t action_flag
-  memory_->SetData32(addr + 4, 0);
-  //   uint32_t relevant_entry
-  memory_->SetData32(addr + 8, 0);
-  //   uint32_t first_entry
-  memory_->SetData32(addr + 12, entry);
+void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t head) {
+  //   void* first_entry_
+  memory_->SetData32(addr + 12, head);
 }
 
-void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t entry) {
-  // Format of the 64 bit JITDescriptor structure:
-  //   uint32_t version
-  memory_->SetData32(addr, 1);
-  //   uint32_t action_flag
-  memory_->SetData32(addr + 4, 0);
-  //   uint64_t relevant_entry
-  memory_->SetData64(addr + 8, 0);
-  //   uint64_t first_entry
-  memory_->SetData64(addr + 16, entry);
+void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t head) {
+  //   void* first_entry_
+  memory_->SetData64(addr + 16, head);
 }
 
-void DexFilesTest::WriteEntry32Pack(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex) {
-  // Format of the 32 bit JITCodeEntry structure:
+void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev,
+                                uint32_t dex_file) {
+  // Format of the 32 bit DEXFileEntry structure:
   //   uint32_t next
-  memory_->SetData32(addr, next);
+  memory_->SetData32(entry_addr, next);
   //   uint32_t prev
-  memory_->SetData32(addr + 4, prev);
-  //   uint32_t dex
-  memory_->SetData32(addr + 8, dex);
-  //   uint64_t symfile_size
-  memory_->SetData64(addr + 12, sizeof(kDexData) * sizeof(uint32_t));
+  memory_->SetData32(entry_addr + 4, prev);
+  //   uint32_t dex_file
+  memory_->SetData32(entry_addr + 8, dex_file);
 }
 
-void DexFilesTest::WriteEntry32Pad(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex) {
-  // Format of the 32 bit JITCodeEntry structure:
-  //   uint32_t next
-  memory_->SetData32(addr, next);
-  //   uint32_t prev
-  memory_->SetData32(addr + 4, prev);
-  //   uint32_t dex
-  memory_->SetData32(addr + 8, dex);
-  //   uint32_t pad
-  memory_->SetData32(addr + 12, 0);
-  //   uint64_t symfile_size
-  memory_->SetData64(addr + 16, sizeof(kDexData) * sizeof(uint32_t));
-}
-
-void DexFilesTest::WriteEntry64(uint64_t addr, uint64_t next, uint64_t prev, uint64_t dex) {
-  // Format of the 64 bit JITCodeEntry structure:
+void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev,
+                                uint64_t dex_file) {
+  // Format of the 64 bit DEXFileEntry structure:
   //   uint64_t next
-  memory_->SetData64(addr, next);
+  memory_->SetData64(entry_addr, next);
   //   uint64_t prev
-  memory_->SetData64(addr + 8, prev);
-  //   uint64_t dex
-  memory_->SetData64(addr + 16, dex);
-  //   uint64_t symfile_size
-  memory_->SetData64(addr + 24, sizeof(kDexData) * sizeof(uint32_t));
+  memory_->SetData64(entry_addr + 8, prev);
+  //   uint64_t dex_file
+  memory_->SetData64(entry_addr + 16, dex_file);
 }
 
 void DexFilesTest::WriteDex(uint64_t dex_file) {
@@ -178,8 +144,9 @@
 TEST_F(DexFilesTest, get_method_information_invalid) {
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFileEntries);
 
-  dex_files_->GetFunctionName(maps_.get(), 0, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset);
   EXPECT_EQ("nothing", method_name);
   EXPECT_EQ(0x124U, method_offset);
 }
@@ -187,12 +154,13 @@
 TEST_F(DexFilesTest, get_method_information_32) {
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   WriteDescriptor32(0xf800, 0x200000);
-  WriteEntry32Pad(0x200000, 0, 0, 0x300000);
+  WriteEntry32(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(0U, method_offset);
 }
@@ -202,12 +170,13 @@
 
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   WriteDescriptor64(0xf800, 0x200000);
   WriteEntry64(0x200000, 0, 0, 0x301000);
   WriteDex(0x301000);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x301102, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(2U, method_offset);
 }
@@ -215,14 +184,14 @@
 TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   WriteDescriptor32(0xf800, 0x200000);
-  WriteEntry32Pad(0x200000, 0x200100, 0, 0x100000);
-  WriteDex(0x100000);
-  WriteEntry32Pad(0x200100, 0, 0x200000, 0x300000);
+  WriteEntry32(0x200000, 0x200100, 0, 0x100000);
+  WriteEntry32(0x200100, 0, 0x200000, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(4U, method_offset);
 }
@@ -232,14 +201,14 @@
 
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   WriteDescriptor64(0xf800, 0x200000);
   WriteEntry64(0x200000, 0x200100, 0, 0x100000);
-  WriteDex(0x100000);
   WriteEntry64(0x200100, 0, 0x200000, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300106, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(6U, method_offset);
 }
@@ -247,18 +216,19 @@
 TEST_F(DexFilesTest, get_method_information_cached) {
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   WriteDescriptor32(0xf800, 0x200000);
-  WriteEntry32Pad(0x200000, 0, 0, 0x300000);
+  WriteEntry32(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(0U, method_offset);
 
   // Clear all memory and make sure that data is acquired from the cache.
   memory_->Clear();
-  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(0U, method_offset);
 }
@@ -266,24 +236,26 @@
 TEST_F(DexFilesTest, get_method_information_search_libs) {
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   WriteDescriptor32(0xf800, 0x200000);
-  WriteEntry32Pad(0x200000, 0x200100, 0, 0x100000);
-  WriteDex(0x100000);
-  WriteEntry32Pad(0x200100, 0, 0x200000, 0x300000);
+  WriteEntry32(0x200000, 0x200100, 0, 0x100000);
+  WriteEntry32(0x200100, 0, 0x200000, 0x300000);
   WriteDex(0x300000);
 
   // Only search a given named list of libs.
   std::vector<std::string> libs{"libart.so"};
-  dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_, libs);
+  dex_files_.reset(new DexFiles(process_memory_, libs));
+  dex_files_->SetArch(ARCH_ARM);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
   EXPECT_EQ("nothing", method_name);
   EXPECT_EQ(0x124U, method_offset);
 
   MapInfo* map_info = maps_->Get(kMapGlobal);
   map_info->name = "/system/lib/libart.so";
-  dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_, libs);
+  dex_files_.reset(new DexFiles(process_memory_, libs));
+  dex_files_->SetArch(ARCH_ARM);
   // Set the rw map to the same name or this will not scan this entry.
   map_info = maps_->Get(kMapGlobalRw);
   map_info->name = "/system/lib/libart.so";
@@ -291,7 +263,7 @@
   // DexFiles object.
   libs.clear();
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(4U, method_offset);
 }
@@ -299,24 +271,26 @@
 TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   // First global variable found, but value is zero.
   WriteDescriptor32(0xa800, 0);
 
   WriteDescriptor32(0xf800, 0x200000);
-  WriteEntry32Pad(0x200000, 0, 0, 0x300000);
+  WriteEntry32(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(0U, method_offset);
 
   // Verify that second is ignored when first is set to non-zero
-  dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_);
+  dex_files_.reset(new DexFiles(process_memory_));
+  dex_files_->SetArch(ARCH_ARM);
   method_name = "fail";
   method_offset = 0x123;
   WriteDescriptor32(0xa800, 0x100000);
-  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("fail", method_name);
   EXPECT_EQ(0x123U, method_offset);
 }
@@ -326,6 +300,7 @@
 
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
+  MapInfo* info = maps_->Get(kMapDexFiles);
 
   // First global variable found, but value is zero.
   WriteDescriptor64(0xa800, 0);
@@ -334,16 +309,17 @@
   WriteEntry64(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(0U, method_offset);
 
   // Verify that second is ignored when first is set to non-zero
-  dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM64, process_memory_);
+  dex_files_.reset(new DexFiles(process_memory_));
+  dex_files_->SetArch(ARCH_ARM64);
   method_name = "fail";
   method_offset = 0x123;
   WriteDescriptor64(0xa800, 0x100000);
-  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
   EXPECT_EQ("fail", method_name);
   EXPECT_EQ(0x123U, method_offset);
 }
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 23c9cf8..c432d6d 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -132,8 +132,12 @@
   uint64_t func_offset;
   ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset));
 
+  ASSERT_FALSE(elf.StepIfSignalHandler(0, nullptr, nullptr));
+  EXPECT_EQ(ERROR_INVALID_ELF, elf.GetLastErrorCode());
+
   bool finished;
-  ASSERT_FALSE(elf.Step(0, 0, nullptr, nullptr, &finished));
+  ASSERT_FALSE(elf.Step(0, nullptr, nullptr, &finished));
+  EXPECT_EQ(ERROR_INVALID_ELF, elf.GetLastErrorCode());
 }
 
 TEST_F(ElfTest, elf32_invalid_machine) {
@@ -295,9 +299,8 @@
   }
 
   elf.FakeSetValid(true);
-  bool finished;
-  ASSERT_TRUE(elf.Step(0x3000, 0x1000, &regs, &process_memory, &finished));
-  EXPECT_FALSE(finished);
+  ASSERT_TRUE(elf.StepIfSignalHandler(0x3000, &regs, &process_memory));
+  EXPECT_EQ(ERROR_NONE, elf.GetLastErrorCode());
   EXPECT_EQ(15U, regs.pc());
   EXPECT_EQ(13U, regs.sp());
 }
@@ -336,7 +339,7 @@
   EXPECT_CALL(*interface, Step(0x1000, &regs, &process_memory, &finished))
       .WillOnce(::testing::Return(true));
 
-  ASSERT_TRUE(elf.Step(0x1004, 0x1000, &regs, &process_memory, &finished));
+  ASSERT_TRUE(elf.Step(0x1000, &regs, &process_memory, &finished));
 }
 
 TEST_F(ElfTest, get_global_invalid_elf) {
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index 438194a..b1ca111 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -46,7 +46,8 @@
   }
 
   void Init(ArchEnum arch) {
-    jit_debug_ = JitDebug<Elf>::Create(arch, process_memory_);
+    jit_debug_.reset(new JitDebug(process_memory_));
+    jit_debug_->SetArch(arch);
 
     maps_.reset(
         new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf1\n"
@@ -61,12 +62,6 @@
                        "200000-210000 rw-p 0002000 00:00 0 /fake/elf4\n"));
     ASSERT_TRUE(maps_->Parse());
 
-    // Ensure all memory of the ELF file is initialized,
-    // otherwise reads within it may fail.
-    for (uint64_t addr = 0x4000; addr < 0x6000; addr += 8) {
-      memory_->SetData64(addr, 0);
-    }
-
     MapInfo* map_info = maps_->Get(3);
     ASSERT_TRUE(map_info != nullptr);
     CreateFakeElf(map_info);
@@ -99,7 +94,7 @@
     ehdr.e_shstrndx = 1;
     ehdr.e_shoff = sh_offset;
     ehdr.e_shentsize = sizeof(ShdrType);
-    ehdr.e_shnum = 4;
+    ehdr.e_shnum = 3;
     memory_->SetMemory(offset, &ehdr, sizeof(ehdr));
 
     ShdrType shdr;
@@ -115,7 +110,6 @@
     shdr.sh_size = 0x100;
     memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
     memory_->SetMemory(offset + 0x500, ".debug_frame");
-    memory_->SetMemory(offset + 0x550, ".text");
 
     sh_offset += sizeof(shdr);
     memset(&shdr, 0, sizeof(shdr));
@@ -126,15 +120,6 @@
     shdr.sh_size = 0x200;
     memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
 
-    sh_offset += sizeof(shdr);
-    memset(&shdr, 0, sizeof(shdr));
-    shdr.sh_type = SHT_NOBITS;
-    shdr.sh_name = 0x50;
-    shdr.sh_addr = pc;
-    shdr.sh_offset = 0;
-    shdr.sh_size = size;
-    memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
-
     // Now add a single cie/fde.
     uint64_t dwarf_offset = offset + 0x600;
     if (class_type == ELFCLASS32) {
@@ -183,7 +168,7 @@
 
   std::shared_ptr<Memory> process_memory_;
   MemoryFake* memory_;
-  std::unique_ptr<JitDebug<Elf>> jit_debug_;
+  std::unique_ptr<JitDebug> jit_debug_;
   std::unique_ptr<BufferMaps> maps_;
 };
 
@@ -253,20 +238,20 @@
 }
 
 TEST_F(JitDebugTest, get_elf_invalid) {
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
 TEST_F(JitDebugTest, get_elf_no_global_variable) {
   maps_.reset(new BufferMaps(""));
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
 TEST_F(JitDebugTest, get_elf_no_valid_descriptor_in_memory) {
   CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
 
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
@@ -275,7 +260,7 @@
 
   WriteDescriptor32(0xf800, 0x200000);
 
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
@@ -284,7 +269,7 @@
 
   WriteDescriptor32(0xf800, 0);
 
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
@@ -295,7 +280,7 @@
   // Set the version to an invalid value.
   memory_->SetData32(0xf800, 2);
 
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
@@ -305,18 +290,12 @@
   WriteDescriptor32(0xf800, 0x200000);
   WriteEntry32Pad(0x200000, 0, 0, 0x4000, 0x1000);
 
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf != nullptr);
-  uint64_t text_addr;
-  uint64_t text_size;
-  ASSERT_TRUE(elf->GetTextRange(&text_addr, &text_size));
-  ASSERT_EQ(text_addr, 0x1500u);
-  ASSERT_EQ(text_size, 0x200u);
 
   // Clear the memory and verify all of the data is cached.
   memory_->Clear();
-  WriteDescriptor32(0xf800, 0x200000);
-  Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf2 != nullptr);
   EXPECT_EQ(elf, elf2);
 }
@@ -330,15 +309,16 @@
   WriteDescriptor32(0x12800, 0x201000);
   WriteEntry32Pad(0x201000, 0, 0, 0x5000, 0x1000);
 
-  ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) != nullptr);
-  ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x2000) == nullptr);
+  ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr);
+  ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) == nullptr);
 
   // Now clear the descriptor entry for the first one.
   WriteDescriptor32(0xf800, 0);
-  jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_);
+  jit_debug_.reset(new JitDebug(process_memory_));
+  jit_debug_->SetArch(ARCH_ARM);
 
-  ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) == nullptr);
-  ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x2000) != nullptr);
+  ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) == nullptr);
+  ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) != nullptr);
 }
 
 TEST_F(JitDebugTest, get_elf_x86) {
@@ -349,14 +329,13 @@
   WriteDescriptor32(0xf800, 0x200000);
   WriteEntry32Pack(0x200000, 0, 0, 0x4000, 0x1000);
 
-  jit_debug_ = JitDebug<Elf>::Create(ARCH_X86, process_memory_);
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  jit_debug_->SetArch(ARCH_X86);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf != nullptr);
 
   // Clear the memory and verify all of the data is cached.
   memory_->Clear();
-  WriteDescriptor32(0xf800, 0x200000);
-  Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf2 != nullptr);
   EXPECT_EQ(elf, elf2);
 }
@@ -369,13 +348,12 @@
   WriteDescriptor64(0xf800, 0x200000);
   WriteEntry64(0x200000, 0, 0, 0x4000, 0x1000);
 
-  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf != nullptr);
 
   // Clear the memory and verify all of the data is cached.
   memory_->Clear();
-  WriteDescriptor64(0xf800, 0x200000);
-  Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500);
+  Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500);
   ASSERT_TRUE(elf2 != nullptr);
   EXPECT_EQ(elf, elf2);
 }
@@ -388,21 +366,20 @@
   WriteEntry32Pad(0x200000, 0, 0x200100, 0x4000, 0x1000);
   WriteEntry32Pad(0x200100, 0x200100, 0, 0x5000, 0x1000);
 
-  Elf* elf_2 = jit_debug_->Get(maps_.get(), 0x2400);
+  Elf* elf_2 = jit_debug_->GetElf(maps_.get(), 0x2400);
   ASSERT_TRUE(elf_2 != nullptr);
 
-  Elf* elf_1 = jit_debug_->Get(maps_.get(), 0x1600);
+  Elf* elf_1 = jit_debug_->GetElf(maps_.get(), 0x1600);
   ASSERT_TRUE(elf_1 != nullptr);
 
   // Clear the memory and verify all of the data is cached.
   memory_->Clear();
-  WriteDescriptor32(0xf800, 0x200000);
-  EXPECT_EQ(elf_1, jit_debug_->Get(maps_.get(), 0x1500));
-  EXPECT_EQ(elf_1, jit_debug_->Get(maps_.get(), 0x16ff));
-  EXPECT_EQ(elf_2, jit_debug_->Get(maps_.get(), 0x2300));
-  EXPECT_EQ(elf_2, jit_debug_->Get(maps_.get(), 0x26ff));
-  EXPECT_EQ(nullptr, jit_debug_->Get(maps_.get(), 0x1700));
-  EXPECT_EQ(nullptr, jit_debug_->Get(maps_.get(), 0x2700));
+  EXPECT_EQ(elf_1, jit_debug_->GetElf(maps_.get(), 0x1500));
+  EXPECT_EQ(elf_1, jit_debug_->GetElf(maps_.get(), 0x16ff));
+  EXPECT_EQ(elf_2, jit_debug_->GetElf(maps_.get(), 0x2300));
+  EXPECT_EQ(elf_2, jit_debug_->GetElf(maps_.get(), 0x26ff));
+  EXPECT_EQ(nullptr, jit_debug_->GetElf(maps_.get(), 0x1700));
+  EXPECT_EQ(nullptr, jit_debug_->GetElf(maps_.get(), 0x2700));
 }
 
 TEST_F(JitDebugTest, get_elf_search_libs) {
@@ -413,19 +390,21 @@
 
   // Only search a given named list of libs.
   std::vector<std::string> libs{"libart.so"};
-  jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_, libs);
-  EXPECT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) == nullptr);
+  jit_debug_.reset(new JitDebug(process_memory_, libs));
+  jit_debug_->SetArch(ARCH_ARM);
+  EXPECT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) == nullptr);
 
   // Change the name of the map that includes the value and verify this works.
   MapInfo* map_info = maps_->Get(5);
   map_info->name = "/system/lib/libart.so";
   map_info = maps_->Get(6);
   map_info->name = "/system/lib/libart.so";
-  jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_);
+  jit_debug_.reset(new JitDebug(process_memory_, libs));
   // Make sure that clearing our copy of the libs doesn't affect the
   // JitDebug object.
   libs.clear();
-  EXPECT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) != nullptr);
+  jit_debug_->SetArch(ARCH_ARM);
+  EXPECT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr);
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 2ddadef..6be8bdc 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -108,6 +108,7 @@
   info.end = 0x101;
   memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
 }
 
 // Verify that if the offset is non-zero but there is no elf at the offset,
@@ -117,6 +118,7 @@
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0x100U, info.elf_offset);
   EXPECT_EQ(0x100U, info.elf_start_offset);
 
@@ -140,32 +142,40 @@
   // offset to zero.
   info.elf_offset = 0;
   info.elf_start_offset = 0;
+  info.memory_backed_elf = false;
   memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0x100U, info.elf_offset);
   EXPECT_EQ(0x100U, info.elf_start_offset);
 
   prev_info.offset = 0;
   info.elf_offset = 0;
   info.elf_start_offset = 0;
+  info.memory_backed_elf = false;
   memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0x100U, info.elf_offset);
   EXPECT_EQ(0x100U, info.elf_start_offset);
 
   prev_info.flags = PROT_READ;
   info.elf_offset = 0;
   info.elf_start_offset = 0;
+  info.memory_backed_elf = false;
   memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0x100U, info.elf_offset);
   EXPECT_EQ(0x100U, info.elf_start_offset);
 
   prev_info.name = info.name;
   info.elf_offset = 0;
   info.elf_start_offset = 0;
+  info.memory_backed_elf = false;
   memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0x100U, info.elf_offset);
   EXPECT_EQ(0U, info.elf_start_offset);
 }
@@ -177,6 +187,7 @@
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0U, info.elf_offset);
   EXPECT_EQ(0x1000U, info.elf_start_offset);
 
@@ -201,6 +212,7 @@
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0U, info.elf_offset);
   EXPECT_EQ(0x1000U, info.elf_start_offset);
 
@@ -218,6 +230,7 @@
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0U, info.elf_offset);
   EXPECT_EQ(0x2000U, info.elf_start_offset);
 
@@ -259,6 +272,7 @@
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_TRUE(info.memory_backed_elf);
 
   memset(buffer.data(), 0, buffer.size());
   ASSERT_TRUE(memory->ReadFully(0, buffer.data(), buffer.size()));
@@ -290,6 +304,7 @@
 
   std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
   ASSERT_TRUE(mem.get() != nullptr);
+  EXPECT_TRUE(map_info->memory_backed_elf);
   EXPECT_EQ(0x4000UL, map_info->elf_offset);
   EXPECT_EQ(0x4000UL, map_info->offset);
   EXPECT_EQ(0U, map_info->elf_start_offset);
@@ -336,6 +351,7 @@
 
   std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
   ASSERT_TRUE(mem.get() != nullptr);
+  EXPECT_TRUE(map_info->memory_backed_elf);
   EXPECT_EQ(0x1000UL, map_info->elf_offset);
   EXPECT_EQ(0xb000UL, map_info->offset);
   EXPECT_EQ(0xa000UL, map_info->elf_start_offset);
@@ -374,6 +390,7 @@
   // extend over the executable segment.
   std::unique_ptr<Memory> memory(map_info->CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(map_info->memory_backed_elf);
   std::vector<uint8_t> buffer(0x100);
   EXPECT_EQ(0x2000U, map_info->offset);
   EXPECT_EQ(0U, map_info->elf_offset);
@@ -388,7 +405,9 @@
   ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET));
   ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr)));
 
+  map_info->memory_backed_elf = false;
   memory.reset(map_info->CreateMemory(process_memory_));
+  EXPECT_FALSE(map_info->memory_backed_elf);
   EXPECT_EQ(0x2000U, map_info->offset);
   EXPECT_EQ(0x1000U, map_info->elf_offset);
   EXPECT_EQ(0x1000U, map_info->elf_start_offset);
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index e3c646a..6c64c40 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -307,7 +307,9 @@
   }
   process_memory_.reset(memory);
 
+  JitDebug jit_debug(process_memory_);
   Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.SetJitDebug(&jit_debug, regs_->Arch());
   unwinder.Unwind();
 
   std::string frame_info(DumpFrames(unwinder));
@@ -607,7 +609,9 @@
   }
   process_memory_.reset(memory);
 
+  JitDebug jit_debug(process_memory_);
   Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.SetJitDebug(&jit_debug, regs_->Arch());
   unwinder.Unwind();
 
   std::string frame_info(DumpFrames(unwinder));
@@ -928,7 +932,9 @@
   LeakType* leak_data = reinterpret_cast<LeakType*>(data);
 
   std::unique_ptr<Regs> regs_copy(leak_data->regs->Clone());
+  JitDebug jit_debug(leak_data->process_memory);
   Unwinder unwinder(128, leak_data->maps, regs_copy.get(), leak_data->process_memory);
+  unwinder.SetJitDebug(&jit_debug, regs_copy->Arch());
   unwinder.Unwind();
   ASSERT_EQ(76U, unwinder.NumFrames());
 }
@@ -1049,7 +1055,9 @@
   }
   process_memory_.reset(memory);
 
+  JitDebug jit_debug(process_memory_);
   Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.SetJitDebug(&jit_debug, regs_->Arch());
   unwinder.Unwind();
 
   std::string frame_info(DumpFrames(unwinder));
@@ -1207,7 +1215,7 @@
       "  #02 pc 0032bff3  libunwindstack_test (SignalOuterFunction+2)\n"
       "  #03 pc 0032fed3  libunwindstack_test "
       "(unwindstack::SignalCallerHandler(int, siginfo*, void*)+26)\n"
-      "  #04 pc 00026528  libc.so\n"
+      "  #04 pc 0002652c  libc.so (__restore)\n"
       "  #05 pc 00000000  <unknown>\n"
       "  #06 pc 0032c2d9  libunwindstack_test (InnerFunction+736)\n"
       "  #07 pc 0032cc4f  libunwindstack_test (MiddleFunction+42)\n"
@@ -1235,7 +1243,7 @@
   EXPECT_EQ(0xf43d2ce8U, unwinder.frames()[2].sp);
   EXPECT_EQ(0x2e59ed3U, unwinder.frames()[3].pc);
   EXPECT_EQ(0xf43d2cf0U, unwinder.frames()[3].sp);
-  EXPECT_EQ(0xf4136528U, unwinder.frames()[4].pc);
+  EXPECT_EQ(0xf413652cU, unwinder.frames()[4].pc);
   EXPECT_EQ(0xf43d2d10U, unwinder.frames()[4].sp);
   EXPECT_EQ(0U, unwinder.frames()[5].pc);
   EXPECT_EQ(0xffcc0ee0U, unwinder.frames()[5].sp);
@@ -1318,7 +1326,7 @@
       "  #00 pc 000000000014ccbc  linker64 (__dl_syscall+28)\n"
       "  #01 pc 000000000005426c  linker64 "
       "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
-      "  #02 pc 00000000000008bc  vdso.so\n"
+      "  #02 pc 00000000000008c0  vdso.so (__kernel_rt_sigreturn)\n"
       "  #03 pc 00000000000846f4  libc.so (abort+172)\n"
       "  #04 pc 0000000000084ad4  libc.so (__assert2+36)\n"
       "  #05 pc 000000000003d5b4  ANGLEPrebuilt.apk!libfeature_support_angle.so (offset 0x4000) "
@@ -1330,7 +1338,7 @@
   EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp);
   EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc);
   EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp);
-  EXPECT_EQ(0x7e82b018bcULL, unwinder.frames()[2].pc);
+  EXPECT_EQ(0x7e82b018c0ULL, unwinder.frames()[2].pc);
   EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp);
   EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc);
   EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp);
@@ -1358,7 +1366,7 @@
       "  #00 pc 000000000014ccbc  linker64 (__dl_syscall+28)\n"
       "  #01 pc 000000000005426c  linker64 "
       "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
-      "  #02 pc 00000000000008bc  vdso.so\n"
+      "  #02 pc 00000000000008c0  vdso.so (__kernel_rt_sigreturn)\n"
       "  #03 pc 00000000000846f4  libc.so (abort+172)\n"
       "  #04 pc 0000000000084ad4  libc.so (__assert2+36)\n"
       "  #05 pc 000000000003d5b4  ANGLEPrebuilt.apk (offset 0x21d5000)\n"
@@ -1369,7 +1377,7 @@
   EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp);
   EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc);
   EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp);
-  EXPECT_EQ(0x7e82b018bcULL, unwinder.frames()[2].pc);
+  EXPECT_EQ(0x7e82b018c0ULL, unwinder.frames()[2].pc);
   EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp);
   EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc);
   EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp);
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 5e7e6bf..4e38015 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -170,7 +170,7 @@
     unwinder.reset(new Unwinder(512, maps.get(), regs.get(), process_memory));
   } else {
     UnwinderFromPid* unwinder_from_pid = new UnwinderFromPid(512, getpid());
-    ASSERT_TRUE(unwinder_from_pid->Init());
+    ASSERT_TRUE(unwinder_from_pid->Init(regs->Arch()));
     unwinder_from_pid->SetRegs(regs.get());
     unwinder.reset(unwinder_from_pid);
   }
@@ -283,7 +283,7 @@
   ASSERT_TRUE(regs.get() != nullptr);
 
   UnwinderFromPid unwinder(512, pid);
-  ASSERT_TRUE(unwinder.Init());
+  ASSERT_TRUE(unwinder.Init(regs->Arch()));
   unwinder.SetRegs(regs.get());
 
   VerifyUnwind(&unwinder, kFunctionOrder);
@@ -335,7 +335,7 @@
   ASSERT_TRUE(regs.get() != nullptr);
 
   UnwinderFromPid unwinder(512, *pid);
-  ASSERT_TRUE(unwinder.Init());
+  ASSERT_TRUE(unwinder.Init(regs->Arch()));
   unwinder.SetRegs(regs.get());
 
   VerifyUnwind(&unwinder, kFunctionOrder);
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 48e038e..f635021 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -108,6 +108,24 @@
     const auto& info2 = *--maps_->end();
     info2->elf_offset = 0x8000;
 
+    elf = new ElfFake(new MemoryFake);
+    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    AddMapInfo(0xc0000, 0xc1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/unreadable.so", elf);
+    const auto& info3 = *--maps_->end();
+    info3->memory_backed_elf = true;
+
+    elf = new ElfFake(new MemoryFake);
+    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    AddMapInfo(0xc1000, 0xc2000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "[vdso]", elf);
+    const auto& info4 = *--maps_->end();
+    info4->memory_backed_elf = true;
+
+    elf = new ElfFake(new MemoryFake);
+    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    AddMapInfo(0xc2000, 0xc3000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "", elf);
+    const auto& info5 = *--maps_->end();
+    info5->memory_backed_elf = true;
+
     process_memory_.reset(new MemoryFake);
   }
 
@@ -140,6 +158,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -204,6 +223,7 @@
   unwinder.SetResolveNames(false);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -263,6 +283,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -292,6 +313,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -321,6 +343,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -351,6 +374,7 @@
   unwinder.SetEmbeddedSoname(false);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -387,6 +411,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -419,6 +444,7 @@
   Unwinder unwinder(20, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(20U, unwinder.NumFrames());
 
@@ -461,6 +487,7 @@
   std::vector<std::string> skip_libs{"libunwind.so", "libanother.so"};
   unwinder.Unwind(&skip_libs);
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -522,6 +549,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -569,6 +597,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 }
@@ -588,6 +617,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 }
@@ -602,6 +632,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -638,6 +669,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -703,6 +735,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -752,6 +785,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -799,6 +833,7 @@
   std::vector<std::string> skip_names{"libanother.so"};
   unwinder.Unwind(&skip_names);
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(0U, unwinder.NumFrames());
 }
@@ -821,6 +856,7 @@
   std::vector<std::string> suffixes{"oat"};
   unwinder.Unwind(nullptr, &suffixes);
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
   // Make sure the elf was not initialized.
@@ -879,6 +915,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -937,6 +974,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -980,6 +1018,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -1026,6 +1065,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -1084,6 +1124,7 @@
   Unwinder unwinder(1, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -1103,6 +1144,96 @@
   EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
 }
 
+TEST_F(UnwinderTest, elf_from_memory_not_file) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+  regs_.set_pc(0xc0050);
+  regs_.set_sp(0x10000);
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_TRUE(unwinder.elf_from_memory_not_file());
+
+  ASSERT_EQ(1U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x50U, frame->rel_pc);
+  EXPECT_EQ(0xc0050U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("/fake/unreadable.so", frame->map_name);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
+  EXPECT_EQ(0xc0000U, frame->map_start);
+  EXPECT_EQ(0xc1000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
+TEST_F(UnwinderTest, elf_from_memory_but_no_valid_file_with_bracket) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+  regs_.set_pc(0xc1050);
+  regs_.set_sp(0x10000);
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
+
+  ASSERT_EQ(1U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x50U, frame->rel_pc);
+  EXPECT_EQ(0xc1050U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("[vdso]", frame->map_name);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
+  EXPECT_EQ(0xc1000U, frame->map_start);
+  EXPECT_EQ(0xc2000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
+TEST_F(UnwinderTest, elf_from_memory_but_empty_filename) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+  regs_.set_pc(0xc2050);
+  regs_.set_sp(0x10000);
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
+
+  ASSERT_EQ(1U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x50U, frame->rel_pc);
+  EXPECT_EQ(0xc2050U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("", frame->map_name);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
+  EXPECT_EQ(0xc2000U, frame->map_start);
+  EXPECT_EQ(0xc3000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
 // Verify format frame code.
 TEST_F(UnwinderTest, format_frame) {
   RegsFake regs_arm(10);
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index cad95f8..1812e50 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <unwindstack/DexFiles.h>
 #include <unwindstack/Elf.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
@@ -89,7 +90,7 @@
   printf("\n");
 
   unwindstack::UnwinderFromPid unwinder(1024, pid);
-  if (!unwinder.Init()) {
+  if (!unwinder.Init(regs->Arch())) {
     printf("Failed to init unwinder object.\n");
     return;
   }
diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp
index 86f3163..4f67d67 100644
--- a/libunwindstack/tools/unwind_for_offline.cpp
+++ b/libunwindstack/tools/unwind_for_offline.cpp
@@ -248,7 +248,7 @@
   // Do an unwind so we know how much of the stack to save, and what
   // elf files are involved.
   unwindstack::UnwinderFromPid unwinder(1024, pid);
-  if (!unwinder.Init()) {
+  if (!unwinder.Init(regs->Arch())) {
     printf("Unable to init unwinder object.\n");
     return 1;
   }
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index 7324ba9..bd63275 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -97,7 +97,6 @@
 namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
 
 namespace.media.links = default
-namespace.media.link.default.shared_libs  = libandroid.so
 namespace.media.link.default.shared_libs += libbinder_ndk.so
 namespace.media.link.default.shared_libs += libc.so
 namespace.media.link.default.shared_libs += libcgrouprc.so
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 45e80e1..91a4373 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -177,7 +177,6 @@
 
 namespace.media.links = default
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libandroid.so
 namespace.media.link.default.shared_libs += libbinder_ndk.so
 namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -620,7 +619,6 @@
 
 namespace.media.links = default
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libandroid.so
 namespace.media.link.default.shared_libs += libbinder_ndk.so
 namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index a762ba8..11729ee 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -119,7 +119,6 @@
 
 namespace.media.links = default
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libandroid.so
 namespace.media.link.default.shared_libs += libbinder_ndk.so
 namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -443,7 +442,6 @@
 
 namespace.media.links = default
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libandroid.so
 namespace.media.link.default.shared_libs += libbinder_ndk.so
 namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
diff --git a/rootdir/init.rc b/rootdir/init.rc
index b274cf3..17dd145 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -13,9 +13,6 @@
 
 # Cgroups are mounted right before early-init using list from /etc/cgroups.json
 on early-init
-    # Set init and its forked children's oom_adj.
-    write /proc/1/oom_score_adj -1000
-
     # Disable sysrq from keyboard
     write /proc/sys/kernel/sysrq 0