Merge "Move dex pc frame creation into libunwindstack." am: c146c8f5c1 am: d790cad91d
am: 953e5da0ba

Change-Id: I630ab2f717fb7617a1228bbd86d2a48e16c5534a
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 14ae445..10a4e46 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -50,7 +50,6 @@
     "BacktracePtrace.cpp",
     "thread_utils.c",
     "ThreadEntry.cpp",
-    "UnwindDexFile.cpp",
     "UnwindStack.cpp",
     "UnwindStackMap.cpp",
 ]
@@ -110,10 +109,9 @@
             static_libs: ["libasync_safe"],
         },
         vendor: {
-            cflags: ["-DNO_LIBDEXFILE"],
-            exclude_srcs: ["UnwindDexFile.cpp"],
+            cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
             exclude_shared_libs: ["libdexfile"],
-        },
+        }
     },
     whole_static_libs: ["libdemangle"],
 }
@@ -145,8 +143,6 @@
         "backtrace_test.cpp",
         "GetPss.cpp",
         "thread_utils.c",
-
-        "unwind_dex_test.cpp",
     ],
 
     cflags: [
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 158467e..7e2e6d0 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -36,70 +36,15 @@
 #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"
-#ifndef NO_LIBDEXFILE
-#include "UnwindDexFile.h"
-#endif
 #include "UnwindStack.h"
 #include "UnwindStackMap.h"
 
-static void FillInDexFrame(UnwindStackMap* stack_map, uint64_t dex_pc,
-                           backtrace_frame_data_t* frame) {
-  // The DEX PC points into the .dex section within an ELF file.
-  // However, this is a BBS section manually mmaped to a .vdex file,
-  // so we need to get the following map to find the ELF data.
-  unwindstack::Maps* maps = stack_map->stack_maps();
-  auto it = maps->begin();
-  uint64_t rel_dex_pc;
-  unwindstack::MapInfo* info;
-  for (; it != maps->end(); ++it) {
-    auto entry = *it;
-    if (dex_pc >= entry->start && dex_pc < entry->end) {
-      info = entry;
-      rel_dex_pc = dex_pc - entry->start;
-      frame->map.start = entry->start;
-      frame->map.end = entry->end;
-      frame->map.offset = entry->offset;
-      frame->map.load_bias = entry->load_bias;
-      frame->map.flags = entry->flags;
-      frame->map.name = entry->name;
-      frame->rel_pc = rel_dex_pc;
-      break;
-    }
-  }
-  if (it == maps->end() || ++it == maps->end()) {
-    return;
-  }
-
-  auto entry = *it;
-  auto process_memory = stack_map->process_memory();
-  unwindstack::Elf* elf = entry->GetElf(process_memory, true);
-  if (!elf->valid()) {
-    return;
-  }
-
-  // Adjust the relative dex by the offset.
-  rel_dex_pc += entry->elf_offset;
-
-  uint64_t dex_offset;
-  if (!elf->GetFunctionName(rel_dex_pc, &frame->func_name, &dex_offset)) {
-    return;
-  }
-  frame->func_offset = dex_offset;
-  if (frame->func_name != "$dexfile") {
-    return;
-  }
-
-#ifndef NO_LIBDEXFILE
-  UnwindDexFile* dex_file = stack_map->GetDexFile(dex_pc - dex_offset, info);
-  if (dex_file != nullptr) {
-    dex_file->GetMethodInformation(dex_offset, &frame->func_name, &frame->func_offset);
-  }
-#endif
-}
-
 bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
                        std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
                        std::vector<std::string>* skip_names, BacktraceUnwindError* error) {
@@ -110,6 +55,11 @@
   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()) {
@@ -150,36 +100,11 @@
   }
 
   auto unwinder_frames = unwinder.frames();
