Merge "Fix offsets when shared lib split across maps."
am: 1baa19b1a6

Change-Id: I05884b4b1dbd604c4c2bdec961bf51c376ef6ba1
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index fe28eba..f5f9b2a 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -117,7 +117,7 @@
     back_frame->map.name = frame->map_name;
     back_frame->map.start = frame->map_start;
     back_frame->map.end = frame->map_end;
-    back_frame->map.offset = frame->map_offset;
+    back_frame->map.offset = frame->map_elf_start_offset;
     back_frame->map.load_bias = frame->map_load_bias;
     back_frame->map.flags = frame->map_flags;
   }
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 44ec5c1..39a09cf 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -32,33 +32,27 @@
 bool MapInfo::InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory) {
   // One last attempt, see if the previous map is read-only with the
   // same name and stretches across this map.
-  for (auto iter = maps_->begin(); iter != maps_->end(); ++iter) {
-    if (*iter == this) {
-      if (iter == maps_->begin()) {
-        return false;
-      }
-      --iter;
-      MapInfo* prev_map = *iter;
-      // Make sure this is a read-only map.
-      if (prev_map->flags != PROT_READ) {
-        return false;
-      }
-      uint64_t map_size = end - prev_map->end;
-      if (!memory->Init(name, prev_map->offset, map_size)) {
-        return false;
-      }
-      uint64_t max_size;
-      if (!Elf::GetInfo(memory, &max_size) || max_size < map_size) {
-        return false;
-      }
-      if (!memory->Init(name, prev_map->offset, max_size)) {
-        return false;
-      }
-      elf_offset = offset - prev_map->offset;
-      return true;
-    }
+  if (prev_map == nullptr || prev_map->flags != PROT_READ) {
+    return false;
   }
-  return false;
+
+  uint64_t map_size = end - prev_map->end;
+  if (!memory->Init(name, prev_map->offset, map_size)) {
+    return false;
+  }
+
+  uint64_t max_size;
+  if (!Elf::GetInfo(memory, &max_size) || max_size < map_size) {
+    return false;
+  }
+
+  if (!memory->Init(name, prev_map->offset, max_size)) {
+    return false;
+  }
+
+  elf_offset = offset - prev_map->offset;
+  elf_start_offset = prev_map->offset;
+  return true;
 }
 
 Memory* MapInfo::GetFileMemory() {
@@ -91,14 +85,13 @@
 
   // Check if the start of this map is an embedded elf.
   uint64_t max_size = 0;
-  uint64_t file_offset = offset;
   if (Elf::GetInfo(memory.get(), &max_size)) {
     if (max_size > map_size) {
-      if (memory->Init(name, file_offset, max_size)) {
+      if (memory->Init(name, offset, max_size)) {
         return memory.release();
       }
       // Try to reinit using the default map_size.
-      if (memory->Init(name, file_offset, map_size)) {
+      if (memory->Init(name, offset, map_size)) {
         return memory.release();
       }
       return nullptr;
@@ -109,6 +102,13 @@
   // No elf at offset, try to init as if the whole file is an elf.
   if (memory->Init(name, 0) && Elf::IsValidElf(memory.get())) {
     elf_offset = offset;
+    // Need to check how to set the elf start offset. If this map is not
+    // the r-x map of a r-- map, then use the real offset value. Otherwise,
+    // use 0.
+    if (prev_map == nullptr || prev_map->offset != 0 || prev_map->flags != PROT_READ ||
+        prev_map->name != name) {
+      elf_start_offset = offset;
+    }
     return memory.release();
   }
 
@@ -156,35 +156,24 @@
     return memory.release();
   }
 
-  if (name.empty() || maps_ == nullptr) {
-    return nullptr;
-  }
-
   // Find the read-only map by looking at the previous map. The linker
   // doesn't guarantee that this invariant will always be true. However,
   // if that changes, there is likely something else that will change and
   // break something.
-  MapInfo* ro_map_info = nullptr;
-  for (auto iter = maps_->begin(); iter != maps_->end(); ++iter) {
-    if (*iter == this) {
-      if (iter != maps_->begin()) {
-        --iter;
-        ro_map_info = *iter;
-      }
-      break;
-    }
-  }
-
-  if (ro_map_info == nullptr || ro_map_info->name != name || ro_map_info->offset >= offset) {
+  if (offset == 0 || name.empty() || prev_map == nullptr || prev_map->name != name ||
+      prev_map->offset >= offset) {
     return nullptr;
   }
 
   // Make sure that relative pc values are corrected properly.
-  elf_offset = offset - ro_map_info->offset;
+  elf_offset = offset - prev_map->offset;
+  // Use this as the elf start offset, otherwise, you always get offsets into
+  // the r-x section, which is not quite the right information.
+  elf_start_offset = prev_map->offset;
 
   MemoryRanges* ranges = new MemoryRanges;
-  ranges->Insert(new MemoryRange(process_memory, ro_map_info->start,
-                                 ro_map_info->end - ro_map_info->start, 0));
+  ranges->Insert(
+      new MemoryRange(process_memory, prev_map->start, prev_map->end - prev_map->start, 0));
   ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset));
 
   return ranges;
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index a9fb859..c90e383 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -67,13 +67,15 @@
         if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
           flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
         }
-        maps_.push_back(new MapInfo(this, start, end, pgoff, flags, name));
+        maps_.push_back(
+            new MapInfo(maps_.empty() ? nullptr : maps_.back(), start, end, pgoff, flags, name));
       });
 }
 
 void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
                const std::string& name, uint64_t load_bias) {
-  MapInfo* map_info = new MapInfo(this, start, end, offset, flags, name);
+  MapInfo* map_info =
+      new MapInfo(maps_.empty() ? nullptr : maps_.back(), start, end, offset, flags, name);
   map_info->load_bias = load_bias;
   maps_.push_back(map_info);
 }
