Merge changes from topic "libprocessgroup_rc"

* changes:
  CgroupSetupCgroups -> CgroupSetup
  Add libcgrouprc to ld.config.*.txt.
  libprocessgroup: use libcgrouprc to read cgroup.rc
  libprocessgroup_setup: use libcgrouprc_format
  libprocessgroup: Move CgroupSetupCgroups() to libprocessgroup_setup
  libprocessgroup: Add libcgrouprc
  libprocessgroup: Add libcgrouprc_format
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index 381ded4..5c0da47 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -557,9 +557,7 @@
 }
 
 void usb_reset(usb_handle* handle) {
-    if (!handle->dead) {
-        (*handle->interface)->USBDeviceReEnumerate(handle->interface, 0);
-    }
+    // Unimplemented on OS X.
     usb_kick(handle);
 }
 
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 82ba0a1..437450c 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -48,7 +48,6 @@
 #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>
@@ -567,7 +566,7 @@
 
   // TODO: Use seccomp to lock ourselves down.
   unwindstack::UnwinderFromPid unwinder(256, vm_pid);
-  if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
+  if (!unwinder.Init()) {
     LOG(FATAL) << "Failed to init unwinder object.";
   }
 
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index bbec612..5f7ebc3 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -42,7 +42,6 @@
 #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>
@@ -81,12 +80,12 @@
     thread.pid = getpid();
     thread.tid = gettid();
     thread.thread_name = get_thread_name(gettid());
-    unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch();
-    thread.registers.reset(unwindstack::Regs::CreateFromUcontext(arch, ucontext));
+    thread.registers.reset(
+        unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
 
     // TODO: Create this once and store it in a global?
     unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid());
-    if (unwinder.Init(arch)) {
+    if (unwinder.Init()) {
       dump_backtrace_thread(output_fd, &unwinder, thread);
     } else {
       async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Unable to init unwinder.");
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 47a7a8f..4bdb9c8 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -44,7 +44,6 @@
 #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>
@@ -650,7 +649,7 @@
   };
 
   unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid);
-  if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
+  if (!unwinder.Init()) {
     LOG(FATAL) << "Failed to init unwinder object.";
   }
 
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index c09dc3d..c22176b 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -1026,7 +1026,7 @@
 elif [ -z "${ANDROID_HOST_OUT}" ]; then
   echo "${ORANGE}[  WARNING ]${NORMAL} please run lunch, skipping"
 else
-  adb reboot-fastboot ||
+  adb reboot fastboot ||
     die "fastbootd not supported (wrong adb in path?)"
   any_wait 2m &&
     inFastboot ||
@@ -1136,7 +1136,7 @@
 
   echo "${GREEN}[ RUN      ]${NORMAL} test fastboot flash to ${scratch_partition} recovery" >&2
 
