Internalize subclasses of Memory

There are many subclasses of the Memory class and the overwhelming
majority of them don't need to be exposed externally. We move all of
them to internal headers except MemoryOfflineBuffer, which moves to a
separate header. This dramatically reduces the exposed API surface and
makes the code more modular.

Also, remove the Offline code from libbacktrace. It's not used any where.

Test: Unit tests pass, clean tree still builds
Change-Id: I55dacdf080daba0bfe65c1ad53a4b326bb482e83
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index e171155..9ece847 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -135,7 +135,6 @@
     defaults: ["libbacktrace_common"],
     host_supported: true,
     srcs: [
-        "backtrace_offline_test.cpp",
         "backtrace_test.cpp",
     ],
 
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 36640cd..a128623 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -129,22 +129,6 @@
   return true;
 }
 
-bool Backtrace::UnwindOffline(unwindstack::Regs* regs, BacktraceMap* back_map,
-                              const backtrace_stackinfo_t& stack,
-                              std::vector<backtrace_frame_data_t>* frames,
-                              BacktraceUnwindError* error) {
-  UnwindStackOfflineMap* offline_map = reinterpret_cast<UnwindStackOfflineMap*>(back_map);
-  // Create the process memory from the stack data since this will almost
-  // always be different each unwind.
-  if (!offline_map->CreateProcessMemory(stack)) {
-    if (error != nullptr) {
-      error->error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
-    }
-    return false;
-  }
-  return Backtrace::Unwind(regs, back_map, frames, 0U, nullptr, error);
-}
-
 UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map)
     : BacktraceCurrent(pid, tid, map) {}
 
@@ -171,7 +155,7 @@
 }
 
 UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
-    : BacktracePtrace(pid, tid, map), memory_(pid) {}
+    : BacktracePtrace(pid, tid, map), memory_(unwindstack::Memory::CreateProcessMemory(pid)) {}
 
 std::string UnwindStackPtrace::GetFunctionNameRaw(uint64_t pc, uint64_t* offset) {
   return GetMap()->GetFunctionName(pc, offset);
@@ -189,73 +173,5 @@
 }
 
 size_t UnwindStackPtrace::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
-  return memory_.Read(addr, buffer, bytes);
-}
-
-UnwindStackOffline::UnwindStackOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map,
-                                       bool map_shared)
-    : Backtrace(pid, tid, map), arch_(arch) {
-  map_shared_ = map_shared;
-}
-
-bool UnwindStackOffline::Unwind(size_t num_ignore_frames, void* ucontext) {
-  if (ucontext == nullptr) {
-    return false;
-  }
-
-  unwindstack::ArchEnum arch;
-  switch (arch_) {
-    case ARCH_ARM:
-      arch = unwindstack::ARCH_ARM;
-      break;
-    case ARCH_ARM64:
-      arch = unwindstack::ARCH_ARM64;
-      break;
-    case ARCH_X86:
-      arch = unwindstack::ARCH_X86;
-      break;
-    case ARCH_X86_64:
-      arch = unwindstack::ARCH_X86_64;
-      break;
-    default:
-      return false;
-  }
-
-  std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromUcontext(arch, ucontext));
-
-  return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr, &error_);
-}
-
-std::string UnwindStackOffline::GetFunctionNameRaw(uint64_t, uint64_t*) {
-  return "";
-}
-
-size_t UnwindStackOffline::Read(uint64_t, uint8_t*, size_t) {
-  return 0;
-}
-
-bool UnwindStackOffline::ReadWord(uint64_t, word_t*) {
-  return false;
-}
-
-Backtrace* Backtrace::CreateOffline(ArchEnum arch, pid_t pid, pid_t tid,
-                                    const std::vector<backtrace_map_t>& maps,
-                                    const backtrace_stackinfo_t& stack) {
-  std::unique_ptr<UnwindStackOfflineMap> map(
-      reinterpret_cast<UnwindStackOfflineMap*>(BacktraceMap::CreateOffline(pid, maps)));
-  if (map.get() == nullptr || !map->CreateProcessMemory(stack)) {
-    return nullptr;
-  }
-  return new UnwindStackOffline(arch, pid, tid, map.release(), false);
-}
-
-Backtrace* Backtrace::CreateOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map) {
-  if (map == nullptr) {
-    return nullptr;
-  }
-  return new UnwindStackOffline(arch, pid, tid, map, true);
-}
-
-void Backtrace::SetGlobalElfCache(bool enable) {
-  unwindstack::Elf::SetCachingEnabled(enable);
+  return memory_->Read(addr, buffer, bytes);
 }
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h
index 4ec591d..47f6757 100644
--- a/libbacktrace/UnwindStack.h
+++ b/libbacktrace/UnwindStack.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <string>
 
 #include <backtrace/BacktraceMap.h>
@@ -49,23 +50,7 @@
   size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
 
  private:
-  unwindstack::MemoryRemote memory_;
-};
-
-class UnwindStackOffline : public Backtrace {
- public:
-  UnwindStackOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map, bool map_shared);
-
-  bool Unwind(size_t num_ignore_frames, void* context) override;
-
-  std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override;
-
-  size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
-
-  bool ReadWord(uint64_t ptr, word_t* out_value) override;
-
- private:
-  ArchEnum arch_;
+  std::shared_ptr<unwindstack::Memory> memory_;
 };
 
 #endif  // _LIBBACKTRACE_UNWIND_STACK_H
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 4518891..aa0b17c 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -132,43 +132,6 @@
   return process_memory_;
 }
 
-UnwindStackOfflineMap::UnwindStackOfflineMap(pid_t pid) : UnwindStackMap(pid) {}
-
-bool UnwindStackOfflineMap::Build() {
-  return false;
-}
-
-bool UnwindStackOfflineMap::Build(const std::vector<backtrace_map_t>& backtrace_maps) {
-  for (const backtrace_map_t& map : backtrace_maps) {
-    maps_.push_back(map);
-  }
-
-  std::sort(maps_.begin(), maps_.end(),
-            [](const backtrace_map_t& a, const backtrace_map_t& b) { return a.start < b.start; });
-
-  unwindstack::Maps* maps = new unwindstack::Maps;
-  stack_maps_.reset(maps);
-  for (const backtrace_map_t& map : maps_) {
-    maps->Add(map.start, map.end, map.offset, map.flags, map.name, map.load_bias);
-  }
-  return true;
-}
-
-bool UnwindStackOfflineMap::CreateProcessMemory(const backtrace_stackinfo_t& stack) {
-  if (stack.start >= stack.end) {
-    return false;
-  }
-
-  // Create the process memory from the stack data.
-  if (memory_ == nullptr) {
-    memory_ = new unwindstack::MemoryOfflineBuffer(stack.data, stack.start, stack.end);
-    process_memory_.reset(memory_);
-  } else {
-    memory_->Reset(stack.data, stack.start, stack.end);
-  }
-  return true;
-}
-
 //-------------------------------------------------------------------------
 // BacktraceMap create function.
 //-------------------------------------------------------------------------