@@ -81,6 +83,13 @@
 void Maps::Sort() {
   std::sort(maps_.begin(), maps_.end(),
             [](const MapInfo* a, const MapInfo* b) { return a->start < b->start; });
+
+  // Set the prev_map values on the info objects.
+  MapInfo* prev_map = nullptr;
+  for (MapInfo* map_info : maps_) {
+    map_info->prev_map = prev_map;
+    prev_map = map_info;
+  }
 }
 
 Maps::~Maps() {
@@ -98,7 +107,8 @@
         if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
           flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
         }
-        maps_.push_back(new MapInfo(this, start, end, pgoff, flags, name));
+        maps_.push_back(
+            new MapInfo(maps_.empty() ? nullptr : maps_.back(), start, end, pgoff, flags, name));
       });
 }
 
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 792cd0b..8133639 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -59,7 +59,8 @@
   if (info != nullptr) {
     frame->map_start = info->start;
     frame->map_end = info->end;
-    frame->map_offset = info->offset;
+    frame->map_elf_start_offset = info->elf_start_offset;
+    frame->map_exact_offset = info->offset;
     frame->map_load_bias = info->load_bias;
     frame->map_flags = info->flags;
     if (resolve_names_) {
@@ -102,7 +103,8 @@
   if (resolve_names_) {
     frame->map_name = map_info->name;
   }
-  frame->map_offset = map_info->offset;
+  frame->map_elf_start_offset = map_info->elf_start_offset;
+  frame->map_exact_offset = map_info->offset;
   frame->map_start = map_info->start;
   frame->map_end = map_info->end;
   frame->map_flags = map_info->flags;
@@ -290,10 +292,6 @@
     data += android::base::StringPrintf("  #%02zu pc %016" PRIx64, frame.num, frame.rel_pc);
   }
 
-  if (frame.map_offset != 0) {
-    data += android::base::StringPrintf(" (offset 0x%" PRIx64 ")", frame.map_offset);
-  }
-
   if (frame.map_start == frame.map_end) {
     // No valid map associated with this frame.
     data += "  <unknown>";
@@ -302,6 +300,11 @@
   } else {
     data += android::base::StringPrintf("  <anonymous:%" PRIx64 ">", frame.map_start);
   }
+
+  if (frame.map_elf_start_offset != 0) {
+    data += android::base::StringPrintf(" (offset 0x%" PRIx64 ")", frame.map_elf_start_offset);
+  }
+
   if (!frame.function_name.empty()) {
     data += " (" + frame.function_name;
     if (frame.function_offset != 0) {
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index cfdefd0..5e3d6f6 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -25,38 +25,31 @@
 #include <string>
 
 #include <unwindstack/Elf.h>
+#include <unwindstack/Memory.h>
 
 namespace unwindstack {
 
-// Forward declarations.
-class Maps;
-class Memory;
-
 struct MapInfo {
-  MapInfo(Maps* maps) : maps_(maps) {}
-  MapInfo(Maps* maps, uint64_t start, uint64_t end) : maps_(maps), start(start), end(end) {}
-  MapInfo(Maps* maps, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
+  MapInfo(MapInfo* map_info, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
           const char* name)
-      : maps_(maps),
-        start(start),
+      : start(start),
         end(end),
         offset(offset),
         flags(flags),
         name(name),
+        prev_map(map_info),
         load_bias(static_cast<uint64_t>(-1)) {}
-  MapInfo(Maps* maps, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
+  MapInfo(MapInfo* map_info, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
           const std::string& name)
-      : maps_(maps),
-        start(start),
+      : start(start),
         end(end),
         offset(offset),
         flags(flags),
         name(name),
+        prev_map(map_info),
         load_bias(static_cast<uint64_t>(-1)) {}
   ~MapInfo() = default;
 
-  Maps* maps_ = nullptr;
-
   uint64_t start = 0;
   uint64_t end = 0;
   uint64_t offset = 0;
@@ -64,10 +57,14 @@
   std::string name;
   std::shared_ptr<Elf> elf;
   // This value is only non-zero if the offset is non-zero but there is
-  // no elf signature found at that offset. This indicates that the
-  // entire file is represented by the Memory object returned by CreateMemory,
-  // instead of a portion of the file.
+  // no elf signature found at that offset.
   uint64_t elf_offset = 0;
+  // This value is the offset from the map in memory that is the start
+  // of the elf. This is not equal to offset when the linker splits
+  // shared libraries into a read-only and read-execute map.
+  uint64_t elf_start_offset = 0;
+
+  MapInfo* prev_map = nullptr;
 
   std::atomic_uint64_t load_bias;
 
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 56b0581..d7bbd9d 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -48,7 +48,13 @@
   uint64_t function_offset = 0;
 
   std::string map_name;
-  uint64_t map_offset = 0;
+  // The offset from the first map representing the frame. When there are
+  // two maps (read-only and read-execute) this will be the offset from
+  // the read-only map. When there is only one map, this will be the
+  // same as the actual offset of the map and match map_exact_offset.
+  uint64_t map_elf_start_offset = 0;
+  // The actual offset from the map where the pc lies.
+  uint64_t map_exact_offset = 0;
   uint64_t map_start = 0;
   uint64_t map_end = 0;
   uint64_t map_load_bias = 0;
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 7766218..f7689ce 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -269,7 +269,7 @@
   elf.FakeSetInterface(interface);
 
   elf.FakeSetValid(true);
-  MapInfo map_info(nullptr, 0x1000, 0x2000);
+  MapInfo map_info(nullptr, 0x1000, 0x2000, 0, 0, "");
 
   ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
 
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 943b3c9..a66685a 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -118,6 +118,7 @@
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
   ASSERT_EQ(0x100U, info.elf_offset);
+  EXPECT_EQ(0x100U, info.elf_start_offset);
 
   // Read the entire file.
   std::vector<uint8_t> buffer(1024);
@@ -129,6 +130,44 @@
   }
 
   ASSERT_FALSE(memory->ReadFully(1024, buffer.data(), 1));
+
+  // Now verify the elf start offset is set correctly based on the previous
+  // info.
+  MapInfo prev_info(nullptr, 0, 0x100, 0x10, 0, "");
+  info.prev_map = &prev_info;
+
+  // No preconditions met, change each one until it should set the elf start
+  // offset to zero.
+  info.elf_offset = 0;
+  info.elf_start_offset = 0;
+  memory.reset(info.CreateMemory(process_memory_));
+  ASSERT_TRUE(memory.get() != nullptr);
+  ASSERT_EQ(0x100U, info.elf_offset);
+  EXPECT_EQ(0x100U, info.elf_start_offset);
+
+  prev_info.offset = 0;
+  info.elf_offset = 0;
+  info.elf_start_offset = 0;
+  memory.reset(info.CreateMemory(process_memory_));
+  ASSERT_TRUE(memory.get() != nullptr);
+  ASSERT_EQ(0x100U, info.elf_offset);
+  EXPECT_EQ(0x100U, info.elf_start_offset);
+
+  prev_info.flags = PROT_READ;
+  info.elf_offset = 0;
+  info.elf_start_offset = 0;
+  memory.reset(info.CreateMemory(process_memory_));
+  ASSERT_TRUE(memory.get() != nullptr);
+  ASSERT_EQ(0x100U, info.elf_offset);
+  EXPECT_EQ(0x100U, info.elf_start_offset);
+
+  prev_info.name = info.name;
+  info.elf_offset = 0;
+  info.elf_start_offset = 0;
+  memory.reset(info.CreateMemory(process_memory_));
+  ASSERT_TRUE(memory.get() != nullptr);
+  ASSERT_EQ(0x100U, info.elf_offset);
+  EXPECT_EQ(0U, info.elf_start_offset);
 }
 
 // Verify that if the offset is non-zero and there is an elf at that
@@ -139,6 +178,7 @@
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
+  EXPECT_EQ(0U, info.elf_start_offset);
 
   // Read the valid part of the file.
   std::vector<uint8_t> buffer(0x100);
@@ -162,6 +202,7 @@
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
+  EXPECT_EQ(0U, info.elf_start_offset);
 
   // Verify the memory is a valid elf.
   uint8_t e_ident[SELFMAG + 1];
@@ -178,6 +219,7 @@
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
+  EXPECT_EQ(0U, info.elf_start_offset);
 
   // Verify the memory is a valid elf.
   uint8_t e_ident[SELFMAG + 1];
@@ -250,6 +292,7 @@
   ASSERT_TRUE(mem.get() != nullptr);
   EXPECT_EQ(0x4000UL, map_info->elf_offset);
   EXPECT_EQ(0x4000UL, map_info->offset);
+  EXPECT_EQ(0U, map_info->elf_start_offset);
 
   // Verify that reading values from this memory works properly.
   std::vector<uint8_t> buffer(0x4000);
@@ -295,6 +338,7 @@
   ASSERT_TRUE(mem.get() != nullptr);
   EXPECT_EQ(0x1000UL, map_info->elf_offset);
   EXPECT_EQ(0xb000UL, map_info->offset);
+  EXPECT_EQ(0xa000UL, map_info->elf_start_offset);
 
   // Verify that reading values from this memory works properly.
   std::vector<uint8_t> buffer(0x4000);
@@ -333,6 +377,7 @@
   std::vector<uint8_t> buffer(0x100);
   EXPECT_EQ(0x2000U, map_info->offset);
   EXPECT_EQ(0U, map_info->elf_offset);
+  EXPECT_EQ(0U, map_info->elf_start_offset);
   ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 0x100));
   EXPECT_EQ(0xffU, buffer[0]);
 
@@ -346,6 +391,7 @@
   memory.reset(map_info->CreateMemory(process_memory_));
   EXPECT_EQ(0x2000U, map_info->offset);
   EXPECT_EQ(0x1000U, map_info->elf_offset);
+  EXPECT_EQ(0x1000U, map_info->elf_start_offset);
   Elf64_Ehdr ehdr_mem;
   ASSERT_TRUE(memory->ReadFully(0, &ehdr_mem, sizeof(ehdr_mem)));
   EXPECT_TRUE(memcmp(&ehdr, &ehdr_mem, sizeof(ehdr)) == 0);
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
index 80e292a..b4197f2 100644
--- a/libunwindstack/tests/MapsTest.cpp
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -62,7 +62,7 @@
 }
 
 TEST(MapsTest, verify_parse_line) {
-  MapInfo info(nullptr);
+  MapInfo info(nullptr, 0, 0, 0, 0, "");
 
   VerifyLine("01-02 rwxp 03 04:05 06\n", &info);
   EXPECT_EQ(1U, info.start);
@@ -135,7 +135,7 @@
 }
 
 TEST(MapsTest, verify_large_values) {
-  MapInfo info(nullptr);
+  MapInfo info(nullptr, 0, 0, 0, 0, "");
 #if defined(__LP64__)
   VerifyLine("fabcdef012345678-f12345678abcdef8 rwxp f0b0d0f010305070 00:00 0\n", &info);
   EXPECT_EQ(0xfabcdef012345678UL, info.start);
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 00264c2..472d1cf 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -182,7 +182,7 @@
   RegsX86_64 regs_x86_64;
   RegsMips regs_mips;
   RegsMips64 regs_mips64;
-  MapInfo map_info(nullptr, 0x1000, 0x2000);
+  MapInfo map_info(nullptr, 0x1000, 0x2000, 0, 0, "");
   Elf* invalid_elf = new Elf(nullptr);
   map_info.elf.reset(invalid_elf);
 
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index dc015b4..aab9ec2 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -298,7 +298,7 @@
   EXPECT_EQ(
       "  #00 pc 00068fb8  libarttestd.so (_ZN3artL13CauseSegfaultEv+72)\n"
       "  #01 pc 00067f00  libarttestd.so (Java_Main_unwindInProcess+10032)\n"
-      "  #02 pc 000021a8 (offset 0x2000)  137-cfi.odex (boolean Main.unwindInProcess(boolean, int, "
+      "  #02 pc 000021a8  137-cfi.odex (offset 0x2000) (boolean Main.unwindInProcess(boolean, int, "
       "boolean)+136)\n"
       "  #03 pc 0000fe80  anonymous:ee74c000 (boolean Main.bar(boolean)+64)\n"
       "  #04 pc 006ad4d2  libartd.so (art_quick_invoke_stub+338)\n"
@@ -591,7 +591,7 @@
   ASSERT_EQ(76U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
   EXPECT_EQ(
       "  #00 pc 00018a5e  libarttestd.so (Java_Main_unwindInProcess+866)\n"
-      "  #01 pc 0000212d (offset 0x2000)  137-cfi.odex (boolean Main.unwindInProcess(boolean, int, "
+      "  #01 pc 0000212d  137-cfi.odex (offset 0x2000) (boolean Main.unwindInProcess(boolean, int, "
       "boolean)+92)\n"
       "  #02 pc 00011cb1  anonymous:e2796000 (boolean Main.bar(boolean)+72)\n"
       "  #03 pc 00462175  libartd.so (art_quick_invoke_stub_internal+68)\n"
@@ -1135,29 +1135,29 @@
   std::string frame_info(DumpFrames(unwinder));
   ASSERT_EQ(19U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
   EXPECT_EQ(
-      "  #00 pc 0032bfa0 (offset 0x42000)  libunwindstack_test (SignalInnerFunction+40)\n"
-      "  #01 pc 0032bfeb (offset 0x42000)  libunwindstack_test (SignalMiddleFunction+2)\n"
-      "  #02 pc 0032bff3 (offset 0x42000)  libunwindstack_test (SignalOuterFunction+2)\n"
-      "  #03 pc 0032fed3 (offset 0x42000)  libunwindstack_test "
+      "  #00 pc 0032bfa0  libunwindstack_test (SignalInnerFunction+40)\n"
+      "  #01 pc 0032bfeb  libunwindstack_test (SignalMiddleFunction+2)\n"
+      "  #02 pc 0032bff3  libunwindstack_test (SignalOuterFunction+2)\n"
+      "  #03 pc 0032fed3  libunwindstack_test "
       "(_ZN11unwindstackL19SignalCallerHandlerEiP7siginfoPv+26)\n"
-      "  #04 pc 00026528 (offset 0x25000)  libc.so\n"
+      "  #04 pc 00026528  libc.so\n"
       "  #05 pc 00000000  <unknown>\n"
-      "  #06 pc 0032c2d9 (offset 0x42000)  libunwindstack_test (InnerFunction+736)\n"
-      "  #07 pc 0032cc4f (offset 0x42000)  libunwindstack_test (MiddleFunction+42)\n"
-      "  #08 pc 0032cc81 (offset 0x42000)  libunwindstack_test (OuterFunction+42)\n"
-      "  #09 pc 0032e547 (offset 0x42000)  libunwindstack_test "
+      "  #06 pc 0032c2d9  libunwindstack_test (InnerFunction+736)\n"
+      "  #07 pc 0032cc4f  libunwindstack_test (MiddleFunction+42)\n"
+      "  #08 pc 0032cc81  libunwindstack_test (OuterFunction+42)\n"
+      "  #09 pc 0032e547  libunwindstack_test "
       "(_ZN11unwindstackL19RemoteThroughSignalEij+270)\n"
-      "  #10 pc 0032ed99 (offset 0x42000)  libunwindstack_test "
+      "  #10 pc 0032ed99  libunwindstack_test "
       "(_ZN11unwindstack55UnwindTest_remote_through_signal_with_invalid_func_Test8TestBodyEv+16)\n"
-      "  #11 pc 00354453 (offset 0x42000)  libunwindstack_test (_ZN7testing4Test3RunEv+154)\n"
-      "  #12 pc 00354de7 (offset 0x42000)  libunwindstack_test (_ZN7testing8TestInfo3RunEv+194)\n"
-      "  #13 pc 00355105 (offset 0x42000)  libunwindstack_test (_ZN7testing8TestCase3RunEv+180)\n"
-      "  #14 pc 0035a215 (offset 0x42000)  libunwindstack_test "
+      "  #11 pc 00354453  libunwindstack_test (_ZN7testing4Test3RunEv+154)\n"
+      "  #12 pc 00354de7  libunwindstack_test (_ZN7testing8TestInfo3RunEv+194)\n"
+      "  #13 pc 00355105  libunwindstack_test (_ZN7testing8TestCase3RunEv+180)\n"
+      "  #14 pc 0035a215  libunwindstack_test "
       "(_ZN7testing8internal12UnitTestImpl11RunAllTestsEv+664)\n"
-      "  #15 pc 00359f4f (offset 0x42000)  libunwindstack_test (_ZN7testing8UnitTest3RunEv+110)\n"
-      "  #16 pc 0034d3db (offset 0x42000)  libunwindstack_test (main+38)\n"
-      "  #17 pc 00092c0d (offset 0x25000)  libc.so (__libc_init+48)\n"
-      "  #18 pc 0004202f (offset 0x42000)  libunwindstack_test (_start_main+38)\n",
+      "  #15 pc 00359f4f  libunwindstack_test (_ZN7testing8UnitTest3RunEv+110)\n"
+      "  #16 pc 0034d3db  libunwindstack_test (main+38)\n"
+      "  #17 pc 00092c0d  libc.so (__libc_init+48)\n"
+      "  #18 pc 0004202f  libunwindstack_test (_start_main+38)\n",
       frame_info);
 
   EXPECT_EQ(0x2e55fa0U, unwinder.frames()[0].pc);
@@ -1248,14 +1248,14 @@
   std::string frame_info(DumpFrames(unwinder));
   ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
   EXPECT_EQ(
-      "  #00 pc 000000000014ccbc (offset 0x39000)  linker64 (__dl_syscall+28)\n"
-      "  #01 pc 000000000005426c (offset 0x39000)  linker64 "
+      "  #00 pc 000000000014ccbc  linker64 (__dl_syscall+28)\n"
+      "  #01 pc 000000000005426c  linker64 "
       "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
       "  #02 pc 00000000000008bc  vdso.so\n"
-      "  #03 pc 00000000000846f4 (offset 0x40000)  libc.so (abort+172)\n"
-      "  #04 pc 0000000000084ad4 (offset 0x40000)  libc.so (__assert2+36)\n"
-      "  #05 pc 000000000003d5b4 (offset 0x40000)  ANGLEPrebuilt.apk (ANGLEGetUtilityAPI+56)\n"
-      "  #06 pc 000000000007fe68 (offset 0x40000)  libc.so (__libc_init)\n",
+      "  #03 pc 00000000000846f4  libc.so (abort+172)\n"
+      "  #04 pc 0000000000084ad4  libc.so (__assert2+36)\n"
+      "  #05 pc 000000000003d5b4  ANGLEPrebuilt.apk (offset 0x4000) (ANGLEGetUtilityAPI+56)\n"
+      "  #06 pc 000000000007fe68  libc.so (__libc_init)\n",
       frame_info);
 
   EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc);
@@ -1287,14 +1287,14 @@
   std::string frame_info(DumpFrames(unwinder));
   ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
   EXPECT_EQ(
-      "  #00 pc 000000000014ccbc (offset 0x39000)  linker64 (__dl_syscall+28)\n"
-      "  #01 pc 000000000005426c (offset 0x39000)  linker64 "
+      "  #00 pc 000000000014ccbc  linker64 (__dl_syscall+28)\n"
+      "  #01 pc 000000000005426c  linker64 "
       "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
       "  #02 pc 00000000000008bc  vdso.so\n"
-      "  #03 pc 00000000000846f4 (offset 0x40000)  libc.so (abort+172)\n"
-      "  #04 pc 0000000000084ad4 (offset 0x40000)  libc.so (__assert2+36)\n"
-      "  #05 pc 000000000003d5b4 (offset 0x2211000)  ANGLEPrebuilt.apk\n"
-      "  #06 pc 000000000007fe68 (offset 0x40000)  libc.so (__libc_init)\n",
+      "  #03 pc 00000000000846f4  libc.so (abort+172)\n"
+      "  #04 pc 0000000000084ad4  libc.so (__assert2+36)\n"
+      "  #05 pc 000000000003d5b4  ANGLEPrebuilt.apk (offset 0x21d5000)\n"
+      "  #06 pc 000000000007fe68  libc.so (__libc_init)\n",
       frame_info);
 
   EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc);
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index c4b8763..1fdeee5 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -42,84 +42,64 @@
 
 namespace unwindstack {
 
-class MapsFake : public Maps {
- public:
-  MapsFake() = default;
-  virtual ~MapsFake() = default;
-
-  bool Parse() { return true; }
-
-  void FakeClear() { maps_.clear(); }
-
-  void FakeAddMapInfo(MapInfo* map_info) { maps_.push_back(map_info); }
-};
-
 class UnwinderTest : public ::testing::Test {
  protected:
+  static void AddMapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
+                         const char* name, Elf* elf = nullptr) {
+    std::string str_name(name);
+    maps_->Add(start, end, offset, flags, name, static_cast<uint64_t>(-1));
+    if (elf != nullptr) {
+      MapInfo* map_info = *--maps_->end();
+      map_info->elf.reset(elf);
+    }
+  }
+
   static void SetUpTestCase() {
-    maps_.FakeClear();
-    MapInfo* info =
-        new MapInfo(&maps_, 0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so");
+    maps_.reset(new Maps);
+
     ElfFake* elf = new ElfFake(new MemoryFake);
-    info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
-    maps_.FakeAddMapInfo(info);
+    AddMapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so", elf);
 
-    info = new MapInfo(&maps_, 0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
-    maps_.FakeAddMapInfo(info);
+    AddMapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
 
-    info = new MapInfo(&maps_, 0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP,
-                       "/dev/fake_device");
-    maps_.FakeAddMapInfo(info);
+    AddMapInfo(0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP,
+               "/dev/fake_device");
 
-    info = new MapInfo(&maps_, 0x20000, 0x22000, 0, PROT_READ | PROT_WRITE,
-                       "/system/fake/libunwind.so");
     elf = new ElfFake(new MemoryFake);
-    info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
-    maps_.FakeAddMapInfo(info);
+    AddMapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so", elf);
 
-    info = new MapInfo(&maps_, 0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so");
     elf = new ElfFake(new MemoryFake);
-    info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
-    maps_.FakeAddMapInfo(info);
+    AddMapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so", elf);
 
-    info = new MapInfo(&maps_, 0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so");
     elf = new ElfFake(new MemoryFake);
-    info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
-    maps_.FakeAddMapInfo(info);
+    AddMapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so", elf);
 
-    info = new MapInfo(&maps_, 0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk");
     elf = new ElfFake(new MemoryFake);
-    info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
-    maps_.FakeAddMapInfo(info);
+    AddMapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk", elf);
 
-    info = new MapInfo(&maps_, 0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
-    maps_.FakeAddMapInfo(info);
+    AddMapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
 
-    info = new MapInfo(&maps_, 0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
-                       "/fake/fake.vdex");
+    AddMapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex");
+    MapInfo* info = *--maps_->end();
     info->load_bias = 0;
-    maps_.FakeAddMapInfo(info);
 
-    info = new MapInfo(&maps_, 0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
-                       "/fake/fake_load_bias.so");
     elf = new ElfFake(new MemoryFake);
-    info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     elf->FakeSetLoadBias(0x5000);
-    maps_.FakeAddMapInfo(info);
+    AddMapInfo(0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake_load_bias.so",
+               elf);
 
-    info = new MapInfo(&maps_, 0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
-                       "/fake/fake_offset.oat");
     elf = new ElfFake(new MemoryFake);
-    info->elf.reset(elf);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    AddMapInfo(0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake_offset.oat",
+               elf);
+    info = *--maps_->end();
     info->elf_offset = 0x8000;
-    maps_.FakeAddMapInfo(info);
 
     process_memory_.reset(new MemoryFake);
   }
@@ -130,12 +110,12 @@
     regs_.FakeSetReturnAddressValid(false);
   }
 
-  static MapsFake maps_;
+  static std::unique_ptr<Maps> maps_;
   static RegsFake regs_;
   static std::shared_ptr<Memory> process_memory_;
 };
 
-MapsFake UnwinderTest::maps_;
+std::unique_ptr<Maps> UnwinderTest::maps_;
 RegsFake UnwinderTest::regs_(5);
 std::shared_ptr<Memory> UnwinderTest::process_memory_(nullptr);
 
@@ -150,7 +130,7 @@
   ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
@@ -164,7 +144,8 @@
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/system/fake/libc.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -178,7 +159,8 @@
   EXPECT_EQ("Frame1", frame->function_name);
   EXPECT_EQ(1U, frame->function_offset);
   EXPECT_EQ("/system/fake/libc.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -192,7 +174,8 @@
   EXPECT_EQ("Frame2", frame->function_name);
   EXPECT_EQ(2U, frame->function_offset);
   EXPECT_EQ("/system/fake/libc.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -210,7 +193,7 @@
   ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.SetResolveNames(false);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -225,7 +208,8 @@
   EXPECT_EQ("", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -239,7 +223,8 @@
   EXPECT_EQ("", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -253,7 +238,8 @@
   EXPECT_EQ("", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -267,7 +253,7 @@
   regs_.set_sp(0x10000);
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
@@ -281,7 +267,8 @@
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/fake/fake_load_bias.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0xa5000U, frame->map_start);
   EXPECT_EQ(0xa6000U, frame->map_end);
   EXPECT_EQ(0x5000U, frame->map_load_bias);
@@ -295,7 +282,7 @@
   regs_.set_sp(0x10000);
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
@@ -309,7 +296,8 @@
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/fake/fake_offset.oat", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0xa7000U, frame->map_start);
   EXPECT_EQ(0xa8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -323,7 +311,7 @@
   regs_.set_sp(0x10000);
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
@@ -337,7 +325,8 @@
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/fake/fake.apk", frame->map_name);
-  EXPECT_EQ(0x1d000U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0x1d000U, frame->map_exact_offset);
   EXPECT_EQ(0x43000U, frame->map_start);
   EXPECT_EQ(0x44000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -358,7 +347,7 @@
   ElfInterfaceFake::FakePushStepData(StepData(0x1102, 0x10010, false));
   ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false));
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
@@ -372,7 +361,8 @@
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/system/fake/libc.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -389,7 +379,7 @@
   regs_.set_pc(0x1000);
   regs_.set_sp(0x10000);
 
-  Unwinder unwinder(20, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(20, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
 
@@ -404,7 +394,8 @@
     EXPECT_EQ("Frame" + std::to_string(i), frame->function_name) << "Failed at frame " << i;
     EXPECT_EQ(i, frame->function_offset) << "Failed at frame " << i;
     EXPECT_EQ("/system/fake/libc.so", frame->map_name) << "Failed at frame " << i;
-    EXPECT_EQ(0U, frame->map_offset) << "Failed at frame " << i;
+    EXPECT_EQ(0U, frame->map_elf_start_offset) << "Failed at frame " << i;
+    EXPECT_EQ(0U, frame->map_exact_offset) << "Failed at frame " << i;
     EXPECT_EQ(0x1000U, frame->map_start) << "Failed at frame " << i;
     EXPECT_EQ(0x8000U, frame->map_end) << "Failed at frame " << i;
     EXPECT_EQ(0U, frame->map_load_bias) << "Failed at frame " << i;
@@ -429,7 +420,7 @@
   ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10070, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   std::vector<std::string> skip_libs{"libunwind.so", "libanother.so"};
   unwinder.Unwind(&skip_libs);
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -444,7 +435,8 @@
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/system/fake/libc.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -458,7 +450,8 @@
   EXPECT_EQ("Frame1", frame->function_name);
   EXPECT_EQ(1U, frame->function_offset);
   EXPECT_EQ("/system/fake/libunwind.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x20000U, frame->map_start);
   EXPECT_EQ(0x22000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -472,7 +465,7 @@
   EXPECT_EQ("Frame2", frame->function_name);
   EXPECT_EQ(2U, frame->function_offset);
   EXPECT_EQ("/fake/libanother.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x23000U, frame->map_start);
   EXPECT_EQ(0x24000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -489,7 +482,7 @@
   ElfInterfaceFake::FakePushStepData(StepData(0x21002, 0x50020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
@@ -503,7 +496,7 @@
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/system/fake/libc.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -517,7 +510,7 @@
   EXPECT_EQ("Frame1", frame->function_name);
   EXPECT_EQ(1U, frame->function_offset);
   EXPECT_EQ("/system/fake/libunwind.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x20000U, frame->map_start);
   EXPECT_EQ(0x22000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -536,7 +529,7 @@
   ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
@@ -555,7 +548,7 @@
   ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
@@ -569,7 +562,7 @@
   regs_.set_pc(0x41000);
   regs_.set_sp(0x13000);
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
 
@@ -583,7 +576,8 @@
   EXPECT_EQ("", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0U, frame->map_start);
   EXPECT_EQ(0U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -604,7 +598,7 @@
   ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
@@ -618,7 +612,8 @@
   EXPECT_EQ("", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0U, frame->map_start);
   EXPECT_EQ(0U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -632,7 +627,8 @@
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/system/fake/libc.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -646,7 +642,8 @@
   EXPECT_EQ("Frame1", frame->function_name);
   EXPECT_EQ(1U, frame->function_offset);
   EXPECT_EQ("/fake/libanother.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x23000U, frame->map_start);
   EXPECT_EQ(0x24000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -666,7 +663,7 @@
   regs_.FakeSetReturnAddress(0x12);
   regs_.FakeSetReturnAddressValid(true);
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
 
@@ -680,7 +677,8 @@
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/system/fake/libunwind.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x20000U, frame->map_start);
   EXPECT_EQ(0x22000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -694,7 +692,8 @@
   EXPECT_EQ("", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0U, frame->map_start);
   EXPECT_EQ(0U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -713,7 +712,7 @@
   regs_.FakeSetReturnAddress(0x1202);
   regs_.FakeSetReturnAddressValid(true);
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
@@ -727,7 +726,8 @@
   EXPECT_EQ("", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0U, frame->map_start);
   EXPECT_EQ(0U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -741,7 +741,8 @@
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/system/fake/libc.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -762,14 +763,14 @@
   ElfInterfaceFake::FakePushStepData(StepData(0x53502, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   std::vector<std::string> suffixes{"oat"};
   unwinder.Unwind(nullptr, &suffixes);
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
   // Make sure the elf was not initialized.
-  MapInfo* map_info = maps_.Find(0x53000);
+  MapInfo* map_info = maps_->Find(0x53000);
   ASSERT_TRUE(map_info != nullptr);
   EXPECT_TRUE(map_info->elf == nullptr);
 
@@ -781,7 +782,8 @@
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/system/fake/libc.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -795,7 +797,8 @@
   EXPECT_EQ("Frame1", frame->function_name);
   EXPECT_EQ(1U, frame->function_offset);
   EXPECT_EQ("/fake/fake.apk", frame->map_name);
-  EXPECT_EQ(0x1d000U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0x1d000U, frame->map_exact_offset);
   EXPECT_EQ(0x43000U, frame->map_start);
   EXPECT_EQ(0x44000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -819,7 +822,7 @@
   ElfInterfaceFake::FakePushStepData(StepData(0x33502, 0x10020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode());
 
@@ -833,7 +836,8 @@
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/system/fake/libc.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -847,7 +851,8 @@
   EXPECT_EQ("Frame1", frame->function_name);
   EXPECT_EQ(1U, frame->function_offset);
   EXPECT_EQ("/fake/compressed.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x33000U, frame->map_start);
   EXPECT_EQ(0x34000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -861,7 +866,8 @@
   EXPECT_EQ("Frame2", frame->function_name);
   EXPECT_EQ(2U, frame->function_offset);
   EXPECT_EQ("/fake/compressed.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x33000U, frame->map_start);
   EXPECT_EQ(0x34000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -874,7 +880,7 @@
   regs_.set_sp(0x10000);
   regs_.FakeSetDexPc(0xa3400);
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
@@ -888,7 +894,8 @@
   EXPECT_EQ("", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/fake/fake.vdex", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0xa3000U, frame->map_start);
   EXPECT_EQ(0xa4000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -902,7 +909,8 @@
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/system/fake/libc.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -915,7 +923,7 @@
   regs_.set_sp(0x10000);
   regs_.FakeSetDexPc(0x50000);
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
@@ -929,7 +937,8 @@
   EXPECT_EQ("", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0U, frame->map_start);
   EXPECT_EQ(0U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -943,7 +952,8 @@
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/system/fake/libc.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -959,7 +969,7 @@
   ElfInterfaceFake::FakePushStepData(StepData(0x33402, 0x10010, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
-  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
@@ -973,7 +983,8 @@
   EXPECT_EQ("", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/fake/fake.vdex", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0xa3000U, frame->map_start);
   EXPECT_EQ(0xa4000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -987,7 +998,8 @@
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/system/fake/libc.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x1000U, frame->map_start);
   EXPECT_EQ(0x8000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -1001,7 +1013,8 @@
   EXPECT_EQ("Frame1", frame->function_name);
   EXPECT_EQ(1U, frame->function_offset);
   EXPECT_EQ("/fake/compressed.so", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0x33000U, frame->map_start);
   EXPECT_EQ(0x34000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -1014,7 +1027,7 @@
   regs_.set_sp(0x10000);
   regs_.FakeSetDexPc(0xa3400);
 
-  Unwinder unwinder(1, &maps_, &regs_, process_memory_);
+  Unwinder unwinder(1, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
 
@@ -1028,7 +1041,8 @@
   EXPECT_EQ("", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/fake/fake.vdex", frame->map_name);
-  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
   EXPECT_EQ(0xa3000U, frame->map_start);
   EXPECT_EQ(0xa4000U, frame->map_end);
   EXPECT_EQ(0U, frame->map_load_bias);
@@ -1045,17 +1059,17 @@
   frame.function_name = "function";
   frame.function_offset = 100;
   frame.map_name = "/fake/libfake.so";
-  frame.map_offset = 0x2000;
+  frame.map_elf_start_offset = 0x2000;
   frame.map_start = 0x3000;
   frame.map_end = 0x6000;
   frame.map_flags = PROT_READ;
 
-  EXPECT_EQ("  #01 pc 0000000000001000 (offset 0x2000)  /fake/libfake.so (function+100)",
+  EXPECT_EQ("  #01 pc 0000000000001000  /fake/libfake.so (offset 0x2000) (function+100)",
             Unwinder::FormatFrame(frame, false));
-  EXPECT_EQ("  #01 pc 00001000 (offset 0x2000)  /fake/libfake.so (function+100)",
+  EXPECT_EQ("  #01 pc 00001000  /fake/libfake.so (offset 0x2000) (function+100)",
             Unwinder::FormatFrame(frame, true));
 
-  frame.map_offset = 0;
+  frame.map_elf_start_offset = 0;
   EXPECT_EQ("  #01 pc 0000000000001000  /fake/libfake.so (function+100)",
             Unwinder::FormatFrame(frame, false));
   EXPECT_EQ("  #01 pc 00001000  /fake/libfake.so (function+100)",
@@ -1130,7 +1144,7 @@
   for (auto regs : reg_list) {
     ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10));
 
-    Unwinder unwinder(64, &maps_, regs, process_memory_);
+    Unwinder unwinder(64, maps_.get(), regs, process_memory_);
     unwinder.Unwind();
 
     ASSERT_EQ(1U, unwinder.NumFrames());
diff --git a/libunwindstack/tests/files/offline/offset_arm/maps.txt b/libunwindstack/tests/files/offline/offset_arm/maps.txt
index 6224464..768dd9f 100644
--- a/libunwindstack/tests/files/offline/offset_arm/maps.txt
+++ b/libunwindstack/tests/files/offline/offset_arm/maps.txt
@@ -1,2 +1,4 @@
+2b2a000-2b6c000 r--p 0 00:00 0   libunwindstack_test
 2b6c000-2e92000 r-xp 42000 00:00 0   libunwindstack_test
+f4110000-f4135000 r--p 0 00:00 0   libc.so
 f4135000-f41a9000 r-xp 25000 00:00 0   libc.so
diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp
index 652dbd1..5ae8874 100644
--- a/libunwindstack/tools/unwind_for_offline.cpp
+++ b/libunwindstack/tools/unwind_for_offline.cpp
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/mman.h>
 #include <sys/ptrace.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -46,6 +47,7 @@
   uint64_t start;
   uint64_t end;
   uint64_t offset;
+  uint64_t flags;
   std::string name;
 };
 
@@ -163,14 +165,19 @@
   return true;
 }
 
-bool CopyElfFromFile(map_info_t* info) {
+bool CopyElfFromFile(map_info_t* info, bool* file_copied) {
+  std::string cur_name = basename(info->name.c_str());
+  if (*file_copied) {
+    info->name = cur_name;
+    return true;
+  }
+
   std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(info->name.c_str(), "r"), &fclose);
   if (fp == nullptr) {
     perror((std::string("Cannot open ") + info->name).c_str());
     return false;
   }
 
-  std::string cur_name = basename(info->name.c_str());
   std::unique_ptr<FILE, decltype(&fclose)> output(fopen(cur_name.c_str(), "w+"), &fclose);
   if (output == nullptr) {
     perror((std::string("Cannot create file " + cur_name)).c_str());
@@ -193,6 +200,39 @@
   return true;
 }
 
+map_info_t* FillInAndGetMapInfo(std::unordered_map<uint64_t, map_info_t>& maps_by_start,
+                                unwindstack::MapInfo* map_info) {
+  auto info = &maps_by_start[map_info->start];
+  info->start = map_info->start;
+  info->end = map_info->end;
+  info->offset = map_info->offset;
+  info->name = map_info->name;
+  info->flags = map_info->flags;
+
+  return info;
+}
+
+void SaveMapInformation(std::shared_ptr<unwindstack::Memory>& process_memory, map_info_t* info,
+                        bool* file_copied) {
+  if (CopyElfFromFile(info, file_copied)) {
+    return;
+  }
+  *file_copied = false;
+
+  // Try to create the elf from memory, this will handle cases where
+  // the data only exists in memory such as vdso data on x86.
+  if (CreateElfFromMemory(process_memory, info)) {
+    return;
+  }
+
+  printf("Cannot save memory or file for map ");
+  if (!info->name.empty()) {
+    printf("%s\n", info->name.c_str());
+  } else {
+    printf("anonymous:%" PRIx64 "\n", info->start);
+  }
+}
+
 int SaveData(pid_t pid) {
   unwindstack::Regs* regs = unwindstack::Regs::RemoteGet(pid);
   if (regs == nullptr) {
@@ -237,22 +277,21 @@
     }
 
     if (maps_by_start.count(frame.map_start) == 0) {
-      auto info = &maps_by_start[frame.map_start];
-      info->start = frame.map_start;
-      info->end = frame.map_end;
-      info->offset = frame.map_offset;
-      info->name = frame.map_name;
-      if (!CopyElfFromFile(info)) {
-        // Try to create the elf from memory, this will handle cases where
-        // the data only exists in memory such as vdso data on x86.
-        if (!CreateElfFromMemory(process_memory, info)) {
-          printf("Ignoring map ");
-          if (!info->name.empty()) {
-            printf("%s\n", info->name.c_str());
-          } else {
-            printf("anonymous:%" PRIx64 "\n", info->start);
-          }
-        }
+      map_info = maps.Find(frame.map_start);
+
+      auto info = FillInAndGetMapInfo(maps_by_start, map_info);
+      bool file_copied = false;
+      SaveMapInformation(process_memory, info, &file_copied);
+
+      // If you are using a a linker that creates two maps (one read-only, one
+      // read-executable), it's necessary to capture the previous map
+      // information if needed.
+      unwindstack::MapInfo* prev_map = map_info->prev_map;
+      if (prev_map != nullptr && map_info->offset != 0 && prev_map->offset == 0 &&
+          prev_map->flags == PROT_READ && map_info->name == prev_map->name &&
+          maps_by_start.count(prev_map->start) == 0) {
+        info = FillInAndGetMapInfo(maps_by_start, prev_map);
+        SaveMapInformation(process_memory, info, &file_copied);
       }
     }
   }
@@ -277,8 +316,18 @@
   }
 
   for (auto& element : sorted_maps) {
+    char perms[5] = {"---p"};
     map_info_t& map = element.second;
-    fprintf(fp.get(), "%" PRIx64 "-%" PRIx64 " r-xp %" PRIx64 " 00:00 0", map.start, map.end,
+    if (map.flags & PROT_READ) {
+      perms[0] = 'r';
+    }
+    if (map.flags & PROT_WRITE) {
+      perms[1] = 'w';
+    }
+    if (map.flags & PROT_EXEC) {
+      perms[2] = 'x';
+    }
+    fprintf(fp.get(), "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " 00:00 0", map.start, map.end, perms,
             map.offset);
     if (!map.name.empty()) {
       fprintf(fp.get(), "   %s", map.name.c_str());