-  adb reboot-fastboot ||
+  adb reboot fastboot ||
     die "Reboot into fastbootd"
   img=${TMPDIR}/adb-remount-test-${$}.img
   cleanup() {
diff --git a/init/devices.cpp b/init/devices.cpp
index 1a77ba1..159c75e 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -21,8 +21,14 @@
 #include <sys/sysmacros.h>
 #include <unistd.h>
 
+#include <chrono>
+#include <map>
 #include <memory>
+#include <string>
+#include <thread>
 
+#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
@@ -37,12 +43,16 @@
 #error "Do not include init.h in files used by ueventd; it will expose init's globals"
 #endif
 
+using namespace std::chrono_literals;
+
 using android::base::Basename;
 using android::base::Dirname;
+using android::base::ReadFileToString;
 using android::base::Readlink;
 using android::base::Realpath;
 using android::base::StartsWith;
 using android::base::StringPrintf;
+using android::base::Trim;
 
 namespace android {
 namespace init {
@@ -101,6 +111,31 @@
     return true;
 }
 
+// Given a path that may start with a virtual dm block device, populate
+// the supplied buffer with the dm module's instantiated name.
+// If it doesn't start with a virtual block device, or there is some
+// error, return false.
+static bool FindDmDevicePartition(const std::string& path, std::string* result) {
+    result->clear();
+    if (!StartsWith(path, "/devices/virtual/block/dm-")) return false;
+    if (getpid() == 1) return false;  // first_stage_init has no sepolicy needs
+
+    static std::map<std::string, std::string> cache;
+    // wait_for_file will not work, the content is also delayed ...
+    for (android::base::Timer t; t.duration() < 200ms; std::this_thread::sleep_for(10ms)) {
+        if (ReadFileToString("/sys" + path + "/dm/name", result) && !result->empty()) {
+            // Got it, set cache with result, when node arrives
+            cache[path] = *result = Trim(*result);
+            return true;
+        }
+    }
+    auto it = cache.find(path);
+    if ((it == cache.end()) || (it->second.empty())) return false;
+    // Return cached results, when node goes away
+    *result = it->second;
+    return true;
+}
+
 Permissions::Permissions(const std::string& name, mode_t perm, uid_t uid, gid_t gid)
     : name_(name), perm_(perm), uid_(uid), gid_(gid), prefix_(false), wildcard_(false) {
     // Set 'prefix_' or 'wildcard_' based on the below cases:
@@ -293,6 +328,7 @@
 std::vector<std::string> DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uevent) const {
     std::string device;
     std::string type;
+    std::string partition;
 
     if (FindPlatformDevice(uevent.path, &device)) {
         // Skip /devices/platform or /devices/ if present
@@ -310,6 +346,8 @@
         type = "pci";
     } else if (FindVbdDevicePrefix(uevent.path, &device)) {
         type = "vbd";
+    } else if (FindDmDevicePartition(uevent.path, &partition)) {
+        return {"/dev/block/mapper/" + partition};
     } else {
         return {};
     }
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index f5f9b2a..ff19833 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -32,9 +32,6 @@
 #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"
@@ -50,14 +47,6 @@
                                  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()) {
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 4518891..726fdfa 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -43,13 +43,6 @@
   // 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 e19b605..9bb9709 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -27,9 +27,6 @@
 
 #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>
@@ -53,12 +50,6 @@
 
   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:
@@ -66,11 +57,6 @@
 
   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/libcutils/android_reboot.cpp b/libcutils/android_reboot.cpp
index ce41cd3..e0def71 100644
--- a/libcutils/android_reboot.cpp
+++ b/libcutils/android_reboot.cpp
@@ -23,12 +23,12 @@
 
 #define TAG "android_reboot"
 
-int android_reboot(int cmd, int /*flags*/, const char* arg) {
+int android_reboot(unsigned cmd, int /*flags*/, const char* arg) {
     int ret;
     const char* restart_cmd = NULL;
     char* prop_value;
 
-    switch (static_cast<unsigned>(cmd)) {
+    switch (cmd) {
         case ANDROID_RB_RESTART:  // deprecated
         case ANDROID_RB_RESTART2:
             restart_cmd = "reboot";
diff --git a/libcutils/include/cutils/android_reboot.h b/libcutils/include/cutils/android_reboot.h
index 99030ed..cd27eef 100644
--- a/libcutils/include/cutils/android_reboot.h
+++ b/libcutils/include/cutils/android_reboot.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef __CUTILS_ANDROID_REBOOT_H__
-#define __CUTILS_ANDROID_REBOOT_H__
+#pragma once
 
 #include <sys/cdefs.h>
 
@@ -36,10 +35,8 @@
 /* Reboot or shutdown the system.
  * This call uses ANDROID_RB_PROPERTY to request reboot to init process.
  * Due to that, process calling this should have proper selinux permission
- * to write to the property. Otherwise, the call will fail.
+ * to write to the property or the call will fail.
  */
-int android_reboot(int cmd, int flags, const char *arg);
+int android_reboot(unsigned cmd, int flags, const char* arg);
 
 __END_DECLS
-
-#endif /* __CUTILS_ANDROID_REBOOT_H__ */
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index b7650a1..ce25108 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -49,7 +49,6 @@
     srcs: [
         "ArmExidx.cpp",
         "DexFile.cpp",
-        "DexFiles.cpp",
         "DwarfCfa.cpp",
         "DwarfEhFrameWithHdr.cpp",
         "DwarfMemory.cpp",
@@ -92,7 +91,6 @@
             cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
             exclude_srcs: [
                 "DexFile.cpp",
-                "DexFiles.cpp",
             ],
             exclude_shared_libs: [
                 "libdexfile_support",
@@ -102,7 +100,6 @@
             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 eaf867f..d8d5a24 100644
--- a/libunwindstack/DexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -35,22 +35,31 @@
 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 =
+    std::unique_ptr<DexFile> dex_file_from_file =
         DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name);
-    if (dex_file) {
-      return dex_file;
+    if (dex_file_from_file) {
+      dex_file_from_file->addr_ = dex_file_offset_in_memory;
+      return dex_file_from_file;
     }
   }
-  return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name);
+  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;
 }
 
-bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
-                                   uint64_t* method_offset) {
+bool DexFile::GetFunctionName(uint64_t dex_pc, std::string* method_name, uint64_t* method_offset) {
+  uint64_t dex_offset = dex_pc - addr_;
   art_api::dex::MethodInfo method_info = GetMethodInfoForOffset(dex_offset, false);
   if (method_info.offset == 0) {
     return false;
   }
-  *method_name = method_info.name;
+  if (method_name != nullptr) {
+    *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 ca658e6..1448a4b 100644
--- a/libunwindstack/DexFile.h
+++ b/libunwindstack/DexFile.h
@@ -29,17 +29,22 @@
 
 namespace unwindstack {
 
+class Memory;
+struct MapInfo;
+
 class DexFile : protected art_api::dex::DexFile {
  public:
   virtual ~DexFile() = default;
 
-  bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
+  bool GetFunctionName(uint64_t dex_pc, 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
deleted file mode 100644
index 63a77e5..0000000
--- a/libunwindstack/DexFiles.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * 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 4b93abb..5b402ed 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -243,6 +243,24 @@
   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 12efb94..e09a2ae 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -69,6 +69,15 @@
   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;
@@ -330,29 +339,26 @@
       }
       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 && sec_size != 0) {
+    } else if (shdr.sh_type == SHT_PROGBITS || shdr.sh_type == SHT_NOBITS) {
       // 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") {
-            offset_ptr = &debug_frame_offset_;
-            size_ptr = &debug_frame_size_;
+            debug_frame_offset_ = shdr.sh_offset;
+            debug_frame_size_ = shdr.sh_size;
           } else if (name == ".gnu_debugdata") {
-            offset_ptr = &gnu_debugdata_offset_;
-            size_ptr = &gnu_debugdata_size_;
+            gnu_debugdata_offset_ = shdr.sh_offset;
+            gnu_debugdata_size_ = shdr.sh_size;
           } else if (name == ".eh_frame") {
-            offset_ptr = &eh_frame_offset_;
-            size_ptr = &eh_frame_size_;
+            eh_frame_offset_ = shdr.sh_offset;
+            eh_frame_size_ = shdr.sh_size;
           } else if (eh_frame_hdr_offset_ == 0 && name == ".eh_frame_hdr") {
-            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;
+            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;
           }
         }
       }
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp
index 20bc4b9..71665a1 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -16,8 +16,13 @@
 
 #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>
@@ -25,197 +30,334 @@
 #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 {
 
-struct JITCodeEntry32Pack {
-  uint32_t next;
-  uint32_t prev;
-  uint32_t symfile_addr;
-  uint64_t symfile_size;
+// 32-bit platforms may differ in alignment of uint64_t.
+struct Uint64_P {
+  uint64_t value;
 } __attribute__((packed));
+struct Uint64_A {
+  uint64_t value;
+} __attribute__((aligned(8)));
 
-struct JITCodeEntry32Pad {
-  uint32_t next;
-  uint32_t prev;
-  uint32_t symfile_addr;
-  uint32_t pad;
-  uint64_t symfile_size;
+// 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 JITCodeEntry64 {
-  uint64_t next;
-  uint64_t prev;
-  uint64_t symfile_addr;
-  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 JITDescriptorHeader {
-  uint32_t version;
-  uint32_t action_flag;
+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 JITCodeEntry {
+    PointerT next;
+    PointerT prev;
+    PointerT symfile_addr;
+    Uint64_T symfile_size;
+  };
+
+  struct JITDescriptor {
+    uint32_t version;
+    uint32_t action_flag;
+    PointerT relevant_entry;
+    PointerT 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;
+  };
+
+  JitDebugImpl(ArchEnum arch, std::shared_ptr<Memory>& memory,
+               std::vector<std::string>& search_libs)
+      : Global(memory, search_libs) {
+    SetArch(arch);
+  }
+
+  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);
+
+  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.
+
+  std::deque<JitCacheEntry<Symfile>> entries_;
+
+  std::mutex lock_;
 };
 
-struct JITDescriptor32 {
-  JITDescriptorHeader header;
-  uint32_t relevant_entry;
-  uint32_t first_entry;
-};
-
-struct JITDescriptor64 {
-  JITDescriptorHeader header;
-  uint64_t relevant_entry;
-  uint64_t first_entry;
-};
-
-JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : Global(memory) {}
-
-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;
-  }
-
-  if (desc.header.version != 1 || desc.first_entry == 0) {
-    // Either unknown version, or no jit entries.
-    return 0;
-  }
-
-  return desc.first_entry;
-}
-
-uint64_t JitDebug::ReadDescriptor64(uint64_t addr) {
-  JITDescriptor64 desc;
-  if (!memory_->ReadFully(addr, &desc, sizeof(desc))) {
-    return 0;
-  }
-
-  if (desc.header.version != 1 || desc.first_entry == 0) {
-    // Either unknown version, or no jit entries.
-    return 0;
-  }
-
-  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()) {
+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) {
     case ARCH_X86:
-      read_descriptor_func_ = &JitDebug::ReadDescriptor32;
-      read_entry_func_ = &JitDebug::ReadEntry32Pack;
+      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));
       break;
-
     case ARCH_ARM:
     case ARCH_MIPS:
-      read_descriptor_func_ = &JitDebug::ReadDescriptor32;
-      read_entry_func_ = &JitDebug::ReadEntry32Pad;
+      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));
       break;
-
     case ARCH_ARM64:
     case ARCH_X86_64:
     case ARCH_MIPS64:
-      read_descriptor_func_ = &JitDebug::ReadDescriptor64;
-      read_entry_func_ = &JitDebug::ReadEntry64;
+      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));
       break;
-    case ARCH_UNKNOWN:
+    default:
       abort();
   }
 }
 