-  // Get the real number of frames we'll need.
-  size_t total_frames = 0;
-  for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++, total_frames++) {
-    if (unwinder_frames[i].dex_pc != 0) {
-      total_frames++;
-    }
-  }
-  frames->resize(total_frames);
+  frames->resize(unwinder.NumFrames() - num_ignore_frames);
   size_t cur_frame = 0;
   for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++) {
     auto frame = &unwinder_frames[i];
 
-    // Inject extra 'virtual' frame that represents the dex pc data.
-    // The dex pc is magic register defined in the Mterp interpreter,
-    // and thus it will be restored/observed in the frame after it.
-    // Adding the dex frame first here will create something like:
-    //   #7 pc 006b1ba1 libartd.so  ExecuteMterpImpl+14625
-    //   #8 pc 0015fa20 core.vdex   java.util.Arrays.binarySearch+8
-    //   #9 pc 0039a1ef libartd.so  art::interpreter::Execute+719
-    if (frame->dex_pc != 0) {
-      backtrace_frame_data_t* dex_frame = &frames->at(cur_frame);
-      dex_frame->num = cur_frame++;
-      dex_frame->pc = frame->dex_pc;
-      dex_frame->rel_pc = frame->dex_pc;
-      dex_frame->sp = frame->sp;
-      dex_frame->stack_size = 0;
-      dex_frame->func_offset = 0;
-      FillInDexFrame(stack_map, frame->dex_pc, dex_frame);
-    }
-
     backtrace_frame_data_t* back_frame = &frames->at(cur_frame);
 
     back_frame->num = cur_frame++;
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 97f8d78..1622e30 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -26,20 +26,11 @@
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Maps.h>
 
-#include "UnwindDexFile.h"
 #include "UnwindStackMap.h"
 
 //-------------------------------------------------------------------------
 UnwindStackMap::UnwindStackMap(pid_t pid) : BacktraceMap(pid) {}
 
-UnwindStackMap::~UnwindStackMap() {
-#ifndef NO_LIBDEXFILE
-  for (auto& entry : dex_files_) {
-    delete entry.second;
-  }
-#endif
-}
-
 bool UnwindStackMap::Build() {
   if (pid_ == 0) {
     pid_ = getpid();
@@ -54,6 +45,9 @@
   // 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_));
+#endif
 
   if (!stack_maps_->Parse()) {
     return false;
@@ -127,26 +121,6 @@
   return process_memory_;
 }
 
-#ifdef NO_LIBDEXFILE
-UnwindDexFile* UnwindStackMap::GetDexFile(uint64_t, unwindstack::MapInfo*) {
-  return nullptr;
-}
-#else
-UnwindDexFile* UnwindStackMap::GetDexFile(uint64_t dex_file_offset, unwindstack::MapInfo* info) {
-  // Lock while we get the data.
-  std::lock_guard<std::mutex> guard(dex_lock_);
-  UnwindDexFile* dex_file;
-  auto entry = dex_files_.find(dex_file_offset);
-  if (entry == dex_files_.end()) {
-    dex_file = UnwindDexFile::Create(dex_file_offset, process_memory_.get(), info);
-    dex_files_[dex_file_offset] = dex_file;
-  } else {
-    dex_file = entry->second;
-  }
-  return dex_file;
-}
-#endif
-
 UnwindStackOfflineMap::UnwindStackOfflineMap(pid_t pid) : UnwindStackMap(pid) {}
 
 bool UnwindStackOfflineMap::Build() {
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index be5c59e..94cbfb2 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/JitDebug.h>
 #include <unwindstack/Maps.h>
 
@@ -36,7 +39,7 @@
 class UnwindStackMap : public BacktraceMap {
  public:
   explicit UnwindStackMap(pid_t pid);
-  ~UnwindStackMap();
+  ~UnwindStackMap() = default;
 
   bool Build() override;
 
@@ -51,7 +54,9 @@
 
   unwindstack::JitDebug* GetJitDebug() { return jit_debug_.get(); }
 
-  UnwindDexFile* GetDexFile(uint64_t dex_file_offset, unwindstack::MapInfo* info);
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  unwindstack::DexFiles* GetDexFiles() { return dex_files_.get(); }
+#endif
 
  protected:
   uint64_t GetLoadBias(size_t index) override;
@@ -59,9 +64,8 @@
   std::unique_ptr<unwindstack::Maps> stack_maps_;
   std::shared_ptr<unwindstack::Memory> process_memory_;
   std::unique_ptr<unwindstack::JitDebug> jit_debug_;
-#ifndef NO_LIBDEXFILE
-  std::mutex dex_lock_;
-  std::unordered_map<uint64_t, UnwindDexFile*> dex_files_;
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  std::unique_ptr<unwindstack::DexFiles> dex_files_;
 #endif
 };
 
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 28d7e64..74dfaa5 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -80,7 +80,13 @@
         host: {
             cflags: ["-O0", "-g"],
         },
+        vendor: {
+            cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
+            exclude_static_libs: ["libunwindstack_dex"],
+            exclude_shared_libs: ["libdexfile"],
+        },
     },
+    whole_static_libs: ["libunwindstack_dex"],
 
     arch: {
         x86: {
@@ -99,14 +105,70 @@
 
     shared_libs: [
         "libbase",
+        "libdexfile",
         "liblog",
         "liblzma",
     ],
 }
 
+// Isolate the dex file processing into a separate library. Currently,
+// it is necessary to add art include directories directly, which also
+// adds the art elf.h file in the include path, overriding the system one.
+// Work to isolate libdexfile is b/72216369.
+cc_library_static {
+    name: "libunwindstack_dex",
+    vendor_available: false,
+    defaults: ["libunwindstack_flags"],
+
+    cflags: [
+        "-Wexit-time-destructors",
+    ],
+
+    srcs: [
+        "DexFile.cpp",
+        "DexFiles.cpp",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libdexfile",
+    ],
+    local_include_dirs: ["include"],
+    allow_undefined_symbols: true,
+
+    // libdexfile will eventually properly export headers, for now include
+    // these directly.
+    include_dirs: [
+        "art/runtime",
+    ],
+}
+
 //-------------------------------------------------------------------------
 // Unit Tests
 //-------------------------------------------------------------------------
+cc_test_library {
+    name: "libunwindstack_dex_test",
+    vendor_available: false,
+    defaults: ["libunwindstack_flags"],
+
+    srcs: [
+        "tests/DexFileTest.cpp",
+    ],
+    local_include_dirs: ["include"],
+    allow_undefined_symbols: true,
+
+    shared_libs: [
+        "libbase",
+        "libunwindstack",
+    ],
+
+    // libdexfile will eventually properly export headers, for now include
+    // these directly.
+    include_dirs: [
+        "art/runtime",
+    ],
+}
+
 cc_test {
     name: "libunwindstack_test",
     defaults: ["libunwindstack_flags"],
@@ -168,6 +230,8 @@
         "libgmock",
     ],
 
+    whole_static_libs: ["libunwindstack_dex_test"],
+
     data: [
         "tests/files/elf32.xz",
         "tests/files/elf64.xz",
diff --git a/libbacktrace/UnwindDexFile.cpp b/libunwindstack/DexFile.cpp
similarity index 85%
rename from libbacktrace/UnwindDexFile.cpp
rename to libunwindstack/DexFile.cpp
index 5780fbb..be6c2f7 100644
--- a/libbacktrace/UnwindDexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -33,26 +33,27 @@
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Memory.h>
 
-#include "UnwindDexFile.h"
+#include "DexFile.h"
 
-UnwindDexFile* UnwindDexFile::Create(uint64_t dex_file_offset_in_memory,
-                                     unwindstack::Memory* memory, unwindstack::MapInfo* info) {
+namespace unwindstack {
+
+DexFile* DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info) {
   if (!info->name.empty()) {
-    std::unique_ptr<UnwindDexFileFromFile> dex_file(new UnwindDexFileFromFile);
+    std::unique_ptr<DexFileFromFile> dex_file(new DexFileFromFile);
     if (dex_file->Open(dex_file_offset_in_memory - info->start + info->offset, info->name)) {
       return dex_file.release();
     }
   }
 
-  std::unique_ptr<UnwindDexFileFromMemory> dex_file(new UnwindDexFileFromMemory);
+  std::unique_ptr<DexFileFromMemory> dex_file(new DexFileFromMemory);
   if (dex_file->Open(dex_file_offset_in_memory, memory)) {
     return dex_file.release();
   }
   return nullptr;
 }
 
-void UnwindDexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
-                                         uint64_t* method_offset) {
+void DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
+                                   uint64_t* method_offset) {
   if (dex_file_ == nullptr) {
     return;
   }
@@ -87,13 +88,13 @@
   }
 }
 
-UnwindDexFileFromFile::~UnwindDexFileFromFile() {
+DexFileFromFile::~DexFileFromFile() {
   if (size_ != 0) {
     munmap(mapped_memory_, size_);
   }
 }
 
-bool UnwindDexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) {
+bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) {
   android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
   if (fd == -1) {
     return false;
@@ -137,7 +138,7 @@
   return dex_file_ != nullptr;
 }
 
-bool UnwindDexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory) {
+bool DexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, Memory* memory) {
   art::DexFile::Header header;
   if (!memory->ReadFully(dex_file_offset_in_memory, &header, sizeof(header))) {
     return false;
@@ -160,3 +161,5 @@
   dex_file_.reset(dex.release());
   return dex_file_ != nullptr;
 }
+
+}  // namespace unwindstack
diff --git a/libbacktrace/UnwindDexFile.h b/libunwindstack/DexFile.h
similarity index 60%
rename from libbacktrace/UnwindDexFile.h
rename to libunwindstack/DexFile.h
index dd70aba..22e98df 100644
--- a/libbacktrace/UnwindDexFile.h
+++ b/libunwindstack/DexFile.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _LIBBACKTRACE_UNWIND_DEX_FILE_H
-#define _LIBBACKTRACE_UNWIND_DEX_FILE_H
+#ifndef _LIBUNWINDSTACK_DEX_FILE_H
+#define _LIBUNWINDSTACK_DEX_FILE_H
 
 #include <stdint.h>
 
@@ -26,28 +26,24 @@
 #include <dex/dex_file-inl.h>
 
 namespace unwindstack {
-class Memory;
-struct MapInfo;
-}  // namespace unwindstack
 
-class UnwindDexFile {
+class DexFile {
  public:
-  UnwindDexFile() = default;
-  virtual ~UnwindDexFile() = default;
+  DexFile() = default;
+  virtual ~DexFile() = default;
 
   void GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
 
-  static UnwindDexFile* Create(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory,
-                               unwindstack::MapInfo* info);
+  static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info);
 
  protected:
   std::unique_ptr<const art::DexFile> dex_file_;
 };
 
-class UnwindDexFileFromFile : public UnwindDexFile {
+class DexFileFromFile : public DexFile {
  public:
-  UnwindDexFileFromFile() = default;
-  virtual ~UnwindDexFileFromFile();
+  DexFileFromFile() = default;
+  virtual ~DexFileFromFile();
 
   bool Open(uint64_t dex_file_offset_in_file, const std::string& name);
 
@@ -56,15 +52,17 @@
   size_t size_ = 0;
 };
 
-class UnwindDexFileFromMemory : public UnwindDexFile {
+class DexFileFromMemory : public DexFile {
  public:
-  UnwindDexFileFromMemory() = default;
-  virtual ~UnwindDexFileFromMemory() = default;
+  DexFileFromMemory() = default;
+  virtual ~DexFileFromMemory() = default;
 
-  bool Open(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory);
+  bool Open(uint64_t dex_file_offset_in_memory, Memory* memory);
 
  private:
   std::vector<uint8_t> memory_;
 };
 
-#endif  // _LIBBACKTRACE_UNWIND_DEX_FILE_H
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_DEX_FILE_H
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
new file mode 100644
index 0000000..3d67a6a
--- /dev/null
+++ b/libunwindstack/DexFiles.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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/Memory.h>
+
+#include "DexFile.h"
+
+namespace unwindstack {
+
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : memory_(memory) {}
+
+DexFiles::~DexFiles() {
+  for (auto& entry : files_) {
+    delete entry.second;
+  }
+}
+
+DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) {
+  // Lock while processing the data.
+  std::lock_guard<std::mutex> guard(files_lock_);
+  DexFile* dex_file;
+  auto entry = files_.find(dex_file_offset);
+  if (entry == files_.end()) {
+    dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
+    files_[dex_file_offset] = dex_file;
+  } else {
+    dex_file = entry->second;
+  }
+  return dex_file;
+}
+
+void DexFiles::GetMethodInformation(uint64_t dex_offset, MapInfo* info, std::string* method_name,
+                                    uint64_t* method_offset) {
+  DexFile* dex_file = GetDexFile(dex_offset, info);
+  if (dex_file != nullptr) {
+    dex_file->GetMethodInformation(dex_offset, method_name, method_offset);
+  }
+}
+
+void DexFiles::SetArch(ArchEnum) {}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index f70ed7b..d22e1e8 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -31,8 +31,74 @@
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Unwinder.h>
 
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
+
 namespace unwindstack {
 
+// 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.
+// Adding the dex frame first here will create something like:
+//   #7 pc 0015fa20 core.vdex   java.util.Arrays.binarySearch+8
+//   #8 pc 006b1ba1 libartd.so  ExecuteMterpImpl+14625
+//   #9 pc 0039a1ef libartd.so  art::interpreter::Execute+719
+void Unwinder::FillInDexFrame() {
+  size_t frame_num = frames_.size();
+  frames_.resize(frame_num + 1);
+  FrameData* frame = &frames_.at(frame_num);
+
+  uint64_t dex_pc = regs_->dex_pc();
+  frame->pc = dex_pc;
+  frame->sp = regs_->sp();
+
+  auto it = maps_->begin();
+  uint64_t rel_dex_pc;
+  MapInfo* info;
+  for (; it != maps_->end(); ++it) {
+    auto entry = *it;
+    if (dex_pc >= entry->start && dex_pc < entry->end) {
+      info = entry;
+      rel_dex_pc = dex_pc - entry->start;
+      frame->map_start = entry->start;
+      frame->map_end = entry->end;
+      frame->map_offset = entry->offset;
+      frame->map_load_bias = entry->load_bias;
+      frame->map_flags = entry->flags;
+      frame->map_name = entry->name;
+      frame->rel_pc = rel_dex_pc;
+      break;
+    }
+  }
+
+  if (it == maps_->end() || ++it == maps_->end()) {
+    return;
+  }
+
+  auto entry = *it;
+  unwindstack::Elf* elf = entry->GetElf(process_memory_, true);
+  if (!elf->valid()) {
+    return;
+  }
+
+  // Adjust the relative dex by the offset.
+  rel_dex_pc += entry->elf_offset;
+
+  uint64_t dex_offset;
+  if (!elf->GetFunctionName(rel_dex_pc, &frame->function_name, &dex_offset)) {
+    return;
+  }
+  frame->function_offset = dex_offset;
+  if (frame->function_name != "$dexfile") {
+    return;
+  }
+
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  dex_files_->GetMethodInformation(dex_offset, info, &frame->function_name, &frame->function_offset);
+#endif
+}
+
 void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t func_pc) {
   size_t frame_num = frames_.size();
   frames_.resize(frame_num + 1);
@@ -40,7 +106,6 @@
   frame->num = frame_num;
   frame->sp = regs_->sp();
   frame->rel_pc = adjusted_rel_pc;
-  frame->dex_pc = regs_->dex_pc();
 
   if (map_info == nullptr) {
     frame->pc = regs_->pc();
@@ -128,6 +193,11 @@
     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()) {
+      if (regs_->dex_pc() != 0) {
+        // Add a frame to represent the dex file.
+        FillInDexFrame();
+      }
+
       FillInFrame(map_info, elf, adjusted_rel_pc, adjusted_pc);
 
       // Once a frame is added, stop skipping frames.
@@ -240,4 +310,11 @@
   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
+
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
new file mode 100644
index 0000000..d80e9b7
--- /dev/null
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -0,0 +1,56 @@
+/*
+ * 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>
+
+namespace unwindstack {
+
+// Forward declarations.
+class DexFile;
+class Maps;
+struct MapInfo;
+class Memory;
+enum ArchEnum : uint8_t;
+
+class DexFiles {
+ public:
+  explicit DexFiles(std::shared_ptr<Memory>& memory);
+  ~DexFiles();
+
+  DexFile* GetDexFile(uint64_t dex_offset, MapInfo* info);
+
+  void GetMethodInformation(uint64_t dex_offset, MapInfo* info, std::string* method_name,
+                            uint64_t* method_offset);
+
+  void SetArch(ArchEnum arch);
+
+ private:
+  std::shared_ptr<Memory> memory_;
+  std::mutex files_lock_;
+  std::unordered_map<uint64_t, DexFile*> files_;
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_DEX_FILES_H
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index a7b57e6..e8af8b4 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -32,6 +32,7 @@
 namespace unwindstack {
 
 // Forward declarations.
+class DexFiles;
 class Elf;
 class JitDebug;
 enum ArchEnum : uint8_t;
@@ -42,7 +43,6 @@
   uint64_t rel_pc;
   uint64_t pc;
   uint64_t sp;
-  uint64_t dex_pc;
 
   std::string function_name;
   uint64_t function_offset;
@@ -75,10 +75,15 @@
 
   void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
 
+#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; }
 
  private:
+  void FillInDexFrame();
   void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc, uint64_t adjusted_pc);
 
   size_t max_frames_;
@@ -87,6 +92,9 @@
   std::vector<FrameData> frames_;
   std::shared_ptr<Memory> process_memory_;
   JitDebug* jit_debug_ = nullptr;
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+  DexFiles* dex_files_ = nullptr;
+#endif
   ErrorData last_error_;
 };
 
diff --git a/libbacktrace/unwind_dex_test.cpp b/libunwindstack/tests/DexFileTest.cpp
similarity index 66%
rename from libbacktrace/unwind_dex_test.cpp
rename to libunwindstack/tests/DexFileTest.cpp
index 449e662..d1338cb 100644
--- a/libbacktrace/unwind_dex_test.cpp
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -30,46 +30,11 @@
 
 #include <gtest/gtest.h>
 
-#include "UnwindDexFile.h"
+#include "DexFile.h"
 
-class MemoryFake : public unwindstack::Memory {
- public:
-  MemoryFake() = default;
-  virtual ~MemoryFake() = default;
+#include "MemoryFake.h"
 
-  size_t Read(uint64_t addr, void* buffer, size_t size) override;
-
-  void SetMemory(uint64_t addr, const void* memory, size_t length);
-
-  void Clear() { data_.clear(); }
-
- private:
-  std::unordered_map<uint64_t, uint8_t> data_;
-};
-
-void MemoryFake::SetMemory(uint64_t addr, const void* memory, size_t length) {
-  const uint8_t* src = reinterpret_cast<const uint8_t*>(memory);
-  for (size_t i = 0; i < length; i++, addr++) {
-    auto value = data_.find(addr);
-    if (value != data_.end()) {
-      value->second = src[i];
-    } else {
-      data_.insert({addr, src[i]});
-    }
-  }
-}
-
-size_t MemoryFake::Read(uint64_t addr, void* memory, size_t size) {
-  uint8_t* dst = reinterpret_cast<uint8_t*>(memory);
-  for (size_t i = 0; i < size; i++, addr++) {
-    auto value = data_.find(addr);
-    if (value == data_.end()) {
-      return i;
-    }
-    dst[i] = value->second;
-  }
-  return size;
-}
+namespace unwindstack {
 
 // Borrowed from art/dex/dex_file_test.cc.
 static constexpr uint32_t kDexData[] = {
@@ -92,12 +57,12 @@
     0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
 };
 
-TEST(UnwindDexTest, from_file_open_non_exist) {
-  UnwindDexFileFromFile dex_file;
+TEST(DexFileTest, from_file_open_non_exist) {
+  DexFileFromFile dex_file;
   ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist"));
 }
 
-TEST(UnwindDexTest, from_file_open_too_small) {
+TEST(DexFileTest, from_file_open_too_small) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
 
@@ -106,7 +71,7 @@
                 TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2)));
 
   // Header too small.
-  UnwindDexFileFromFile dex_file;
+  DexFileFromFile dex_file;
   ASSERT_FALSE(dex_file.Open(0, tf.path));
 
   // Header correct, file too small.
@@ -116,18 +81,18 @@
   ASSERT_FALSE(dex_file.Open(0, tf.path));
 }
 
-TEST(UnwindDexTest, from_file_open) {
+TEST(DexFileTest, from_file_open) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
 
   ASSERT_EQ(sizeof(kDexData),
             static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
 
-  UnwindDexFileFromFile dex_file;
+  DexFileFromFile dex_file;
   ASSERT_TRUE(dex_file.Open(0, tf.path));
 }
 
-TEST(UnwindDexTest, from_file_open_non_zero_offset) {
+TEST(DexFileTest, from_file_open_non_zero_offset) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
 
@@ -135,38 +100,38 @@
   ASSERT_EQ(sizeof(kDexData),
             static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
 
-  UnwindDexFileFromFile dex_file;
+  DexFileFromFile dex_file;
   ASSERT_TRUE(dex_file.Open(0x100, tf.path));
 }
 
-TEST(UnwindDexTest, from_memory_fail_too_small_for_header) {
+TEST(DexFileTest, from_memory_fail_too_small_for_header) {
   MemoryFake memory;
 
   memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1);
-  UnwindDexFileFromMemory dex_file;
+  DexFileFromMemory dex_file;
 
   ASSERT_FALSE(dex_file.Open(0x1000, &memory));
 }
 
-TEST(UnwindDexTest, from_memory_fail_too_small_for_data) {
+TEST(DexFileTest, from_memory_fail_too_small_for_data) {
   MemoryFake memory;
 
   memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2);
-  UnwindDexFileFromMemory dex_file;
+  DexFileFromMemory dex_file;
 
   ASSERT_FALSE(dex_file.Open(0x1000, &memory));
 }
 
-TEST(UnwindDexTest, from_memory_open) {
+TEST(DexFileTest, from_memory_open) {
   MemoryFake memory;
 
   memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
-  UnwindDexFileFromMemory dex_file;
+  DexFileFromMemory dex_file;
 
   ASSERT_TRUE(dex_file.Open(0x1000, &memory));
 }
 
-TEST(UnwindDexTest, create_using_file) {
+TEST(DexFileTest, create_using_file) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
 
@@ -175,12 +140,12 @@
             static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
 
   MemoryFake memory;
-  unwindstack::MapInfo info(0, 0x10000, 0, 0x5, tf.path);
-  std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x500, &memory, &info));
+  MapInfo info(0, 0x10000, 0, 0x5, tf.path);
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x500, &memory, &info));
   ASSERT_TRUE(dex_file != nullptr);
 }
 
-TEST(UnwindDexTest, create_using_file_non_zero_start) {
+TEST(DexFileTest, create_using_file_non_zero_start) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
 
@@ -189,12 +154,12 @@
             static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
 
   MemoryFake memory;
-  unwindstack::MapInfo info(0x100, 0x10000, 0, 0x5, tf.path);
-  std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x600, &memory, &info));
+  MapInfo info(0x100, 0x10000, 0, 0x5, tf.path);
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x600, &memory, &info));
   ASSERT_TRUE(dex_file != nullptr);
 }
 
-TEST(UnwindDexTest, create_using_file_non_zero_offset) {
+TEST(DexFileTest, create_using_file_non_zero_offset) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
 
@@ -203,28 +168,28 @@
             static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
 
   MemoryFake memory;
-  unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, tf.path);
-  std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x400, &memory, &info));
+  MapInfo info(0x100, 0x10000, 0x200, 0x5, tf.path);
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x400, &memory, &info));
   ASSERT_TRUE(dex_file != nullptr);
 }
 
-TEST(UnwindDexTest, create_using_memory_empty_file) {
+TEST(DexFileTest, create_using_memory_empty_file) {
   MemoryFake memory;
   memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
-  unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
-  std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
+  MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
   ASSERT_TRUE(dex_file != nullptr);
 }
 
-TEST(UnwindDexTest, create_using_memory_file_does_not_exist) {
+TEST(DexFileTest, create_using_memory_file_does_not_exist) {
   MemoryFake memory;
   memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
-  unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
-  std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
+  MapInfo info(0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
   ASSERT_TRUE(dex_file != nullptr);
 }
 
-TEST(UnwindDexTest, create_using_memory_file_is_malformed) {
+TEST(DexFileTest, create_using_memory_file_is_malformed) {
   TemporaryFile tf;
   ASSERT_TRUE(tf.fd != -1);
 
@@ -233,30 +198,30 @@
 
   MemoryFake memory;
   memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
-  unwindstack::MapInfo info(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
-  std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
+  MapInfo info(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
   ASSERT_TRUE(dex_file != nullptr);
 
   // Check it came from memory by clearing memory and verifying it fails.
   memory.Clear();
-  dex_file.reset(UnwindDexFile::Create(0x4000, &memory, &info));
+  dex_file.reset(DexFile::Create(0x4000, &memory, &info));
   ASSERT_TRUE(dex_file == nullptr);
 }
 
-TEST(UnwindDexTest, get_method_not_opened) {
+TEST(DexFileTest, get_method_not_opened) {
   std::string method("something");
   uint64_t method_offset = 100;
-  UnwindDexFile dex_file;
+  DexFile dex_file;
   dex_file.GetMethodInformation(0x100, &method, &method_offset);
   EXPECT_EQ("something", method);
   EXPECT_EQ(100U, method_offset);
 }
 
-TEST(UnwindDexTest, get_method) {
+TEST(DexFileTest, get_method) {
   MemoryFake memory;
   memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
-  unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
-  std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info));
+  MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
+  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
   ASSERT_TRUE(dex_file != nullptr);
 
   std::string method;
@@ -271,3 +236,5 @@
   EXPECT_EQ("not_in_a_method", method);
   EXPECT_EQ(0x123U, method_offset);
 }
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 33e5527..07e48af 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -96,13 +96,8 @@
   unwinder.Unwind();
 
   // Print the frames.
-  const std::vector<unwindstack::FrameData>& frames = unwinder.frames();
   for (size_t i = 0; i < unwinder.NumFrames(); i++) {
     printf("%s\n", unwinder.FormatFrame(i).c_str());
-    const unwindstack::FrameData* frame = &frames[i];
-    if (frame->dex_pc != 0) {
-      printf("      dex pc %" PRIx64 "\n", frame->dex_pc);
-    }
   }
 }