@@ -189,15 +152,3 @@
   }
   return map;
 }
-
-//-------------------------------------------------------------------------
-// BacktraceMap create offline function.
-//-------------------------------------------------------------------------
-BacktraceMap* BacktraceMap::CreateOffline(pid_t pid, const std::vector<backtrace_map_t>& maps) {
-  UnwindStackOfflineMap* map = new UnwindStackOfflineMap(pid);
-  if (!map->Build(maps)) {
-    delete map;
-    return nullptr;
-  }
-  return map;
-}
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index e19b605..f0e7d8b 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -33,6 +33,7 @@
 #include <unwindstack/Elf.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
 
 // Forward declarations.
 class UnwindDexFile;
@@ -74,19 +75,4 @@
   unwindstack::ArchEnum arch_ = unwindstack::ARCH_UNKNOWN;
 };
 
-class UnwindStackOfflineMap : public UnwindStackMap {
- public:
-  UnwindStackOfflineMap(pid_t pid);
-  ~UnwindStackOfflineMap() = default;
-
-  bool Build() override;
-
-  bool Build(const std::vector<backtrace_map_t>& maps);
-
-  bool CreateProcessMemory(const backtrace_stackinfo_t& stack);
-
- private:
-  unwindstack::MemoryOfflineBuffer* memory_ = nullptr;
-};
-
 #endif  // _LIBBACKTRACE_UNWINDSTACK_MAP_H
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
deleted file mode 100644
index 662fb99..0000000
--- a/libbacktrace/backtrace_offline_test.cpp
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-#include <pthread.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <functional>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/threads.h>
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include <gtest/gtest.h>
-
-#include "BacktraceTest.h"
-
-struct FunctionSymbol {
-  std::string name;
-  uint64_t start;
-  uint64_t end;
-};
-
-static std::vector<FunctionSymbol> GetFunctionSymbols() {
-  std::vector<FunctionSymbol> symbols = {
-      {"unknown_start", 0, 0},
-      {"test_level_one", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_one_), 0},
-      {"test_level_two", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_two_), 0},
-      {"test_level_three", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_three_), 0},
-      {"test_level_four", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_four_), 0},
-      {"test_recursive_call", reinterpret_cast<uint64_t>(&BacktraceTest::test_recursive_call_), 0},
-      {"test_get_context_and_wait",
-       reinterpret_cast<uint64_t>(&BacktraceTest::test_get_context_and_wait_), 0},
-      {"unknown_end", static_cast<uint64_t>(-1), static_cast<uint64_t>(-1)},
-  };
-  std::sort(
-      symbols.begin(), symbols.end(),
-      [](const FunctionSymbol& s1, const FunctionSymbol& s2) { return s1.start < s2.start; });
-  for (size_t i = 0; i + 1 < symbols.size(); ++i) {
-    symbols[i].end = symbols[i + 1].start;
-  }
-  return symbols;
-}
-
-static std::string RawDataToHexString(const void* data, size_t size) {
-  const uint8_t* p = static_cast<const uint8_t*>(data);
-  std::string s;
-  for (size_t i = 0; i < size; ++i) {
-    s += android::base::StringPrintf("%02x", p[i]);
-  }
-  return s;
-}
-
-static void HexStringToRawData(const char* s, std::vector<uint8_t>* data, size_t size) {
-  for (size_t i = 0; i < size; ++i) {
-    int value;
-    sscanf(s, "%02x", &value);
-    data->push_back(value);
-    s += 2;
-  }
-}
-
-struct OfflineThreadArg {
-  std::vector<uint8_t> ucontext;
-  pid_t tid;
-  volatile int exit_flag;
-};
-
-static void* OfflineThreadFunc(void* arg) {
-  OfflineThreadArg* fn_arg = reinterpret_cast<OfflineThreadArg*>(arg);
-  fn_arg->tid = android::base::GetThreadId();
-  BacktraceTest::test_get_context_and_wait_(&fn_arg->ucontext, &fn_arg->exit_flag);
-  return nullptr;
-}
-
-std::string GetTestPath(const std::string& arch, const std::string& path) {
-  return android::base::GetExecutableDirectory() + "/testdata/" + arch + '/' + path;
-}
-
-// This test is disable because it is for generating test data.
-TEST_F(BacktraceTest, DISABLED_generate_offline_testdata) {
-  // Create a thread to generate the needed stack and registers information.
-  const size_t stack_size = 16 * 1024;
-  void* stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-  ASSERT_NE(MAP_FAILED, stack);
-  uint64_t stack_addr = reinterpret_cast<uint64_t>(stack);
-  pthread_attr_t attr;
-  ASSERT_EQ(0, pthread_attr_init(&attr));
-  ASSERT_EQ(0, pthread_attr_setstack(&attr, reinterpret_cast<void*>(stack), stack_size));
-  pthread_t thread;
-  OfflineThreadArg arg;
-  arg.exit_flag = 0;
-  ASSERT_EQ(0, pthread_create(&thread, &attr, OfflineThreadFunc, &arg));
-  // Wait for the offline thread to generate the stack and context information.
-  sleep(1);
-  // Copy the stack information.
-  std::vector<uint8_t> stack_data(reinterpret_cast<uint8_t*>(stack),
-                                  reinterpret_cast<uint8_t*>(stack) + stack_size);
-  arg.exit_flag = 1;
-  ASSERT_EQ(0, pthread_join(thread, nullptr));
-  ASSERT_EQ(0, munmap(stack, stack_size));
-
-  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid()));
-  ASSERT_TRUE(map != nullptr);
-
-  backtrace_stackinfo_t stack_info;
-  stack_info.start = stack_addr;
-  stack_info.end = stack_addr + stack_size;
-  stack_info.data = stack_data.data();
-
-  // Generate offline testdata.
-  std::string testdata;
-  // 1. Dump pid, tid
-  testdata += android::base::StringPrintf("pid: %d tid: %d\n", getpid(), arg.tid);
-  // 2. Dump maps
-  for (auto it = map->begin(); it != map->end(); ++it) {
-    const backtrace_map_t* entry = *it;
-    testdata +=
-        android::base::StringPrintf("map: start: %" PRIx64 " end: %" PRIx64 " offset: %" PRIx64
-                                    " load_bias: %" PRIx64 " flags: %d name: %s\n",
-                                    entry->start, entry->end, entry->offset, entry->load_bias,
-                                    entry->flags, entry->name.c_str());
-  }
-  // 3. Dump ucontext
-  testdata += android::base::StringPrintf("ucontext: %zu ", arg.ucontext.size());
-  testdata += RawDataToHexString(arg.ucontext.data(), arg.ucontext.size());
-  testdata.push_back('\n');
-
-  // 4. Dump stack
-  testdata += android::base::StringPrintf(
-      "stack: start: %" PRIx64 " end: %" PRIx64 " size: %zu ",
-      stack_info.start, stack_info.end, stack_data.size());
-  testdata += RawDataToHexString(stack_data.data(), stack_data.size());
-  testdata.push_back('\n');
-
-  // 5. Dump function symbols
-  std::vector<FunctionSymbol> function_symbols = GetFunctionSymbols();
-  for (const auto& symbol : function_symbols) {
-    testdata +=
-        android::base::StringPrintf("function: start: %" PRIx64 " end: %" PRIx64 " name: %s\n",
-                                    symbol.start, symbol.end, symbol.name.c_str());
-  }
-
-  ASSERT_TRUE(android::base::WriteStringToFile(testdata, "offline_testdata"));
-}
-
-// Return the name of the function which matches the address. Although we don't know the
-// exact end of each function, it is accurate enough for the tests.
-static std::string FunctionNameForAddress(uint64_t addr,
-                                          const std::vector<FunctionSymbol>& symbols) {
-  for (auto& symbol : symbols) {
-    if (addr >= symbol.start && addr < symbol.end) {
-      return symbol.name;
-    }
-  }
-  return "";
-}
-
-struct OfflineTestData {
-  int pid;
-  int tid;
-  std::vector<backtrace_map_t> maps;
-  std::vector<uint8_t> ucontext;
-  backtrace_stackinfo_t stack_info;
-  std::vector<uint8_t> stack;
-  std::vector<FunctionSymbol> symbols;
-};
-
-bool ReadOfflineTestData(const std::string offline_testdata_path, OfflineTestData* testdata) {
-  std::string s;
-  if (!android::base::ReadFileToString(offline_testdata_path, &s)) {
-    return false;
-  }
-  // Parse offline_testdata.
-  std::vector<std::string> lines = android::base::Split(s, "\n");
-  for (const auto& line : lines) {
-    if (android::base::StartsWith(line, "pid:")) {
-      sscanf(line.c_str(), "pid: %d tid: %d", &testdata->pid, &testdata->tid);
-    } else if (android::base::StartsWith(line, "map:")) {
-      testdata->maps.resize(testdata->maps.size() + 1);
-      backtrace_map_t& map = testdata->maps.back();
-      int pos;
-      sscanf(line.c_str(),
-             "map: start: %" SCNx64 " end: %" SCNx64 " offset: %" SCNx64 " load_bias: %" SCNx64
-             " flags: %d name: %n",
-             &map.start, &map.end, &map.offset, &map.load_bias, &map.flags, &pos);
-      map.name = android::base::Trim(line.substr(pos));
-    } else if (android::base::StartsWith(line, "ucontext:")) {
-      size_t size;
-      int pos;
-      testdata->ucontext.clear();
-      sscanf(line.c_str(), "ucontext: %zu %n", &size, &pos);
-      HexStringToRawData(&line[pos], &testdata->ucontext, size);
-    } else if (android::base::StartsWith(line, "stack:")) {
-      size_t size;
-      int pos;
-      sscanf(line.c_str(),
-             "stack: start: %" SCNx64 " end: %" SCNx64 " size: %zu %n",
-             &testdata->stack_info.start, &testdata->stack_info.end, &size, &pos);
-      CHECK_EQ(testdata->stack_info.end - testdata->stack_info.start, size);
-      testdata->stack.clear();
-      HexStringToRawData(&line[pos], &testdata->stack, size);
-      testdata->stack_info.data = testdata->stack.data();
-    } else if (android::base::StartsWith(line, "function:")) {
-      testdata->symbols.resize(testdata->symbols.size() + 1);
-      FunctionSymbol& symbol = testdata->symbols.back();
-      int pos;
-      sscanf(line.c_str(), "function: start: %" SCNx64 " end: %" SCNx64 " name: %n", &symbol.start,
-             &symbol.end, &pos);
-      symbol.name = line.substr(pos);
-    }
-  }
-  return true;
-}
-
-static void BacktraceOfflineTest(std::string arch_str, const std::string& testlib_name) {
-  const std::string testlib_path(GetTestPath(arch_str, testlib_name));
-  const std::string offline_testdata_path(GetTestPath(arch_str, "offline_testdata"));
-  OfflineTestData testdata;
-  ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata)) << "Failed " << arch_str;
-
-  // Fix path of libbacktrace_testlib.so.
-  for (auto& map : testdata.maps) {
-    if (map.name.find("libbacktrace_test.so") != std::string::npos) {
-      map.name = testlib_path;
-    }
-  }
-
-  Backtrace::ArchEnum arch;
-  if (arch_str == "arm") {
-    arch = Backtrace::ARCH_ARM;
-  } else if (arch_str == "arm64") {
-    arch = Backtrace::ARCH_ARM64;
-  } else if (arch_str == "x86") {
-    arch = Backtrace::ARCH_X86;
-  } else if (arch_str == "x86_64") {
-    arch = Backtrace::ARCH_X86_64;
-  } else {
-    abort();
-  }
-
-  std::unique_ptr<Backtrace> backtrace(Backtrace::CreateOffline(
-      arch, testdata.pid, testdata.tid, testdata.maps, testdata.stack_info));
-  ASSERT_TRUE(backtrace != nullptr) << "Failed " << arch_str;
-
-  ASSERT_TRUE(backtrace->Unwind(0, testdata.ucontext.data())) << "Failed " << arch_str;
-
-  // Collect pc values of the call stack frames.
-  std::vector<uint64_t> pc_values;
-  for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
-    pc_values.push_back(backtrace->GetFrame(i)->pc);
-  }
-
-  size_t test_one_index = 0;
-  for (size_t i = 0; i < pc_values.size(); ++i) {
-    if (FunctionNameForAddress(pc_values[i], testdata.symbols) == "test_level_one") {
-      test_one_index = i;
-      break;
-    }
-  }
-
-  ASSERT_GE(test_one_index, 3u) << "Failed " << arch_str;
-  ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], testdata.symbols))
-      << "Failed " << arch_str;
-  ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1], testdata.symbols))
-      << "Failed " << arch_str;
-  ASSERT_EQ("test_level_three",
-            FunctionNameForAddress(pc_values[test_one_index - 2], testdata.symbols))
-      << "Failed " << arch_str;
-  ASSERT_EQ("test_level_four",
-            FunctionNameForAddress(pc_values[test_one_index - 3], testdata.symbols))
-      << "Failed " << arch_str;
-}
-
-// For now, these tests can only run on the given architectures.
-TEST_F(BacktraceTest, offline_eh_frame) {
-  BacktraceOfflineTest("arm64", "libbacktrace_test_eh_frame.so");
-  BacktraceOfflineTest("x86_64", "libbacktrace_test_eh_frame.so");
-}
-
-TEST_F(BacktraceTest, offline_debug_frame) {
-  BacktraceOfflineTest("arm", "libbacktrace_test_debug_frame.so");
-  BacktraceOfflineTest("x86", "libbacktrace_test_debug_frame.so");
-}
-
-TEST_F(BacktraceTest, offline_gnu_debugdata) {
-  BacktraceOfflineTest("arm", "libbacktrace_test_gnu_debugdata.so");
-  BacktraceOfflineTest("x86", "libbacktrace_test_gnu_debugdata.so");
-}
-
-TEST_F(BacktraceTest, offline_arm_exidx) {
-  BacktraceOfflineTest("arm", "libbacktrace_test_arm_exidx.so");
-}
-
-static void LibUnwindingTest(const std::string& arch_str, const std::string& testdata_name,
-                             const std::string& testlib_name) {
-  const std::string testlib_path(GetTestPath(arch_str, testlib_name));
-  struct stat st;
-  ASSERT_EQ(0, stat(testlib_path.c_str(), &st)) << "can't find testlib " << testlib_path;
-
-  const std::string offline_testdata_path(GetTestPath(arch_str, testdata_name));
-  OfflineTestData testdata;
-  ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
-
-  // Fix path of the testlib.
-  for (auto& map : testdata.maps) {
-    if (map.name.find(testlib_name) != std::string::npos) {
-      map.name = testlib_path;
-    }
-  }
-
-  Backtrace::ArchEnum arch;
-  if (arch_str == "arm") {
-    arch = Backtrace::ARCH_ARM;
-  } else if (arch_str == "arm64") {
-    arch = Backtrace::ARCH_ARM64;
-  } else if (arch_str == "x86") {
-    arch = Backtrace::ARCH_X86;
-  } else if (arch_str == "x86_64") {
-    arch = Backtrace::ARCH_X86_64;
-  } else {
-    ASSERT_TRUE(false) << "Unsupported arch " << arch_str;
-    abort();
-  }
-
-  // Do offline backtrace.
-  std::unique_ptr<Backtrace> backtrace(Backtrace::CreateOffline(
-      arch, testdata.pid, testdata.tid, testdata.maps, testdata.stack_info));
-  ASSERT_TRUE(backtrace != nullptr);
-
-  ASSERT_TRUE(backtrace->Unwind(0, testdata.ucontext.data()));
-
-  ASSERT_EQ(testdata.symbols.size(), backtrace->NumFrames());
-  for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
-    std::string name = FunctionNameForAddress(backtrace->GetFrame(i)->rel_pc, testdata.symbols);
-    ASSERT_EQ(name, testdata.symbols[i].name);
-  }
-  ASSERT_TRUE(backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED ||
-              backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_MAP_MISSING ||
-              backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_REPEATED_FRAME);
-}
-
-// This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx
-// overlap with each other, which appears in /system/lib/libart.so.
-TEST_F(BacktraceTest, offline_unwind_mix_eh_frame_and_arm_exidx) {
-  LibUnwindingTest("arm", "offline_testdata_for_libart", "libart.so");
-}
-
-TEST_F(BacktraceTest, offline_debug_frame_with_load_bias) {
-  LibUnwindingTest("arm", "offline_testdata_for_libandroid_runtime", "libandroid_runtime.so");
-}
-
-TEST_F(BacktraceTest, offline_try_armexidx_after_debug_frame) {
-  LibUnwindingTest("arm", "offline_testdata_for_libGLESv2_adreno", "libGLESv2_adreno.so");
-}
-
-TEST_F(BacktraceTest, offline_cie_with_P_augmentation) {
-  // Make sure we can unwind through functions with CIE entry containing P augmentation, which
-  // makes unwinding library reading personality handler from memory. One example is
-  // /system/lib64/libskia.so.
-  LibUnwindingTest("arm64", "offline_testdata_for_libskia", "libskia.so");
-}
-
-TEST_F(BacktraceTest, offline_empty_eh_frame_hdr) {
-  // Make sure we can unwind through libraries with empty .eh_frame_hdr section. One example is
-  // /vendor/lib64/egl/eglSubDriverAndroid.so.
-  LibUnwindingTest("arm64", "offline_testdata_for_eglSubDriverAndroid", "eglSubDriverAndroid.so");
-}
-
-TEST_F(BacktraceTest, offline_max_frames_limit) {
-  // The length of callchain can reach 256 when recording an application.
-  ASSERT_GE(MAX_BACKTRACE_FRAMES, 256);
-}
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 404e7e8..664b531 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -126,24 +126,6 @@
   // If map is not NULL, the map is still owned by the caller.
   static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = nullptr);
 