-bool JitDebug::ReadVariableData(uint64_t ptr) {
-  entry_addr_ = (this->*read_descriptor_func_)(ptr);
-  return entry_addr_ != 0;
-}
-
-void JitDebug::Init(Maps* maps) {
-  if (initialized_) {
-    return;
+size_t JitMemory::Read(uint64_t addr, void* dst, size_t size) {
+  if (!parent_->ReadFully(addr, dst, size)) {
+    return 0;
   }
-  // Regardless of what happens below, consider the init finished.
-  initialized_ = true;
-
-  FindAndReadVariable(maps, "__jit_debug_descriptor");
+  // 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;
 }
 
-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.
+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;
+  }
+  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;
+}
+
+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) {
   std::lock_guard<std::mutex> guard(lock_);
   if (!initialized_) {
-    Init(maps);
+    FindAndReadVariable(maps, GetDescriptorName<Symfile>());
+    initialized_ = true;
   }
 
-  // Search the existing elf object first.
-  for (Elf* elf : elf_list_) {
-    if (elf->IsValidPc(pc)) {
-      return elf;
-    }
+  if (descriptor_addr_ == 0) {
+    return nullptr;
   }
 
-  while (entry_addr_ != 0) {
-    uint64_t start;
-    uint64_t size;
-    entry_addr_ = (this->*read_entry_func_)(&start, &size);
+  if (!Update(maps)) {
+    return nullptr;
+  }
 
-    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;
+  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 nullptr;
+  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;
+    }
+  }
+
+  return true;
+}
+
+// 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;
+  }
+
+  // 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;
+}
+
+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/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 3f2e1c1..73c5a04 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -36,11 +36,38 @@
 #include <unwindstack/Unwinder.h>
 
 #if !defined(NO_LIBDEXFILE_SUPPORT)
-#include <unwindstack/DexFiles.h>
+#include <DexFile.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.
@@ -84,8 +111,7 @@
     return;
   }
 
-  dex_files_->GetMethodInformation(maps_, info, dex_pc, &frame->function_name,
-                                   &frame->function_offset);
+  dex_files_->GetFunctionName(maps_, dex_pc, &frame->function_name, &frame->function_offset);
 #endif
 }
 
@@ -185,7 +211,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_->GetElf(maps_, adjusted_jit_pc);
+        Elf* jit_elf = jit_debug_->Get(maps_, adjusted_jit_pc);
         if (jit_elf != nullptr) {
           // The jit debug information requires a non relative adjusted pc.
           step_pc = adjusted_jit_pc;
@@ -330,19 +356,7 @@
   return FormatFrame(frames_[frame_num]);
 }
 
-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) {
+bool UnwinderFromPid::Init() {
   if (pid_ == getpid()) {
     maps_ptr_.reset(new LocalMaps());
   } else {
@@ -355,15 +369,6 @@
 
   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
deleted file mode 100644
index 67a9640..0000000
--- a/libunwindstack/include/unwindstack/DexFiles.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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 ac94f10..25a665d 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -78,6 +78,8 @@
 
   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 dbd917d..945c277 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -68,6 +68,8 @@
 
   virtual bool IsValidPc(uint64_t pc);
 
+  bool GetTextRange(uint64_t* addr, uint64_t* size);
+
   Memory* CreateGnuDebugdataMemory();
 
   Memory* memory() { return memory_; }
@@ -156,6 +158,9 @@
   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/JitDebug.h b/libunwindstack/include/unwindstack/JitDebug.h
index 8b7b4b5..0c3ded9 100644
--- a/libunwindstack/include/unwindstack/JitDebug.h
+++ b/libunwindstack/include/unwindstack/JitDebug.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 
+#include <map>
 #include <memory>
 #include <mutex>
 #include <string>
@@ -30,40 +31,24 @@
 namespace unwindstack {
 
 // Forward declarations.
-class Elf;
 class Maps;
 enum ArchEnum : uint8_t;
 
-class JitDebug : public Global {
+template <typename Symfile>
+class JitDebug {
  public:
-  explicit JitDebug(std::shared_ptr<Memory>& memory);
-  JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
-  virtual ~JitDebug();
+  static std::unique_ptr<JitDebug> Create(ArchEnum arch, std::shared_ptr<Memory>& memory,
+                                          std::vector<std::string> search_libs = {});
+  virtual ~JitDebug() {}
 
-  Elf* GetElf(Maps* maps, uint64_t pc);
+  // Find symbol file for given pc.
+  virtual Symfile* Get(Maps* maps, uint64_t pc) = 0;
 
- 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_;
+  // 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);
+  }
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 8b01654..a04d7c3 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -24,7 +24,6 @@
 #include <string>
 #include <vector>
 
-#include <unwindstack/DexFiles.h>
 #include <unwindstack/Error.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
@@ -34,6 +33,7 @@
 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)
-      : max_frames_(max_frames), maps_(maps), regs_(regs), process_memory_(process_memory) {
-    frames_.reserve(max_frames);
-  }
+  Unwinder(size_t max_frames, Maps* maps, Regs* regs, std::shared_ptr<Memory> process_memory);
   Unwinder(size_t max_frames, Maps* maps, std::shared_ptr<Memory> process_memory)
-      : max_frames_(max_frames), maps_(maps), process_memory_(process_memory) {
-    frames_.reserve(max_frames);
-  }
+      : Unwinder(max_frames, maps, nullptr, process_memory) {}
+
+  Unwinder(const Unwinder&) = delete;
+  Unwinder& operator=(const Unwinder&) = delete;
+  Unwinder(Unwinder&&) = default;
+  Unwinder& operator=(Unwinder&&) = default;
 
   virtual ~Unwinder() = default;
 
@@ -90,9 +90,7 @@
   std::string FormatFrame(size_t frame_num);
   std::string FormatFrame(const FrameData& frame);
 
-  void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
-
-  void SetRegs(Regs* regs) { regs_ = regs; }
+  void SetRegs(Regs* regs);
   Maps* GetMaps() { return maps_; }
   std::shared_ptr<Memory>& GetProcessMemory() { return process_memory_; }
 
@@ -107,10 +105,6 @@
 
   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
-
   ErrorCode LastErrorCode() { return last_error_.code; }
   uint64_t LastErrorAddress() { return last_error_.address; }
 
@@ -126,9 +120,9 @@
   Regs* regs_;
   std::vector<FrameData> frames_;
   std::shared_ptr<Memory> process_memory_;
-  JitDebug* jit_debug_ = nullptr;
+  std::unique_ptr<JitDebug<Elf>> jit_debug_;
 #if !defined(NO_LIBDEXFILE_SUPPORT)
-  DexFiles* dex_files_ = nullptr;
+  std::unique_ptr<JitDebug<DexFile>> dex_files_;
 #endif
   bool resolve_names_ = true;
   bool embedded_soname_ = true;
@@ -141,15 +135,11 @@
   UnwinderFromPid(size_t max_frames, pid_t pid) : Unwinder(max_frames), pid_(pid) {}
   virtual ~UnwinderFromPid() = default;
 
-  bool Init(ArchEnum arch);
+  bool Init();
 
  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 0149a42..df7b31d 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->GetMethodInformation(0x102, &method, &method_offset));
+  ASSERT_TRUE(dex_file->GetFunctionName(0x4102, &method, &method_offset));
   EXPECT_EQ("Main.<init>", method);
   EXPECT_EQ(2U, method_offset);
 
-  ASSERT_TRUE(dex_file->GetMethodInformation(0x118, &method, &method_offset));
+  ASSERT_TRUE(dex_file->GetFunctionName(0x4118, &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->GetMethodInformation(0x100000, &method, &method_offset));
+  EXPECT_FALSE(dex_file->GetFunctionName(0x100000, &method, &method_offset));
 
-  EXPECT_FALSE(dex_file->GetMethodInformation(0x98, &method, &method_offset));
+  EXPECT_FALSE(dex_file->GetFunctionName(0x98, &method, &method_offset));
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp
index 1ea9e5c..655dcc8 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,6 +32,10 @@
 #include "ElfFake.h"
 #include "MemoryFake.h"
 
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <DexFile.h>
+#endif
+
 namespace unwindstack {
 
 class DexFilesTest : public ::testing::Test {
@@ -48,8 +52,7 @@
   }
 
   void Init(ArchEnum arch) {
-    dex_files_.reset(new DexFiles(process_memory_));
-    dex_files_->SetArch(arch);
+    dex_files_ = JitDebug<DexFile>::Create(arch, process_memory_);
 
     maps_.reset(
         new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n"
@@ -86,10 +89,11 @@
     Init(ARCH_ARM);
   }
 
-  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 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 WriteDex(uint64_t dex_file);
 
   static constexpr size_t kMapGlobalNonReadable = 2;
@@ -101,40 +105,70 @@
 
   std::shared_ptr<Memory> process_memory_;
   MemoryFake* memory_;
-  std::unique_ptr<DexFiles> dex_files_;
+  std::unique_ptr<JitDebug<DexFile>> dex_files_;
   std::unique_ptr<BufferMaps> maps_;
 };
 
-void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t head) {
-  //   void* first_entry_
-  memory_->SetData32(addr + 12, head);
+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::WriteDescriptor64(uint64_t addr, uint64_t head) {
-  //   void* first_entry_
-  memory_->SetData64(addr + 16, 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::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev,
-                                uint32_t dex_file) {
-  // Format of the 32 bit DEXFileEntry structure:
+void DexFilesTest::WriteEntry32Pack(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex) {
+  // Format of the 32 bit JITCodeEntry structure:
   //   uint32_t next
-  memory_->SetData32(entry_addr, next);
+  memory_->SetData32(addr, next);
   //   uint32_t prev
-  memory_->SetData32(entry_addr + 4, prev);
-  //   uint32_t dex_file
-  memory_->SetData32(entry_addr + 8, dex_file);
+  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));
 }
 
-void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev,
-                                uint64_t dex_file) {
-  // Format of the 64 bit DEXFileEntry structure:
+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:
   //   uint64_t next
-  memory_->SetData64(entry_addr, next);
+  memory_->SetData64(addr, next);
   //   uint64_t prev
-  memory_->SetData64(entry_addr + 8, prev);
-  //   uint64_t dex_file
-  memory_->SetData64(entry_addr + 16, dex_file);
+  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));
 }
 
 void DexFilesTest::WriteDex(uint64_t dex_file) {
@@ -144,9 +178,8 @@
 TEST_F(DexFilesTest, get_method_information_invalid) {
   std::string method_name = "nothing";
   uint64_t method_offset = 0x124;
-  MapInfo* info = maps_->Get(kMapDexFileEntries);
 
-  dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset);
+  dex_files_->GetFunctionName(maps_.get(), 0, &method_name, &method_offset);
   EXPECT_EQ("nothing", method_name);
   EXPECT_EQ(0x124U, method_offset);
 }
@@ -154,13 +187,12 @@
 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);
-  WriteEntry32(0x200000, 0, 0, 0x300000);
+  WriteEntry32Pad(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(0U, method_offset);
 }
@@ -170,13 +202,12 @@
 
   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_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset);