-  // Create an offline Backtrace object that can be used to do an unwind without a process
-  // that is still running. By default, information is only cached in the map
-  // file. If the calling code creates the map, data can be cached between
-  // unwinds. If not, all cached data will be destroyed when the Backtrace
-  // object is destroyed.
-  static Backtrace* CreateOffline(ArchEnum arch, pid_t pid, pid_t tid,
-                                  const std::vector<backtrace_map_t>& maps,
-                                  const backtrace_stackinfo_t& stack);
-  static Backtrace* CreateOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map);
-
-  // Create an offline Backtrace object that can be used to do an unwind without a process
-  // that is still running. If cache_file is set to true, then elf information will be cached
-  // for this call. The cached information survives until the calling process ends. This means
-  // that subsequent calls to create offline Backtrace objects will continue to use the same
-  // cache. It also assumes that the elf files used for each offline unwind are the same.
-  static Backtrace* CreateOffline(pid_t pid, pid_t tid, BacktraceMap* map,
-                                  const backtrace_stackinfo_t& stack, bool cache_file = false);
-
   virtual ~Backtrace();
 
   // Get the current stack trace and store in the backtrace_ structure.
@@ -153,11 +135,6 @@
                      std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
                      std::vector<std::string>* skip_names, BacktraceUnwindError* error = nullptr);
 