+  dex_files_->GetFunctionName(maps_.get(), 0x301102, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(2U, method_offset);
 }
@@ -184,14 +215,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);
-  WriteEntry32(0x200000, 0x200100, 0, 0x100000);
-  WriteEntry32(0x200100, 0, 0x200000, 0x300000);
+  WriteEntry32Pad(0x200000, 0x200100, 0, 0x100000);
+  WriteDex(0x100000);
+  WriteEntry32Pad(0x200100, 0, 0x200000, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
+  dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(4U, method_offset);
 }
@@ -201,14 +232,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_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset);
+  dex_files_->GetFunctionName(maps_.get(), 0x300106, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(6U, method_offset);
 }
@@ -216,19 +247,18 @@
 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);
-  WriteEntry32(0x200000, 0, 0, 0x300000);
+  WriteEntry32Pad(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  dex_files_->GetFunctionName(maps_.get(), 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_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(0U, method_offset);
 }
@@ -236,26 +266,24 @@
 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);
-  WriteEntry32(0x200000, 0x200100, 0, 0x100000);
-  WriteEntry32(0x200100, 0, 0x200000, 0x300000);
+  WriteEntry32Pad(0x200000, 0x200100, 0, 0x100000);
+  WriteDex(0x100000);
+  WriteEntry32Pad(0x200100, 0, 0x200000, 0x300000);
   WriteDex(0x300000);
 
   // Only search a given named list of libs.
   std::vector<std::string> libs{"libart.so"};
-  dex_files_.reset(new DexFiles(process_memory_, libs));
-  dex_files_->SetArch(ARCH_ARM);
+  dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_, libs);
 
-  dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
+  dex_files_->GetFunctionName(maps_.get(), 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_.reset(new DexFiles(process_memory_, libs));
-  dex_files_->SetArch(ARCH_ARM);
+  dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_, libs);
   // 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";
@@ -263,7 +291,7 @@
   // DexFiles object.
   libs.clear();
 
-  dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
+  dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
   EXPECT_EQ("Main.<init>", method_name);
   EXPECT_EQ(4U, method_offset);
 }
@@ -271,26 +299,24 @@
 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);
-  WriteEntry32(0x200000, 0, 0, 0x300000);
+  WriteEntry32Pad(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  dex_files_->GetFunctionName(maps_.get(), 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_.reset(new DexFiles(process_memory_));
-  dex_files_->SetArch(ARCH_ARM);
+  dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_);
   method_name = "fail";
   method_offset = 0x123;
   WriteDescriptor32(0xa800, 0x100000);
-  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
   EXPECT_EQ("fail", method_name);
   EXPECT_EQ(0x123U, method_offset);
 }
@@ -300,7 +326,6 @@
 
   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);
@@ -309,17 +334,16 @@
   WriteEntry64(0x200000, 0, 0, 0x300000);
   WriteDex(0x300000);
 