-  static bool UnwindOffline(unwindstack::Regs* regs, BacktraceMap* back_map,
-                            const backtrace_stackinfo_t& stack_info,
-                            std::vector<backtrace_frame_data_t>* frames,
-                            BacktraceUnwindError* error = nullptr);
-
   // Get the function name and offset into the function given the pc.
   // If the string is empty, then no valid function name was found,
   // or the pc is not in any valid map.
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index c564271..f8d5058 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -69,8 +69,6 @@
   // is unsupported.
   static BacktraceMap* Create(pid_t pid, bool uncached = false);
 
-  static BacktraceMap* CreateOffline(pid_t pid, const std::vector<backtrace_map_t>& maps);
-
   virtual ~BacktraceMap();
 
   class iterator : public std::iterator<std::bidirectional_iterator_tag, backtrace_map_t*> {
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index dee8eb3..f0e4138 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -29,12 +29,12 @@
 #include <unwindstack/DwarfSection.h>
 #include <unwindstack/ElfInterface.h>
 #include <unwindstack/Log.h>
-#include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
 
 #include "DwarfDebugFrame.h"
 #include "DwarfEhFrame.h"
 #include "DwarfEhFrameWithHdr.h"
+#include "MemoryBuffer.h"
 #include "Symbols.h"
 
 namespace unwindstack {
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp
index 20bc4b9..8a85607 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -23,7 +23,8 @@
 #include <unwindstack/Elf.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
+
+#include "MemoryRange.h"
 
 // This implements the JIT Compilation Interface.
 // See https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index d3cec06..1c0f1e6 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -27,7 +27,9 @@
 #include <unwindstack/Elf.h>
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
+
+#include "MemoryFileAtOffset.h"
+#include "MemoryRange.h"
 
 namespace unwindstack {
 
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index 9904fef..a66cd5b 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -32,6 +32,14 @@
 #include <unwindstack/Memory.h>
 
 #include "Check.h"
+#include "MemoryBuffer.h"
+#include "MemoryCache.h"
+#include "MemoryFileAtOffset.h"
+#include "MemoryLocal.h"
+#include "MemoryOffline.h"
+#include "MemoryOfflineBuffer.h"
+#include "MemoryRange.h"
+#include "MemoryRemote.h"
 
 namespace unwindstack {
 
@@ -168,6 +176,16 @@
   return false;
 }
 
+std::unique_ptr<Memory> Memory::CreateFileMemory(const std::string& path, uint64_t offset) {
+  auto memory = std::make_unique<MemoryFileAtOffset>();
+
+  if (memory->Init(path, offset)) {
+    return memory;
+  }
+
+  return nullptr;
+}
+
 std::shared_ptr<Memory> Memory::CreateProcessMemory(pid_t pid) {
   if (pid == getpid()) {
     return std::shared_ptr<Memory>(new MemoryLocal());
@@ -182,6 +200,11 @@
   return std::shared_ptr<Memory>(new MemoryCache(new MemoryRemote(pid)));
 }
 
+std::shared_ptr<Memory> Memory::CreateOfflineMemory(const uint8_t* data, uint64_t start,
+                                                    uint64_t end) {
+  return std::shared_ptr<Memory>(new MemoryOfflineBuffer(data, start, end));
+}
+
 size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
   if (addr >= raw_.size()) {
     return 0;
diff --git a/libunwindstack/MemoryBuffer.h b/libunwindstack/MemoryBuffer.h
new file mode 100644
index 0000000..3fe4bbb
--- /dev/null
+++ b/libunwindstack/MemoryBuffer.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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_MEMORY_BUFFER_H
+#define _LIBUNWINDSTACK_MEMORY_BUFFER_H
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
+
+class MemoryBuffer : public Memory {
+ public:
+  MemoryBuffer() = default;
+  virtual ~MemoryBuffer() = default;
+
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+  uint8_t* GetPtr(size_t offset);
+
+  void Resize(size_t size) { raw_.resize(size); }
+
+  uint64_t Size() { return raw_.size(); }
+
+ private:
+  std::vector<uint8_t> raw_;
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MEMORY_BUFFER_H
diff --git a/libunwindstack/MemoryCache.h b/libunwindstack/MemoryCache.h
new file mode 100644
index 0000000..769d907
--- /dev/null
+++ b/libunwindstack/MemoryCache.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 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_MEMORY_CACHE_H
+#define _LIBUNWINDSTACK_MEMORY_CACHE_H
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
+
+class MemoryCache : public Memory {
+ public:
+  MemoryCache(Memory* memory) : impl_(memory) {}
+  virtual ~MemoryCache() = default;
+
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+  void Clear() override { cache_.clear(); }
+
+ private:
+  constexpr static size_t kCacheBits = 12;
+  constexpr static size_t kCacheMask = (1 << kCacheBits) - 1;
+  constexpr static size_t kCacheSize = 1 << kCacheBits;
+  std::unordered_map<uint64_t, uint8_t[kCacheSize]> cache_;
+
+  std::unique_ptr<Memory> impl_;
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MEMORY_CACHE_H
diff --git a/libunwindstack/MemoryFileAtOffset.h b/libunwindstack/MemoryFileAtOffset.h
new file mode 100644
index 0000000..d136eb4
--- /dev/null
+++ b/libunwindstack/MemoryFileAtOffset.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 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_MEMORY_FILE_AT_OFFSET_H
+#define _LIBUNWINDSTACK_MEMORY_FILE_AT_OFFSET_H
+
+#include <stdint.h>
+
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
+
+class MemoryFileAtOffset : public Memory {
+ public:
+  MemoryFileAtOffset() = default;
+  virtual ~MemoryFileAtOffset();
+
+  bool Init(const std::string& file, uint64_t offset, uint64_t size = UINT64_MAX);
+
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+  size_t Size() { return size_; }
+
+  void Clear() override;
+
+ protected:
+  size_t size_ = 0;
+  size_t offset_ = 0;
+  uint8_t* data_ = nullptr;
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MEMORY_FILE_AT_OFFSET_H
diff --git a/libunwindstack/MemoryLocal.h b/libunwindstack/MemoryLocal.h
new file mode 100644
index 0000000..29aaf12
--- /dev/null
+++ b/libunwindstack/MemoryLocal.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 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_MEMORY_LOCAL_H
+#define _LIBUNWINDSTACK_MEMORY_LOCAL_H
+
+#include <stdint.h>
+
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
+
+class MemoryLocal : public Memory {
+ public:
+  MemoryLocal() = default;
+  virtual ~MemoryLocal() = default;
+
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MEMORY_LOCAL_H
diff --git a/libunwindstack/MemoryOffline.h b/libunwindstack/MemoryOffline.h
new file mode 100644
index 0000000..789f1a2
--- /dev/null
+++ b/libunwindstack/MemoryOffline.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 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_MEMORY_OFFLINE_H
+#define _LIBUNWINDSTACK_MEMORY_OFFLINE_H
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <unwindstack/Memory.h>
+
+#include "MemoryRange.h"
+
+namespace unwindstack {
+
+class MemoryOffline : public Memory {
+ public:
+  MemoryOffline() = default;
+  virtual ~MemoryOffline() = default;
+
+  bool Init(const std::string& file, uint64_t offset);
+
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+ private:
+  std::unique_ptr<MemoryRange> memory_;
+};
+
+class MemoryOfflineParts : public Memory {
+ public:
+  MemoryOfflineParts() = default;
+  virtual ~MemoryOfflineParts();
+
+  void Add(MemoryOffline* memory) { memories_.push_back(memory); }
+
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+ private:
+  std::vector<MemoryOffline*> memories_;
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MEMORY_OFFLINE_H
diff --git a/libunwindstack/MemoryOfflineBuffer.h b/libunwindstack/MemoryOfflineBuffer.h
new file mode 100644
index 0000000..64c49a1
--- /dev/null
+++ b/libunwindstack/MemoryOfflineBuffer.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 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_MEMORY_OFFLINE_BUFFER_H
+#define _LIBUNWINDSTACK_MEMORY_OFFLINE_BUFFER_H
+
+#include <stdint.h>
+
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
+
+class MemoryOfflineBuffer : public Memory {
+ public:
+  MemoryOfflineBuffer(const uint8_t* data, uint64_t start, uint64_t end);
+  virtual ~MemoryOfflineBuffer() = default;
+
+  void Reset(const uint8_t* data, uint64_t start, uint64_t end);
+
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+ private:
+  const uint8_t* data_;
+  uint64_t start_;
+  uint64_t end_;
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MEMORY_OFFLINE_BUFFER_H
diff --git a/libunwindstack/MemoryRange.h b/libunwindstack/MemoryRange.h
new file mode 100644
index 0000000..3b4ab5c
--- /dev/null
+++ b/libunwindstack/MemoryRange.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 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_MEMORY_RANGE_H
+#define _LIBUNWINDSTACK_MEMORY_RANGE_H
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
+
+// MemoryRange maps one address range onto another.
+// The range [src_begin, src_begin + length) in the underlying Memory is mapped onto offset,
+// such that range.read(offset) is equivalent to underlying.read(src_begin).
+class MemoryRange : public Memory {
+ public:
+  MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
+              uint64_t offset);
+  virtual ~MemoryRange() = default;
+
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+  uint64_t offset() { return offset_; }
+  uint64_t length() { return length_; }
+
+ private:
+  std::shared_ptr<Memory> memory_;
+  uint64_t begin_;
+  uint64_t length_;
+  uint64_t offset_;
+};
+
+class MemoryRanges : public Memory {
+ public:
+  MemoryRanges() = default;
+  virtual ~MemoryRanges() = default;
+
+  void Insert(MemoryRange* memory);
+
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+ private:
+  std::map<uint64_t, std::unique_ptr<MemoryRange>> maps_;
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MEMORY_RANGE_H
diff --git a/libunwindstack/MemoryRemote.h b/libunwindstack/MemoryRemote.h
new file mode 100644
index 0000000..db367d6
--- /dev/null
+++ b/libunwindstack/MemoryRemote.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 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_MEMORY_REMOTE_H
+#define _LIBUNWINDSTACK_MEMORY_REMOTE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <atomic>
+
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
+
+class MemoryRemote : public Memory {
+ public:
+  MemoryRemote(pid_t pid) : pid_(pid), read_redirect_func_(0) {}
+  virtual ~MemoryRemote() = default;
+
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+  pid_t pid() { return pid_; }
+
+ private:
+  pid_t pid_;
+  std::atomic_uintptr_t read_redirect_func_;
+};
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_MEMORY_REMOTE_H
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index 025fd98..13ce10f 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -25,10 +25,11 @@
 #include <string>
 
 #include <unwindstack/Elf.h>
-#include <unwindstack/Memory.h>
 
 namespace unwindstack {
 
+class MemoryFileAtOffset;
+
 struct MapInfo {
   MapInfo(MapInfo* map_info, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
           const char* name)
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index b3beb6e..3106564 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -21,12 +21,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <atomic>
-#include <map>
 #include <memory>
 #include <string>
-#include <unordered_map>
-#include <vector>
 
 namespace unwindstack {
 
@@ -37,6 +33,9 @@
 
   static std::shared_ptr<Memory> CreateProcessMemory(pid_t pid);
   static std::shared_ptr<Memory> CreateProcessMemoryCached(pid_t pid);
+  static std::shared_ptr<Memory> CreateOfflineMemory(const uint8_t* data, uint64_t start,
+                                                     uint64_t end);
+  static std::unique_ptr<Memory> CreateFileMemory(const std::string& path, uint64_t offset);
 
   virtual bool ReadString(uint64_t addr, std::string* string, uint64_t max_read = UINT64_MAX);
 
@@ -55,157 +54,6 @@
   }
 };
 
-class MemoryCache : public Memory {
- public:
-  MemoryCache(Memory* memory) : impl_(memory) {}
-  virtual ~MemoryCache() = default;
-
-  size_t Read(uint64_t addr, void* dst, size_t size) override;
-
-  void Clear() override { cache_.clear(); }
-
- private:
-  constexpr static size_t kCacheBits = 12;
-  constexpr static size_t kCacheMask = (1 << kCacheBits) - 1;
-  constexpr static size_t kCacheSize = 1 << kCacheBits;
-  std::unordered_map<uint64_t, uint8_t[kCacheSize]> cache_;
-
-  std::unique_ptr<Memory> impl_;
-};
-
-class MemoryBuffer : public Memory {
- public:
-  MemoryBuffer() = default;
-  virtual ~MemoryBuffer() = default;
-
-  size_t Read(uint64_t addr, void* dst, size_t size) override;
-
-  uint8_t* GetPtr(size_t offset);
-
-  void Resize(size_t size) { raw_.resize(size); }
-
-  uint64_t Size() { return raw_.size(); }
-
- private:
-  std::vector<uint8_t> raw_;
-};
-
-class MemoryFileAtOffset : public Memory {
- public:
-  MemoryFileAtOffset() = default;
-  virtual ~MemoryFileAtOffset();
-
-  bool Init(const std::string& file, uint64_t offset, uint64_t size = UINT64_MAX);
-
-  size_t Read(uint64_t addr, void* dst, size_t size) override;
-
-  size_t Size() { return size_; }
-
-  void Clear() override;
-
- protected:
-  size_t size_ = 0;
-  size_t offset_ = 0;
-  uint8_t* data_ = nullptr;
-};
-
-class MemoryRemote : public Memory {
- public:
-  MemoryRemote(pid_t pid) : pid_(pid), read_redirect_func_(0) {}
-  virtual ~MemoryRemote() = default;
-
-  size_t Read(uint64_t addr, void* dst, size_t size) override;
-
-  pid_t pid() { return pid_; }
-
- private:
-  pid_t pid_;
-  std::atomic_uintptr_t read_redirect_func_;
-};
-
-class MemoryLocal : public Memory {
- public:
-  MemoryLocal() = default;
-  virtual ~MemoryLocal() = default;
-
-  size_t Read(uint64_t addr, void* dst, size_t size) override;
-};
-
-// MemoryRange maps one address range onto another.
-// The range [src_begin, src_begin + length) in the underlying Memory is mapped onto offset,
-// such that range.read(offset) is equivalent to underlying.read(src_begin).
-class MemoryRange : public Memory {
- public:
-  MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
-              uint64_t offset);
-  virtual ~MemoryRange() = default;
-
-  size_t Read(uint64_t addr, void* dst, size_t size) override;
-
-  uint64_t offset() { return offset_; }
-  uint64_t length() { return length_; }
-
- private:
-  std::shared_ptr<Memory> memory_;
-  uint64_t begin_;
-  uint64_t length_;
-  uint64_t offset_;
-};
-
-class MemoryRanges : public Memory {
- public:
-  MemoryRanges() = default;
-  virtual ~MemoryRanges() = default;
-
-  void Insert(MemoryRange* memory);
-
-  size_t Read(uint64_t addr, void* dst, size_t size) override;
-
- private:
-  std::map<uint64_t, std::unique_ptr<MemoryRange>> maps_;
-};
-
-class MemoryOffline : public Memory {
- public:
-  MemoryOffline() = default;
-  virtual ~MemoryOffline() = default;
-
-  bool Init(const std::string& file, uint64_t offset);
-
-  size_t Read(uint64_t addr, void* dst, size_t size) override;
-
- private:
-  std::unique_ptr<MemoryRange> memory_;
-};
-
-class MemoryOfflineBuffer : public Memory {
- public:
-  MemoryOfflineBuffer(const uint8_t* data, uint64_t start, uint64_t end);
-  virtual ~MemoryOfflineBuffer() = default;
-
-  void Reset(const uint8_t* data, uint64_t start, uint64_t end);
-
-  size_t Read(uint64_t addr, void* dst, size_t size) override;
-
- private:
-  const uint8_t* data_;
-  uint64_t start_;
-  uint64_t end_;
-};
-
-class MemoryOfflineParts : public Memory {
- public:
-  MemoryOfflineParts() = default;
-  virtual ~MemoryOfflineParts();
-
-  void Add(MemoryOffline* memory) { memories_.push_back(memory); }
-
-  size_t Read(uint64_t addr, void* dst, size_t size) override;
-
- private:
-  std::vector<MemoryOffline*> memories_;
-};
-
 }  // namespace unwindstack
 
 #endif  // _LIBUNWINDSTACK_MEMORY_H
diff --git a/libunwindstack/tests/MemoryBufferTest.cpp b/libunwindstack/tests/MemoryBufferTest.cpp
index 28e0e76..a6c12aa 100644
--- a/libunwindstack/tests/MemoryBufferTest.cpp
+++ b/libunwindstack/tests/MemoryBufferTest.cpp
@@ -18,9 +18,8 @@
 
 #include <gtest/gtest.h>
 
-#include <unwindstack/Memory.h>
-
 #include "LogFake.h"
+#include "MemoryBuffer.h"
 
 namespace unwindstack {
 
diff --git a/libunwindstack/tests/MemoryCacheTest.cpp b/libunwindstack/tests/MemoryCacheTest.cpp
index a3def20..3bd3e4d 100644
--- a/libunwindstack/tests/MemoryCacheTest.cpp
+++ b/libunwindstack/tests/MemoryCacheTest.cpp
@@ -20,8 +20,7 @@
 
 #include <gtest/gtest.h>
 
-#include <unwindstack/Memory.h>
-
+#include "MemoryCache.h"
 #include "MemoryFake.h"
 
 namespace unwindstack {
diff --git a/libunwindstack/tests/MemoryFileTest.cpp b/libunwindstack/tests/MemoryFileTest.cpp
index d7d1ace..4124a49 100644
--- a/libunwindstack/tests/MemoryFileTest.cpp
+++ b/libunwindstack/tests/MemoryFileTest.cpp
@@ -21,7 +21,7 @@
 #include <android-base/file.h>
 #include <gtest/gtest.h>
 
-#include <unwindstack/Memory.h>
+#include "MemoryFileAtOffset.h"
 
 namespace unwindstack {
 
diff --git a/libunwindstack/tests/MemoryLocalTest.cpp b/libunwindstack/tests/MemoryLocalTest.cpp
index 5a389d0..c9e5dc0 100644
--- a/libunwindstack/tests/MemoryLocalTest.cpp
+++ b/libunwindstack/tests/MemoryLocalTest.cpp
@@ -22,7 +22,7 @@
 
 #include <gtest/gtest.h>
 
-#include <unwindstack/Memory.h>
+#include "MemoryLocal.h"
 
 namespace unwindstack {
 
diff --git a/libunwindstack/tests/MemoryOfflineBufferTest.cpp b/libunwindstack/tests/MemoryOfflineBufferTest.cpp
index f022884..c62c53d 100644
--- a/libunwindstack/tests/MemoryOfflineBufferTest.cpp
+++ b/libunwindstack/tests/MemoryOfflineBufferTest.cpp
@@ -18,9 +18,8 @@
 
 #include <gtest/gtest.h>
 
-#include <unwindstack/Memory.h>
-
 #include "LogFake.h"
+#include "MemoryOfflineBuffer.h"
 
 namespace unwindstack {
 
diff --git a/libunwindstack/tests/MemoryOfflineTest.cpp b/libunwindstack/tests/MemoryOfflineTest.cpp
index ab9aa9d..d0c441b 100644
--- a/libunwindstack/tests/MemoryOfflineTest.cpp
+++ b/libunwindstack/tests/MemoryOfflineTest.cpp
@@ -19,7 +19,8 @@
 #include <gtest/gtest.h>
 
 #include <android-base/file.h>
-#include <unwindstack/Memory.h>
+
+#include "MemoryOffline.h"
 
 namespace unwindstack {
 
diff --git a/libunwindstack/tests/MemoryRangeTest.cpp b/libunwindstack/tests/MemoryRangeTest.cpp
index 2bac95b..2d4f141 100644
--- a/libunwindstack/tests/MemoryRangeTest.cpp
+++ b/libunwindstack/tests/MemoryRangeTest.cpp
@@ -21,9 +21,8 @@
 
 #include <gtest/gtest.h>
 
-#include <unwindstack/Memory.h>
-
 #include "MemoryFake.h"
+#include "MemoryRange.h"
 
 namespace unwindstack {
 
diff --git a/libunwindstack/tests/MemoryRangesTest.cpp b/libunwindstack/tests/MemoryRangesTest.cpp
index d24fcd2..e4e9fc4 100644
--- a/libunwindstack/tests/MemoryRangesTest.cpp
+++ b/libunwindstack/tests/MemoryRangesTest.cpp
@@ -20,9 +20,8 @@
 
 #include <gtest/gtest.h>
 
-#include <unwindstack/Memory.h>
-
 #include "MemoryFake.h"
+#include "MemoryRange.h"
 
 namespace unwindstack {
 
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index fb56e8a..c90dedc 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -30,7 +30,7 @@
 #include <android-base/file.h>
 #include <gtest/gtest.h>
 
-#include <unwindstack/Memory.h>
+#include "MemoryRemote.h"
 
 #include "MemoryFake.h"
 #include "TestUtils.h"
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 553b344..baada82 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -35,7 +35,6 @@
 #include <unwindstack/MachineX86.h>
 #include <unwindstack/MachineX86_64.h>
 #include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
 #include <unwindstack/RegsArm.h>
 #include <unwindstack/RegsArm64.h>
 #include <unwindstack/RegsX86.h>
@@ -43,6 +42,7 @@
 #include <unwindstack/Unwinder.h>
 
 #include "ElfTestUtils.h"
+#include "MemoryOffline.h"
 #include "TestUtils.h"
 
 namespace unwindstack {
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 4e38015..f76a101 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -35,11 +35,11 @@
 #include <android-base/threads.h>
 
 #include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
 #include <unwindstack/RegsGetLocal.h>
 #include <unwindstack/Unwinder.h>
 
+#include "MemoryRemote.h"
 #include "TestUtils.h"
 
 namespace unwindstack {
diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
index 92e5c0a..7a6d8ba 100644
--- a/libunwindstack/tools/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -31,6 +31,7 @@
 #include <unwindstack/Elf.h>
 #include <unwindstack/ElfInterface.h>
 #include <unwindstack/Log.h>
+#include <unwindstack/Memory.h>
 
 #include "ArmExidx.h"
 #include "ElfInterfaceArm.h"
@@ -105,14 +106,7 @@
   // Send all log messages to stdout.
   log_to_stdout(true);
 
-  MemoryFileAtOffset* memory = new MemoryFileAtOffset;
-  if (!memory->Init(file, offset)) {
-    // Initializatation failed.
-    printf("Failed to init\n");
-    return 1;
-  }
-
-  Elf elf(memory);
+  Elf elf(Memory::CreateFileMemory(file, offset).release());
   if (!elf.Init() || !elf.valid()) {
     printf("%s is not a valid elf file.\n", file);
     return 1;
diff --git a/libunwindstack/tools/unwind_reg_info.cpp b/libunwindstack/tools/unwind_reg_info.cpp
index b77a86b..d0562d9 100644
--- a/libunwindstack/tools/unwind_reg_info.cpp
+++ b/libunwindstack/tools/unwind_reg_info.cpp
@@ -33,6 +33,7 @@
 #include <unwindstack/Elf.h>
 #include <unwindstack/ElfInterface.h>
 #include <unwindstack/Log.h>
+#include <unwindstack/Memory.h>
 
 #include "ArmExidx.h"
 #include "DwarfOp.h"
@@ -165,14 +166,7 @@
 }
 
 int GetInfo(const char* file, uint64_t pc) {
-  MemoryFileAtOffset* memory = new MemoryFileAtOffset;
-  if (!memory->Init(file, 0)) {
-    // Initializatation failed.
-    printf("Failed to init\n");
-    return 1;
-  }
-
-  Elf elf(memory);
+  Elf elf(Memory::CreateFileMemory(file, pc).release());
   if (!elf.Init() || !elf.valid()) {
     printf("%s is not a valid elf file.\n", file);
     return 1;
@@ -205,7 +199,7 @@
   DwarfSection* section = interface->eh_frame();
   if (section != nullptr) {
     printf("\neh_frame:\n");
-    PrintRegInformation(section, memory, pc, elf.class_type());
+    PrintRegInformation(section, elf.memory(), pc, elf.class_type());
   } else {
     printf("\nno eh_frame information\n");
   }
@@ -213,7 +207,7 @@
   section = interface->debug_frame();
   if (section != nullptr) {
     printf("\ndebug_frame:\n");
-    PrintRegInformation(section, memory, pc, elf.class_type());
+    PrintRegInformation(section, elf.memory(), pc, elf.class_type());
     printf("\n");
   } else {
     printf("\nno debug_frame information\n");
diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp
index b0a4dd0..8df2284 100644
--- a/libunwindstack/tools/unwind_symbols.cpp
+++ b/libunwindstack/tools/unwind_symbols.cpp
@@ -59,13 +59,7 @@
   // Send all log messages to stdout.
   unwindstack::log_to_stdout(true);
 
-  unwindstack::MemoryFileAtOffset* memory = new unwindstack::MemoryFileAtOffset;
-  if (!memory->Init(argv[1], 0)) {
-    printf("Failed to init\n");
-    return 1;
-  }
-
-  unwindstack::Elf elf(memory);
+  unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(argv[1], 0).release());
   if (!elf.Init() || !elf.valid()) {
     printf("%s is not a valid elf file.\n", argv[1]);
     return 1;