-  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  dex_files_->GetFunctionName(maps_.get(), 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_.reset(new DexFiles(process_memory_));
-  dex_files_->SetArch(ARCH_ARM64);
+  dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM64, process_memory_);
   method_name = "fail";
   method_offset = 0x123;
   WriteDescriptor64(0xa800, 0x100000);
-  dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+  dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
   EXPECT_EQ("fail", method_name);
   EXPECT_EQ(0x123U, method_offset);
 }
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index b1ca111..438194a 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -46,8 +46,7 @@
   }
 
   void Init(ArchEnum arch) {
-    jit_debug_.reset(new JitDebug(process_memory_));
-    jit_debug_->SetArch(arch);
+    jit_debug_ = JitDebug<Elf>::Create(arch, process_memory_);
 
     maps_.reset(
         new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf1\n"
@@ -62,6 +61,12 @@
                        "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);
@@ -94,7 +99,7 @@
     ehdr.e_shstrndx = 1;
     ehdr.e_shoff = sh_offset;
     ehdr.e_shentsize = sizeof(ShdrType);
-    ehdr.e_shnum = 3;
+    ehdr.e_shnum = 4;
     memory_->SetMemory(offset, &ehdr, sizeof(ehdr));
 
     ShdrType shdr;
@@ -110,6 +115,7 @@
     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));
@@ -120,6 +126,15 @@
     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) {
@@ -168,7 +183,7 @@
 
   std::shared_ptr<Memory> process_memory_;
   MemoryFake* memory_;
-  std::unique_ptr<JitDebug> jit_debug_;
+  std::unique_ptr<JitDebug<Elf>> jit_debug_;
   std::unique_ptr<BufferMaps> maps_;
 };
 
@@ -238,20 +253,20 @@
 }
 
 TEST_F(JitDebugTest, get_elf_invalid) {
-  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
 TEST_F(JitDebugTest, get_elf_no_global_variable) {
   maps_.reset(new BufferMaps(""));
-  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->Get(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_->GetElf(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
@@ -260,7 +275,7 @@
 
   WriteDescriptor32(0xf800, 0x200000);
 
-  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
@@ -269,7 +284,7 @@
 
   WriteDescriptor32(0xf800, 0);
 
-  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
@@ -280,7 +295,7 @@
   // Set the version to an invalid value.
   memory_->SetData32(0xf800, 2);
 
-  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
   ASSERT_TRUE(elf == nullptr);
 }
 
@@ -290,12 +305,18 @@
   WriteDescriptor32(0xf800, 0x200000);
   WriteEntry32Pad(0x200000, 0, 0, 0x4000, 0x1000);
 
-  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->Get(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();
-  Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500);
+  WriteDescriptor32(0xf800, 0x200000);
+  Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500);
   ASSERT_TRUE(elf2 != nullptr);
   EXPECT_EQ(elf, elf2);
 }
@@ -309,16 +330,15 @@
   WriteDescriptor32(0x12800, 0x201000);
   WriteEntry32Pad(0x201000, 0, 0, 0x5000, 0x1000);
 
-  ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr);
-  ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) == nullptr);
+  ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) != nullptr);
+  ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x2000) == nullptr);
 
   // Now clear the descriptor entry for the first one.
   WriteDescriptor32(0xf800, 0);
-  jit_debug_.reset(new JitDebug(process_memory_));
-  jit_debug_->SetArch(ARCH_ARM);
+  jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_);
 
-  ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) == nullptr);
-  ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) != nullptr);
+  ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) == nullptr);
+  ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x2000) != nullptr);
 }
 
 TEST_F(JitDebugTest, get_elf_x86) {
@@ -329,13 +349,14 @@
   WriteDescriptor32(0xf800, 0x200000);
   WriteEntry32Pack(0x200000, 0, 0, 0x4000, 0x1000);
 
-  jit_debug_->SetArch(ARCH_X86);
-  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
+  jit_debug_ = JitDebug<Elf>::Create(ARCH_X86, process_memory_);
+  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
   ASSERT_TRUE(elf != nullptr);
 
   // Clear the memory and verify all of the data is cached.
   memory_->Clear();
-  Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500);
+  WriteDescriptor32(0xf800, 0x200000);
+  Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500);
   ASSERT_TRUE(elf2 != nullptr);
   EXPECT_EQ(elf, elf2);
 }
@@ -348,12 +369,13 @@
   WriteDescriptor64(0xf800, 0x200000);
   WriteEntry64(0x200000, 0, 0, 0x4000, 0x1000);
 
-  Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
+  Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
   ASSERT_TRUE(elf != nullptr);
 
   // Clear the memory and verify all of the data is cached.
   memory_->Clear();
-  Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500);
+  WriteDescriptor64(0xf800, 0x200000);
+  Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500);
   ASSERT_TRUE(elf2 != nullptr);
   EXPECT_EQ(elf, elf2);
 }
@@ -366,20 +388,21 @@
   WriteEntry32Pad(0x200000, 0, 0x200100, 0x4000, 0x1000);
   WriteEntry32Pad(0x200100, 0x200100, 0, 0x5000, 0x1000);
 
-  Elf* elf_2 = jit_debug_->GetElf(maps_.get(), 0x2400);
+  Elf* elf_2 = jit_debug_->Get(maps_.get(), 0x2400);
   ASSERT_TRUE(elf_2 != nullptr);
 
-  Elf* elf_1 = jit_debug_->GetElf(maps_.get(), 0x1600);
+  Elf* elf_1 = jit_debug_->Get(maps_.get(), 0x1600);
   ASSERT_TRUE(elf_1 != nullptr);
 
   // Clear the memory and verify all of the data is cached.
   memory_->Clear();
-  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));
+  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));
 }
 
 TEST_F(JitDebugTest, get_elf_search_libs) {
@@ -390,21 +413,19 @@
 
   // Only search a given named list of libs.
   std::vector<std::string> libs{"libart.so"};
-  jit_debug_.reset(new JitDebug(process_memory_, libs));
-  jit_debug_->SetArch(ARCH_ARM);
-  EXPECT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) == nullptr);
+  jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_, libs);
+  EXPECT_TRUE(jit_debug_->Get(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_.reset(new JitDebug(process_memory_, libs));
+  jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_);
   // Make sure that clearing our copy of the libs doesn't affect the
   // JitDebug object.
   libs.clear();
-  jit_debug_->SetArch(ARCH_ARM);
-  EXPECT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr);
+  EXPECT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) != nullptr);
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 655579e..0867561 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -290,9 +290,7 @@
   }
   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));
@@ -592,9 +590,7 @@
   }
   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));
@@ -915,9 +911,7 @@
   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());
 }
@@ -1038,9 +1032,7 @@
   }
   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));
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 4e38015..5e7e6bf 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(regs->Arch()));
+    ASSERT_TRUE(unwinder_from_pid->Init());
     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(regs->Arch()));
+  ASSERT_TRUE(unwinder.Init());
   unwinder.SetRegs(regs.get());
 
   VerifyUnwind(&unwinder, kFunctionOrder);
@@ -335,7 +335,7 @@
   ASSERT_TRUE(regs.get() != nullptr);
 
   UnwinderFromPid unwinder(512, *pid);
-  ASSERT_TRUE(unwinder.Init(regs->Arch()));
+  ASSERT_TRUE(unwinder.Init());
   unwinder.SetRegs(regs.get());
 
   VerifyUnwind(&unwinder, kFunctionOrder);
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 1812e50..cad95f8 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -26,7 +26,6 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <unwindstack/DexFiles.h>
 #include <unwindstack/Elf.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
@@ -90,7 +89,7 @@
   printf("\n");
 
   unwindstack::UnwinderFromPid unwinder(1024, pid);
-  if (!unwinder.Init(regs->Arch())) {
+  if (!unwinder.Init()) {
     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 4f67d67..86f3163 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(regs->Arch())) {
+  if (!unwinder.Init()) {
     printf("Unable to init unwinder object.\n");
     return 1;
   }