Merge "Allow multiple threads sharing a map to unwind."
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 25e5002..9ac0a0b 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -44,15 +44,15 @@
   }
 
   // Iterate through the maps and fill in the backtrace_map_t structure.
-  for (auto& map_info : *stack_maps_) {
+  for (auto* map_info : *stack_maps_) {
     backtrace_map_t map;
-    map.start = map_info.start;
-    map.end = map_info.end;
-    map.offset = map_info.offset;
+    map.start = map_info->start;
+    map.end = map_info->end;
+    map.offset = map_info->offset;
     // Set to -1 so that it is demand loaded.
     map.load_bias = static_cast<uintptr_t>(-1);
-    map.flags = map_info.flags;
-    map.name = map_info.name;
+    map.flags = map_info->flags;
+    map.name = map_info->name;
 
     maps_.push_back(map);
   }
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 0a60ec4..9911e74 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -77,6 +77,7 @@
 
 struct dump_thread_t {
   thread_t thread;
+  BacktraceMap* map;
   Backtrace* backtrace;
   int32_t* now;
   int32_t done;
@@ -632,7 +633,7 @@
   }
 
   // The status of the actual unwind will be checked elsewhere.
-  dump->backtrace = Backtrace::Create(getpid(), dump->thread.tid);
+  dump->backtrace = Backtrace::Create(getpid(), dump->thread.tid, dump->map);
   dump->backtrace->Unwind(0);
 
   android_atomic_acquire_store(1, &dump->done);
@@ -640,8 +641,8 @@
   return nullptr;
 }
 
-TEST(libbacktrace, thread_multiple_dump) {
-  // Dump NUM_THREADS simultaneously.
+static void MultipleThreadDumpTest(bool share_map) {
+  // Dump NUM_THREADS simultaneously using the same map.
   std::vector<thread_t> runners(NUM_THREADS);
   std::vector<dump_thread_t> dumpers(NUM_THREADS);
 
@@ -662,12 +663,17 @@
 
   // Start all of the dumpers at once, they will spin until they are signalled
   // to begin their dump run.
+  std::unique_ptr<BacktraceMap> map;
+  if (share_map) {
+    map.reset(BacktraceMap::Create(getpid()));
+  }
   int32_t dump_now = 0;
   for (size_t i = 0; i < NUM_THREADS; i++) {
     dumpers[i].thread.tid = runners[i].tid;
     dumpers[i].thread.state = 0;
     dumpers[i].done = 0;
     dumpers[i].now = &dump_now;
+    dumpers[i].map = map.get();
 
     ASSERT_TRUE(pthread_create(&dumpers[i].thread.threadId, &attr, ThreadDump, &dumpers[i]) == 0);
   }
@@ -689,47 +695,12 @@
   }
 }
 
-TEST(libbacktrace, thread_multiple_dump_same_thread) {
-  pthread_attr_t attr;
-  pthread_attr_init(&attr);
-  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-  thread_t runner;
-  runner.tid = 0;
-  runner.state = 0;
-  ASSERT_TRUE(pthread_create(&runner.threadId, &attr, ThreadMaxRun, &runner) == 0);
+TEST(libbacktrace, thread_multiple_dump) {
+  MultipleThreadDumpTest(false);
+}
 
-  // Wait for tids to be set.
-  ASSERT_TRUE(WaitForNonZero(&runner.state, 30));
-
-  // Start all of the dumpers at once, they will spin until they are signalled
-  // to begin their dump run.
-  int32_t dump_now = 0;
-  // Dump the same thread NUM_THREADS simultaneously.
-  std::vector<dump_thread_t> dumpers(NUM_THREADS);
-  for (size_t i = 0; i < NUM_THREADS; i++) {
-    dumpers[i].thread.tid = runner.tid;
-    dumpers[i].thread.state = 0;
-    dumpers[i].done = 0;
-    dumpers[i].now = &dump_now;
-
-    ASSERT_TRUE(pthread_create(&dumpers[i].thread.threadId, &attr, ThreadDump, &dumpers[i]) == 0);
-  }
-
-  // Start all of the dumpers going at once.
-  android_atomic_acquire_store(1, &dump_now);
-
-  for (size_t i = 0; i < NUM_THREADS; i++) {
-    ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 30));
-
-    ASSERT_TRUE(dumpers[i].backtrace != nullptr);
-    VerifyMaxDump(dumpers[i].backtrace);
-
-    delete dumpers[i].backtrace;
-    dumpers[i].backtrace = nullptr;
-  }
-
-  // Tell the runner thread to exit its infinite loop.
-  android_atomic_acquire_store(0, &runner.state);
+TEST(libbacktrace, thread_multiple_dump_same_map) {
+  MultipleThreadDumpTest(true);
 }
 
 // This test is for UnwindMaps that should share the same map cursor when
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index edf7ac2..0c65895 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -18,6 +18,7 @@
 #include <string.h>
 
 #include <memory>
+#include <mutex>
 #include <string>
 
 #define LOG_TAG "unwind"
@@ -87,6 +88,7 @@
 }
 
 bool Elf::GetSoname(std::string* name) {
+  std::lock_guard<std::mutex> guard(lock_);
   return valid_ && interface_->GetSoname(name);
 }
 
@@ -95,6 +97,7 @@
 }
 
 bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
+  std::lock_guard<std::mutex> guard(lock_);
   return valid_ && (interface_->GetFunctionName(addr, load_bias_, name, func_offset) ||
                     (gnu_debugdata_interface_ && gnu_debugdata_interface_->GetFunctionName(
                                                      addr, load_bias_, name, func_offset)));
@@ -119,6 +122,8 @@
   }
   rel_pc -= load_bias_;
 
+  // Lock during the step which can update information in the object.
+  std::lock_guard<std::mutex> guard(lock_);
   return interface_->Step(rel_pc, regs, process_memory, finished) ||
          (gnu_debugdata_interface_ &&
           gnu_debugdata_interface_->Step(rel_pc, regs, process_memory, finished));
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 140d05a..5417659 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -19,6 +19,7 @@
 #include <unistd.h>
 
 #include <memory>
+#include <mutex>
 #include <string>
 
 #include <unwindstack/Elf.h>
@@ -105,6 +106,9 @@
 }
 
 Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata) {
+  // Make sure no other thread is trying to add the elf to this map.
+  std::lock_guard<std::mutex> guard(mutex_);
+
   if (elf) {
     return elf;
   }
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index 5e1c0a2..5012ffd 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -44,7 +44,7 @@
   size_t last = maps_.size();
   while (first < last) {
     size_t index = (first + last) / 2;
-    MapInfo* cur = &maps_[index];
+    MapInfo* cur = maps_[index];
     if (pc >= cur->start && pc < cur->end) {
       return cur;
     } else if (pc < cur->start) {
@@ -57,22 +57,22 @@
 }
 
 // Assumes that line does not end in '\n'.
-static bool InternalParseLine(const char* line, MapInfo* map_info) {
+static MapInfo* InternalParseLine(const char* line) {
   // Do not use a sscanf implementation since it is not performant.
 
   // Example linux /proc/<pid>/maps lines:
   // 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so
   char* str;
   const char* old_str = line;
-  map_info->start = strtoul(old_str, &str, 16);
+  uint64_t start = strtoul(old_str, &str, 16);
   if (old_str == str || *str++ != '-') {
-    return false;
+    return nullptr;
   }
 
   old_str = str;
-  map_info->end = strtoul(old_str, &str, 16);
+  uint64_t end = strtoul(old_str, &str, 16);
   if (old_str == str || !std::isspace(*str++)) {
-    return false;
+    return nullptr;
   }
 
   while (std::isspace(*str)) {
@@ -81,82 +81,81 @@
 
   // Parse permissions data.
   if (*str == '\0') {
-    return false;
+    return nullptr;
   }
-  map_info->flags = 0;
+  uint16_t flags = 0;
   if (*str == 'r') {
-    map_info->flags |= PROT_READ;
+    flags |= PROT_READ;
   } else if (*str != '-') {
-    return false;
+    return nullptr;
   }
   str++;
   if (*str == 'w') {
-    map_info->flags |= PROT_WRITE;
+    flags |= PROT_WRITE;
   } else if (*str != '-') {
-    return false;
+    return nullptr;
   }
   str++;
   if (*str == 'x') {
-    map_info->flags |= PROT_EXEC;
+    flags |= PROT_EXEC;
   } else if (*str != '-') {
-    return false;
+    return nullptr;
   }
   str++;
   if (*str != 'p' && *str != 's') {
-    return false;
+    return nullptr;
   }
   str++;
 
   if (!std::isspace(*str++)) {
-    return false;
+    return nullptr;
   }
 
   old_str = str;
-  map_info->offset = strtoul(old_str, &str, 16);
+  uint64_t offset = strtoul(old_str, &str, 16);
   if (old_str == str || !std::isspace(*str)) {
-    return false;
+    return nullptr;
   }
 
   // Ignore the 00:00 values.
   old_str = str;
   (void)strtoul(old_str, &str, 16);
   if (old_str == str || *str++ != ':') {
-    return false;
+    return nullptr;
   }
   if (std::isspace(*str)) {
-    return false;
+    return nullptr;
   }
 
   // Skip the inode.
   old_str = str;
   (void)strtoul(str, &str, 16);
   if (old_str == str || !std::isspace(*str++)) {
-    return false;
+    return nullptr;
   }
 
   // Skip decimal digit.
   old_str = str;
   (void)strtoul(old_str, &str, 10);
   if (old_str == str || (!std::isspace(*str) && *str != '\0')) {
-    return false;
+    return nullptr;
   }
 
   while (std::isspace(*str)) {
     str++;
   }
   if (*str == '\0') {
-    map_info->name = str;
-    return true;
+    return new MapInfo(start, end, offset, flags, "");
   }
 
   // Save the name data.
-  map_info->name = str;
+  std::string name(str);
 
   // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
-  if (map_info->name.substr(0, 5) == "/dev/" && map_info->name.substr(5, 7) != "ashmem/") {
-    map_info->flags |= MAPS_FLAGS_DEVICE_MAP;
+  if (name.substr(0, 5) == "/dev/" && name.substr(5, 7) != "ashmem/") {
+    flags |= MAPS_FLAGS_DEVICE_MAP;
   }
-  return true;
+  return new MapInfo(start, end, offset, flags, name);
 }
 
 bool Maps::Parse() {
@@ -187,8 +186,8 @@
       }
       *newline = '\0';
 
-      MapInfo map_info;
-      if (!InternalParseLine(line, &map_info)) {
+      MapInfo* map_info = InternalParseLine(line);
+      if (map_info == nullptr) {
         return_value = false;
         break;
       }
@@ -205,8 +204,7 @@
 
 Maps::~Maps() {
   for (auto& map : maps_) {
-    delete map.elf;
-    map.elf = nullptr;
+    delete map;
   }
 }
 
@@ -222,8 +220,8 @@
       end_of_line++;
     }
 
-    MapInfo map_info;
-    if (!InternalParseLine(line.c_str(), &map_info)) {
+    MapInfo* map_info = InternalParseLine(line.c_str());
+    if (map_info == nullptr) {
       return false;
     }
     maps_.push_back(map_info);
@@ -252,24 +250,27 @@
 
   std::vector<char> name;
   while (true) {
-    MapInfo map_info;
-    ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.start, sizeof(map_info.start)));
+    uint64_t start;
+    ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, &start, sizeof(start)));
     if (bytes == 0) {
       break;
     }
-    if (bytes == -1 || bytes != sizeof(map_info.start)) {
+    if (bytes == -1 || bytes != sizeof(start)) {
       return false;
     }
-    bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.end, sizeof(map_info.end)));
-    if (bytes == -1 || bytes != sizeof(map_info.end)) {
+    uint64_t end;
+    bytes = TEMP_FAILURE_RETRY(read(fd, &end, sizeof(end)));
+    if (bytes == -1 || bytes != sizeof(end)) {
       return false;
     }
-    bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.offset, sizeof(map_info.offset)));
-    if (bytes == -1 || bytes != sizeof(map_info.offset)) {
+    uint64_t offset;
+    bytes = TEMP_FAILURE_RETRY(read(fd, &offset, sizeof(offset)));
+    if (bytes == -1 || bytes != sizeof(offset)) {
       return false;
     }
-    bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.flags, sizeof(map_info.flags)));
-    if (bytes == -1 || bytes != sizeof(map_info.flags)) {
+    uint16_t flags;
+    bytes = TEMP_FAILURE_RETRY(read(fd, &flags, sizeof(flags)));
+    if (bytes == -1 || bytes != sizeof(flags)) {
       return false;
     }
     uint16_t len;
@@ -283,9 +284,10 @@
       if (bytes == -1 || bytes != len) {
         return false;
       }
-      map_info.name = std::string(name.data(), len);
+      maps_.push_back(new MapInfo(start, end, offset, flags, std::string(name.data(), len)));
+    } else {
+      maps_.push_back(new MapInfo(start, end, offset, flags, ""));
     }
-    maps_.push_back(map_info);
   }
   return true;
 }
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 294d742..71d7aca 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -20,6 +20,7 @@
 #include <stddef.h>
 
 #include <memory>
+#include <mutex>
 #include <string>
 
 #include <unwindstack/ElfInterface.h>
@@ -80,6 +81,8 @@
   std::unique_ptr<Memory> memory_;
   uint32_t machine_type_;
   uint8_t class_type_;
+  // Protect calls that can modify internal state of the interface object.
+  std::mutex lock_;
 
   std::unique_ptr<Memory> gnu_debugdata_memory_;
   std::unique_ptr<ElfInterface> gnu_debugdata_interface_;
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index f108766..e54b348 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -19,34 +19,48 @@
 
 #include <stdint.h>
 
+#include <mutex>
 #include <string>
 
+#include <unwindstack/Elf.h>
+
 namespace unwindstack {
 
 // Forward declarations.
-class Elf;
 class Memory;
 
 struct MapInfo {
-  uint64_t start;
-  uint64_t end;
-  uint64_t offset;
-  uint16_t flags;
+  MapInfo() = default;
+  MapInfo(uint64_t start, uint64_t end) : start(start), end(end) {}
+  MapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name)
+      : start(start), end(end), offset(offset), flags(flags), name(name) {}
+  ~MapInfo() { delete elf; }
+
+  uint64_t start = 0;
+  uint64_t end = 0;
+  uint64_t offset = 0;
+  uint16_t flags = 0;
   std::string name;
   Elf* elf = nullptr;
   // 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.
-  uint64_t elf_offset;
+  uint64_t elf_offset = 0;
 
   // This function guarantees it will never return nullptr.
   Elf* GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata = false);
 
  private:
+  MapInfo(const MapInfo&) = delete;
+  void operator=(const MapInfo&) = delete;
+
   Memory* GetFileMemory();
 
   Memory* CreateMemory(const std::shared_ptr<Memory>& process_memory);
+
+  // Protect the creation of the elf object.
+  std::mutex mutex_;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Maps.h b/libunwindstack/include/unwindstack/Maps.h
index 22122a9..34fef7f 100644
--- a/libunwindstack/include/unwindstack/Maps.h
+++ b/libunwindstack/include/unwindstack/Maps.h
@@ -42,11 +42,11 @@
 
   virtual const std::string GetMapsFile() const { return ""; }
 
-  typedef std::vector<MapInfo>::iterator iterator;
+  typedef std::vector<MapInfo*>::iterator iterator;
   iterator begin() { return maps_.begin(); }
   iterator end() { return maps_.end(); }
 
-  typedef std::vector<MapInfo>::const_iterator const_iterator;
+  typedef std::vector<MapInfo*>::const_iterator const_iterator;
   const_iterator begin() const { return maps_.begin(); }
   const_iterator end() const { return maps_.end(); }
 
@@ -54,11 +54,11 @@
 
   MapInfo* Get(size_t index) {
     if (index >= maps_.size()) return nullptr;
-    return &maps_[index];
+    return maps_[index];
   }
 
  protected:
-  std::vector<MapInfo> maps_;
+  std::vector<MapInfo*> maps_;
 };
 
 class RemoteMaps : public Maps {
diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
index d1461d8..c59e081 100644
--- a/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -33,7 +33,7 @@
 
 #if defined(__arm__)
 
-inline void RegsGetLocal(Regs* regs) {
+inline __always_inline void RegsGetLocal(Regs* regs) {
   void* reg_data = regs->RawData();
   asm volatile(
       ".align 2\n"
@@ -57,7 +57,7 @@
 
 #elif defined(__aarch64__)
 
-inline void RegsGetLocal(Regs* regs) {
+inline __always_inline void RegsGetLocal(Regs* regs) {
   void* reg_data = regs->RawData();
   asm volatile(
       "1:\n"
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 4e48fa1..098f5f4 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -273,7 +273,7 @@
 
   elf.FakeSetValid(true);
   elf.FakeSetLoadBias(0);
-  MapInfo map_info{.start = 0x1000, .end = 0x2000};
+  MapInfo map_info(0x1000, 0x2000);
 
   ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
 
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index d2aad49..bdcb652 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -94,7 +94,7 @@
 TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_;
 
 TEST_F(MapInfoCreateMemoryTest, end_le_start) {
-  MapInfo info{.start = 0x100, .end = 0x100, .offset = 0, .name = elf_.path};
+  MapInfo info(0x100, 0x100, 0, 0, elf_.path);
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() == nullptr);
@@ -112,7 +112,7 @@
 // Verify that if the offset is non-zero but there is no elf at the offset,
 // that the full file is used.
 TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
-  MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_.path};
+  MapInfo info(0x100, 0x200, 0x100, 0, elf_.path);
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
@@ -133,7 +133,7 @@
 // Verify that if the offset is non-zero and there is an elf at that
 // offset, that only part of the file is used.
 TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
-  MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_at_100_.path};
+  MapInfo info(0x100, 0x200, 0x100, 0, elf_at_100_.path);
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
@@ -156,7 +156,7 @@
 // embedded elf is bigger than the initial map, the new object is larger
 // than the original map size. Do this for a 32 bit elf and a 64 bit elf.
 TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
-  MapInfo info{.start = 0x5000, .end = 0x6000, .offset = 0x1000, .name = elf32_at_map_.path};
+  MapInfo info(0x5000, 0x6000, 0x1000, 0, elf32_at_map_.path);
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
@@ -172,7 +172,7 @@
 }
 
 TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
-  MapInfo info{.start = 0x7000, .end = 0x8000, .offset = 0x2000, .name = elf64_at_map_.path};
+  MapInfo info(0x7000, 0x8000, 0x2000, 0, elf64_at_map_.path);
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index 0b70d13..9973794 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -23,7 +23,9 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <atomic>
 #include <memory>
+#include <thread>
 #include <vector>
 
 #include <android-base/file.h>
@@ -67,52 +69,52 @@
 };
 
 TEST_F(MapInfoGetElfTest, invalid) {
-  MapInfo info{.start = 0x1000, .end = 0x2000, .offset = 0, .flags = PROT_READ, .name = ""};
+  MapInfo info(0x1000, 0x2000, 0, PROT_READ, "");
 
   // The map is empty, but this should still create an invalid elf object.
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
-  ASSERT_TRUE(elf.get() != nullptr);
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_FALSE(elf->valid());
 }
 
 TEST_F(MapInfoGetElfTest, valid32) {
-  MapInfo info{.start = 0x3000, .end = 0x4000, .offset = 0, .flags = PROT_READ, .name = ""};
+  MapInfo info(0x3000, 0x4000, 0, PROT_READ, "");
 
   Elf32_Ehdr ehdr;
   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
   memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
-  ASSERT_TRUE(elf.get() != nullptr);
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
   EXPECT_EQ(ELFCLASS32, elf->class_type());
 }
 
 TEST_F(MapInfoGetElfTest, valid64) {
-  MapInfo info{.start = 0x8000, .end = 0x9000, .offset = 0, .flags = PROT_READ, .name = ""};
+  MapInfo info(0x8000, 0x9000, 0, PROT_READ, "");
 
   Elf64_Ehdr ehdr;
   TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
   memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
-  ASSERT_TRUE(elf.get() != nullptr);
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
   EXPECT_EQ(ELFCLASS64, elf->class_type());
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) {
-  MapInfo info{.start = 0x4000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""};
+  MapInfo info(0x4000, 0x8000, 0, PROT_READ, "");
 
   TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false,
                                                [&](uint64_t offset, const void* ptr, size_t size) {
                                                  memory_->SetMemory(0x4000 + offset, ptr, size);
                                                });
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
-  ASSERT_TRUE(elf.get() != nullptr);
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
   EXPECT_EQ(ELFCLASS32, elf->class_type());
@@ -120,15 +122,15 @@
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) {
-  MapInfo info{.start = 0x6000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""};
+  MapInfo info(0x6000, 0x8000, 0, PROT_READ, "");
 
   TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false,
                                                [&](uint64_t offset, const void* ptr, size_t size) {
                                                  memory_->SetMemory(0x6000 + offset, ptr, size);
                                                });
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
-  ASSERT_TRUE(elf.get() != nullptr);
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
   EXPECT_EQ(ELFCLASS64, elf->class_type());
@@ -136,15 +138,15 @@
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
-  MapInfo info{.start = 0x2000, .end = 0x3000, .offset = 0, .flags = PROT_READ, .name = ""};
+  MapInfo info(0x2000, 0x3000, 0, PROT_READ, "");
 
   TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
                                                [&](uint64_t offset, const void* ptr, size_t size) {
                                                  memory_->SetMemory(0x2000 + offset, ptr, size);
                                                });
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, true));
-  ASSERT_TRUE(elf.get() != nullptr);
+  Elf* elf = info.GetElf(process_memory_, true);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
   EXPECT_EQ(ELFCLASS32, elf->class_type());
@@ -152,15 +154,15 @@
 }
 
 TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
-  MapInfo info{.start = 0x5000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""};
+  MapInfo info(0x5000, 0x8000, 0, PROT_READ, "");
 
   TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
                                                [&](uint64_t offset, const void* ptr, size_t size) {
                                                  memory_->SetMemory(0x5000 + offset, ptr, size);
                                                });
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, true));
-  ASSERT_TRUE(elf.get() != nullptr);
+  Elf* elf = info.GetElf(process_memory_, true);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
   EXPECT_EQ(ELFCLASS64, elf->class_type());
@@ -168,32 +170,36 @@
 }
 
 TEST_F(MapInfoGetElfTest, end_le_start) {
-  MapInfo info{.start = 0x1000, .end = 0x1000, .offset = 0, .flags = PROT_READ, .name = elf_.path};
+  MapInfo info(0x1000, 0x1000, 0, PROT_READ, elf_.path);
 
   Elf32_Ehdr ehdr;
   TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
   ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_FALSE(elf->valid());
 
+  delete info.elf;
   info.elf = nullptr;
   info.end = 0xfff;
-  elf.reset(info.GetElf(process_memory_, false));
+  elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_FALSE(elf->valid());
 
   // Make sure this test is valid.
+  delete info.elf;
   info.elf = nullptr;
   info.end = 0x2000;
-  elf.reset(info.GetElf(process_memory_, false));
+  elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
 }
 
 // Verify that if the offset is non-zero but there is no elf at the offset,
 // that the full file is used.
 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
-  MapInfo info{
-      .start = 0x1000, .end = 0x2000, .offset = 0x100, .flags = PROT_READ, .name = elf_.path};
+  MapInfo info(0x1000, 0x2000, 0x100, PROT_READ, elf_.path);
 
   std::vector<uint8_t> buffer(0x1000);
   memset(buffer.data(), 0, buffer.size());
@@ -202,7 +208,8 @@
   memcpy(buffer.data(), &ehdr, sizeof(ehdr));
   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   ASSERT_TRUE(elf->memory() != nullptr);
   ASSERT_EQ(0x100U, info.elf_offset);
@@ -221,8 +228,7 @@
 // Verify that if the offset is non-zero and there is an elf at that
 // offset, that only part of the file is used.
 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
-  MapInfo info{
-      .start = 0x1000, .end = 0x2000, .offset = 0x2000, .flags = PROT_READ, .name = elf_.path};
+  MapInfo info(0x1000, 0x2000, 0x2000, PROT_READ, elf_.path);
 
   std::vector<uint8_t> buffer(0x4000);
   memset(buffer.data(), 0, buffer.size());
@@ -231,7 +237,8 @@
   memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   ASSERT_TRUE(elf->memory() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
@@ -251,8 +258,7 @@
 // embedded elf is bigger than the initial map, the new object is larger
 // than the original map size. Do this for a 32 bit elf and a 64 bit elf.
 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
-  MapInfo info{
-      .start = 0x5000, .end = 0x6000, .offset = 0x1000, .flags = PROT_READ, .name = elf_.path};
+  MapInfo info(0x5000, 0x6000, 0x1000, PROT_READ, elf_.path);
 
   std::vector<uint8_t> buffer(0x4000);
   memset(buffer.data(), 0, buffer.size());
@@ -264,7 +270,8 @@
   memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   ASSERT_TRUE(elf->memory() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
@@ -279,8 +286,7 @@
 }
 
 TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
-  MapInfo info{
-      .start = 0x7000, .end = 0x8000, .offset = 0x1000, .flags = PROT_READ, .name = elf_.path};
+  MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ, elf_.path);
 
   std::vector<uint8_t> buffer(0x4000);
   memset(buffer.data(), 0, buffer.size());
@@ -292,7 +298,8 @@
   memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
   ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_TRUE(elf->valid());
   ASSERT_TRUE(elf->memory() != nullptr);
   ASSERT_EQ(0U, info.elf_offset);
@@ -307,7 +314,7 @@
 }
 
 TEST_F(MapInfoGetElfTest, process_memory_not_read_only) {
-  MapInfo info{.start = 0x9000, .end = 0xa000, .offset = 0x1000, .flags = 0, .name = ""};
+  MapInfo info(0x9000, 0xa000, 0x1000, 0, "");
 
   // Create valid elf data in process memory only.
   Elf64_Ehdr ehdr;
@@ -317,21 +324,19 @@
   ehdr.e_shnum = 4;
   memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_FALSE(elf->valid());
 
+  delete info.elf;
   info.elf = nullptr;
   info.flags = PROT_READ;
-  elf.reset(info.GetElf(process_memory_, false));
+  elf = info.GetElf(process_memory_, false);
   ASSERT_TRUE(elf->valid());
 }
 
 TEST_F(MapInfoGetElfTest, check_device_maps) {
-  MapInfo info{.start = 0x7000,
-               .end = 0x8000,
-               .offset = 0x1000,
-               .flags = PROT_READ | MAPS_FLAGS_DEVICE_MAP,
-               .name = "/dev/something"};
+  MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP, "/dev/something");
 
   // Create valid elf data in process memory for this to verify that only
   // the name is causing invalid elf data.
@@ -342,20 +347,68 @@
   ehdr.e_shnum = 4;
   memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
 
-  std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+  Elf* elf = info.GetElf(process_memory_, false);
+  ASSERT_TRUE(elf != nullptr);
   ASSERT_FALSE(elf->valid());
 
   // Set the name to nothing to verify that it still fails.
+  delete info.elf;
   info.elf = nullptr;
   info.name = "";
-  elf.reset(info.GetElf(process_memory_, false));
+  elf = info.GetElf(process_memory_, false);
   ASSERT_FALSE(elf->valid());
 
   // Change the flags and verify the elf is valid now.
+  delete info.elf;
   info.elf = nullptr;
   info.flags = PROT_READ;
-  elf.reset(info.GetElf(process_memory_, false));
+  elf = info.GetElf(process_memory_, false);
   ASSERT_TRUE(elf->valid());
 }
 
+TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) {
+  static constexpr size_t kNumConcurrentThreads = 100;
+
+  Elf64_Ehdr ehdr;
+  TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
+  ehdr.e_shoff = 0x2000;
+  ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
+  ehdr.e_shnum = 4;
+  memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
+
+  Elf* elf_in_threads[kNumConcurrentThreads];
+  std::vector<std::thread*> threads;
+
+  std::atomic_bool wait;
+  wait = true;
+  // Create all of the threads and have them do the GetElf at the same time
+  // to make it likely that a race will occur.
+  MapInfo info(0x7000, 0x8000, 0x1000, PROT_READ, "");
+  for (size_t i = 0; i < kNumConcurrentThreads; i++) {
+    std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() {
+      while (wait)
+        ;
+      Elf* elf = info.GetElf(process_memory_, false);
+      elf_in_threads[i] = elf;
+    });
+    threads.push_back(thread);
+  }
+  ASSERT_TRUE(info.elf == nullptr);
+
+  // Set them all going and wait for the threads to finish.
+  wait = false;
+  for (auto thread : threads) {
+    thread->join();
+    delete thread;
+  }
+
+  // Now verify that all of the elf files are exactly the same and valid.
+  Elf* elf = info.elf;
+  ASSERT_TRUE(elf != nullptr);
+  EXPECT_TRUE(elf->valid());
+  for (size_t i = 0; i < kNumConcurrentThreads; i++) {
+    EXPECT_EQ(elf, elf_in_threads[i]) << "Thread " << i << " mismatched.";
+  }
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
index 2d15a4e..8dc884f 100644
--- a/libunwindstack/tests/MapsTest.cpp
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -35,7 +35,12 @@
     ASSERT_TRUE(maps.Parse()) << "Failed on: " + line;
     MapInfo* element = maps.Get(0);
     ASSERT_TRUE(element != nullptr) << "Failed on: " + line;
-    *info = *element;
+    info->start = element->start;
+    info->end = element->end;
+    info->offset = element->offset;
+    info->flags = element->flags;
+    info->name = element->name;
+    info->elf_offset = element->elf_offset;
   }
 }
 
@@ -139,38 +144,48 @@
 
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(5U, maps.Total());
-  auto it = maps.begin();
-  ASSERT_EQ(PROT_NONE, it->flags);
-  ASSERT_EQ(0x1000U, it->start);
-  ASSERT_EQ(0x2000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ("", it->name);
-  ++it;
-  ASSERT_EQ(PROT_READ, it->flags);
-  ASSERT_EQ(0x2000U, it->start);
-  ASSERT_EQ(0x3000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ("", it->name);
-  ++it;
-  ASSERT_EQ(PROT_WRITE, it->flags);
-  ASSERT_EQ(0x3000U, it->start);
-  ASSERT_EQ(0x4000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ("", it->name);
-  ++it;
-  ASSERT_EQ(PROT_EXEC, it->flags);
-  ASSERT_EQ(0x4000U, it->start);
-  ASSERT_EQ(0x5000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ("", it->name);
-  ++it;
-  ASSERT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, it->flags);
-  ASSERT_EQ(0x5000U, it->start);
-  ASSERT_EQ(0x6000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ("", it->name);
-  ++it;
-  ASSERT_EQ(it, maps.end());
+
+  MapInfo* info = maps.Get(0);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(PROT_NONE, info->flags);
+  EXPECT_EQ(0x1000U, info->start);
+  EXPECT_EQ(0x2000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ("", info->name);
+
+  info = maps.Get(1);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(PROT_READ, info->flags);
+  EXPECT_EQ(0x2000U, info->start);
+  EXPECT_EQ(0x3000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ("", info->name);
+
+  info = maps.Get(2);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(PROT_WRITE, info->flags);
+  EXPECT_EQ(0x3000U, info->start);
+  EXPECT_EQ(0x4000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ("", info->name);
+
+  info = maps.Get(3);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(PROT_EXEC, info->flags);
+  EXPECT_EQ(0x4000U, info->start);
+  EXPECT_EQ(0x5000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ("", info->name);
+
+  info = maps.Get(4);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags);
+  EXPECT_EQ(0x5000U, info->start);
+  EXPECT_EQ(0x6000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ("", info->name);
+
+  ASSERT_TRUE(maps.Get(5) == nullptr);
 }
 
 TEST(MapsTest, parse_name) {
@@ -181,26 +196,32 @@
 
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(3U, maps.Total());
-  auto it = maps.begin();
-  ASSERT_EQ("", it->name);
-  ASSERT_EQ(0x7b29b000U, it->start);
-  ASSERT_EQ(0x7b29e000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
-  ++it;
-  ASSERT_EQ("/system/lib/fake.so", it->name);
-  ASSERT_EQ(0x7b29e000U, it->start);
-  ASSERT_EQ(0x7b29f000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
-  ++it;
-  ASSERT_EQ("", it->name);
-  ASSERT_EQ(0x7b29f000U, it->start);
-  ASSERT_EQ(0x7b2a0000U, it->end);
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
-  ++it;
-  ASSERT_EQ(it, maps.end());
+
+  MapInfo* info = maps.Get(0);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ("", info->name);
+  EXPECT_EQ(0x7b29b000U, info->start);
+  EXPECT_EQ(0x7b29e000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+
+  info = maps.Get(1);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ("/system/lib/fake.so", info->name);
+  EXPECT_EQ(0x7b29e000U, info->start);
+  EXPECT_EQ(0x7b29f000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+
+  info = maps.Get(2);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ("", info->name);
+  EXPECT_EQ(0x7b29f000U, info->start);
+  EXPECT_EQ(0x7b2a0000U, info->end);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+
+  ASSERT_TRUE(maps.Get(3) == nullptr);
 }
 
 TEST(MapsTest, parse_offset) {
@@ -210,20 +231,60 @@
 
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(2U, maps.Total());
-  auto it = maps.begin();
-  ASSERT_EQ(0U, it->offset);
-  ASSERT_EQ(0xa000U, it->start);
-  ASSERT_EQ(0xe000U, it->end);
-  ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
-  ASSERT_EQ("/system/lib/fake.so", it->name);
+
+  MapInfo* info = maps.Get(0);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0U, info->offset);
+  EXPECT_EQ(0xa000U, info->start);
+  EXPECT_EQ(0xe000U, info->end);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+  EXPECT_EQ("/system/lib/fake.so", info->name);
+
+  info = maps.Get(1);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0xa12345U, info->offset);
+  EXPECT_EQ(0xe000U, info->start);
+  EXPECT_EQ(0xf000U, info->end);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+  EXPECT_EQ("/system/lib/fake.so", info->name);
+
+  ASSERT_TRUE(maps.Get(2) == nullptr);
+}
+
+TEST(MapsTest, iterate) {
+  BufferMaps maps(
+      "a000-e000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
+      "e000-f000 rw-p 00a12345 00:00 0 /system/lib/fake.so\n");
+
+  ASSERT_TRUE(maps.Parse());
+  ASSERT_EQ(2U, maps.Total());
+
+  Maps::iterator it = maps.begin();
+  EXPECT_EQ(0xa000U, (*it)->start);
+  EXPECT_EQ(0xe000U, (*it)->end);
   ++it;
-  ASSERT_EQ(0xa12345U, it->offset);
-  ASSERT_EQ(0xe000U, it->start);
-  ASSERT_EQ(0xf000U, it->end);
-  ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
-  ASSERT_EQ("/system/lib/fake.so", it->name);
+  EXPECT_EQ(0xe000U, (*it)->start);
+  EXPECT_EQ(0xf000U, (*it)->end);
   ++it;
-  ASSERT_EQ(maps.end(), it);
+  EXPECT_EQ(maps.end(), it);
+}
+
+TEST(MapsTest, const_iterate) {
+  BufferMaps maps(
+      "a000-e000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
+      "e000-f000 rw-p 00a12345 00:00 0 /system/lib/fake.so\n");
+
+  ASSERT_TRUE(maps.Parse());
+  ASSERT_EQ(2U, maps.Total());
+
+  Maps::const_iterator it = maps.begin();
+  EXPECT_EQ(0xa000U, (*it)->start);
+  EXPECT_EQ(0xe000U, (*it)->end);
+  ++it;
+  EXPECT_EQ(0xe000U, (*it)->start);
+  EXPECT_EQ(0xf000U, (*it)->end);
+  ++it;
+  EXPECT_EQ(maps.end(), it);
 }
 
 TEST(MapsTest, device) {
@@ -235,18 +296,23 @@
 
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(4U, maps.Total());
-  auto it = maps.begin();
-  ASSERT_TRUE(it->flags & 0x8000);
-  ASSERT_EQ("/dev/", it->name);
-  ++it;
-  ASSERT_TRUE(it->flags & 0x8000);
-  ASSERT_EQ("/dev/does_not_exist", it->name);
-  ++it;
-  ASSERT_FALSE(it->flags & 0x8000);
-  ASSERT_EQ("/dev/ashmem/does_not_exist", it->name);
-  ++it;
-  ASSERT_FALSE(it->flags & 0x8000);
-  ASSERT_EQ("/devsomething/does_not_exist", it->name);
+
+  MapInfo* info = maps.Get(0);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_TRUE(info->flags & 0x8000);
+  EXPECT_EQ("/dev/", info->name);
+
+  info = maps.Get(1);
+  EXPECT_TRUE(info->flags & 0x8000);
+  EXPECT_EQ("/dev/does_not_exist", info->name);
+
+  info = maps.Get(2);
+  EXPECT_FALSE(info->flags & 0x8000);
+  EXPECT_EQ("/dev/ashmem/does_not_exist", info->name);
+
+  info = maps.Get(3);
+  EXPECT_FALSE(info->flags & 0x8000);
+  EXPECT_EQ("/devsomething/does_not_exist", info->name);
 }
 
 TEST(MapsTest, file_smoke) {
@@ -263,26 +329,32 @@
 
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(3U, maps.Total());
-  auto it = maps.begin();
-  ASSERT_EQ(0x7b29b000U, it->start);
-  ASSERT_EQ(0x7b29e000U, it->end);
-  ASSERT_EQ(0xa0000000U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
-  ASSERT_EQ("/fake.so", it->name);
-  ++it;
-  ASSERT_EQ(0x7b2b0000U, it->start);
-  ASSERT_EQ(0x7b2e0000U, it->end);
-  ASSERT_EQ(0xb0000000U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
-  ASSERT_EQ("/fake2.so", it->name);
-  ++it;
-  ASSERT_EQ(0x7b2e0000U, it->start);
-  ASSERT_EQ(0x7b2f0000U, it->end);
-  ASSERT_EQ(0xc0000000U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
-  ASSERT_EQ("/fake3.so", it->name);
-  ++it;
-  ASSERT_EQ(it, maps.end());
+
+  MapInfo* info = maps.Get(0);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0x7b29b000U, info->start);
+  EXPECT_EQ(0x7b29e000U, info->end);
+  EXPECT_EQ(0xa0000000U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+  EXPECT_EQ("/fake.so", info->name);
+
+  info = maps.Get(1);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0x7b2b0000U, info->start);
+  EXPECT_EQ(0x7b2e0000U, info->end);
+  EXPECT_EQ(0xb0000000U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+  EXPECT_EQ("/fake2.so", info->name);
+
+  info = maps.Get(2);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0x7b2e0000U, info->start);
+  EXPECT_EQ(0x7b2f0000U, info->end);
+  EXPECT_EQ(0xc0000000U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+  EXPECT_EQ("/fake3.so", info->name);
+
+  ASSERT_TRUE(maps.Get(3) == nullptr);
 }
 
 TEST(MapsTest, file_no_map_name) {
@@ -299,26 +371,32 @@
 
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(3U, maps.Total());
-  auto it = maps.begin();
-  ASSERT_EQ(0x7b29b000U, it->start);
-  ASSERT_EQ(0x7b29e000U, it->end);
-  ASSERT_EQ(0xa0000000U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
-  ASSERT_EQ("", it->name);
-  ++it;
-  ASSERT_EQ(0x7b2b0000U, it->start);
-  ASSERT_EQ(0x7b2e0000U, it->end);
-  ASSERT_EQ(0xb0000000U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
-  ASSERT_EQ("/fake2.so", it->name);
-  ++it;
-  ASSERT_EQ(0x7b2e0000U, it->start);
-  ASSERT_EQ(0x7b2f0000U, it->end);
-  ASSERT_EQ(0xc0000000U, it->offset);
-  ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
-  ASSERT_EQ("", it->name);
-  ++it;
-  ASSERT_EQ(it, maps.end());
+
+  MapInfo* info = maps.Get(0);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0x7b29b000U, info->start);
+  EXPECT_EQ(0x7b29e000U, info->end);
+  EXPECT_EQ(0xa0000000U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+  EXPECT_EQ("", info->name);
+
+  info = maps.Get(1);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0x7b2b0000U, info->start);
+  EXPECT_EQ(0x7b2e0000U, info->end);
+  EXPECT_EQ(0xb0000000U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+  EXPECT_EQ("/fake2.so", info->name);
+
+  info = maps.Get(2);
+  ASSERT_TRUE(info != nullptr);
+  EXPECT_EQ(0x7b2e0000U, info->start);
+  EXPECT_EQ(0x7b2f0000U, info->end);
+  EXPECT_EQ(0xc0000000U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
+  EXPECT_EQ("", info->name);
+
+  ASSERT_TRUE(maps.Get(3) == nullptr);
 }
 
 // Verify that a file that crosses a buffer is parsed correctly.
@@ -435,10 +513,10 @@
   ASSERT_EQ(5000U, maps.Total());
   for (size_t i = 0; i < 5000; i++) {
     MapInfo* info = maps.Get(i);
-    ASSERT_EQ(start + i * 4096, info->start) << "Failed at map " + std::to_string(i);
-    ASSERT_EQ(start + (i + 1) * 4096, info->end) << "Failed at map " + std::to_string(i);
+    EXPECT_EQ(start + i * 4096, info->start) << "Failed at map " + std::to_string(i);
+    EXPECT_EQ(start + (i + 1) * 4096, info->end) << "Failed at map " + std::to_string(i);
     std::string name = "/fake" + std::to_string(i) + ".so";
-    ASSERT_EQ(name, info->name) << "Failed at map " + std::to_string(i);
+    EXPECT_EQ(name, info->name) << "Failed at map " + std::to_string(i);
   }
 }
 
@@ -452,52 +530,52 @@
   ASSERT_TRUE(maps.Parse());
   ASSERT_EQ(5U, maps.Total());
 
-  ASSERT_TRUE(maps.Find(0x500) == nullptr);
-  ASSERT_TRUE(maps.Find(0x2000) == nullptr);
-  ASSERT_TRUE(maps.Find(0x5010) == nullptr);
-  ASSERT_TRUE(maps.Find(0x9a00) == nullptr);
-  ASSERT_TRUE(maps.Find(0xf000) == nullptr);
-  ASSERT_TRUE(maps.Find(0xf010) == nullptr);
+  EXPECT_TRUE(maps.Find(0x500) == nullptr);
+  EXPECT_TRUE(maps.Find(0x2000) == nullptr);
+  EXPECT_TRUE(maps.Find(0x5010) == nullptr);
+  EXPECT_TRUE(maps.Find(0x9a00) == nullptr);
+  EXPECT_TRUE(maps.Find(0xf000) == nullptr);
+  EXPECT_TRUE(maps.Find(0xf010) == nullptr);
 
   MapInfo* info = maps.Find(0x1000);
   ASSERT_TRUE(info != nullptr);
-  ASSERT_EQ(0x1000U, info->start);
-  ASSERT_EQ(0x2000U, info->end);
-  ASSERT_EQ(0x10U, info->offset);
-  ASSERT_EQ(PROT_READ, info->flags);
-  ASSERT_EQ("/system/lib/fake1.so", info->name);
+  EXPECT_EQ(0x1000U, info->start);
+  EXPECT_EQ(0x2000U, info->end);
+  EXPECT_EQ(0x10U, info->offset);
+  EXPECT_EQ(PROT_READ, info->flags);
+  EXPECT_EQ("/system/lib/fake1.so", info->name);
 
   info = maps.Find(0x3020);
   ASSERT_TRUE(info != nullptr);
-  ASSERT_EQ(0x3000U, info->start);
-  ASSERT_EQ(0x4000U, info->end);
-  ASSERT_EQ(0x20U, info->offset);
-  ASSERT_EQ(PROT_WRITE, info->flags);
-  ASSERT_EQ("/system/lib/fake2.so", info->name);
+  EXPECT_EQ(0x3000U, info->start);
+  EXPECT_EQ(0x4000U, info->end);
+  EXPECT_EQ(0x20U, info->offset);
+  EXPECT_EQ(PROT_WRITE, info->flags);
+  EXPECT_EQ("/system/lib/fake2.so", info->name);
 
   info = maps.Find(0x6020);
   ASSERT_TRUE(info != nullptr);
-  ASSERT_EQ(0x6000U, info->start);
-  ASSERT_EQ(0x8000U, info->end);
-  ASSERT_EQ(0x30U, info->offset);
-  ASSERT_EQ(PROT_EXEC, info->flags);
-  ASSERT_EQ("/system/lib/fake3.so", info->name);
+  EXPECT_EQ(0x6000U, info->start);
+  EXPECT_EQ(0x8000U, info->end);
+  EXPECT_EQ(0x30U, info->offset);
+  EXPECT_EQ(PROT_EXEC, info->flags);
+  EXPECT_EQ("/system/lib/fake3.so", info->name);
 
   info = maps.Find(0xafff);
   ASSERT_TRUE(info != nullptr);
-  ASSERT_EQ(0xa000U, info->start);
-  ASSERT_EQ(0xb000U, info->end);
-  ASSERT_EQ(0x40U, info->offset);
-  ASSERT_EQ(PROT_READ | PROT_WRITE, info->flags);
-  ASSERT_EQ("/system/lib/fake4.so", info->name);
+  EXPECT_EQ(0xa000U, info->start);
+  EXPECT_EQ(0xb000U, info->end);
+  EXPECT_EQ(0x40U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
+  EXPECT_EQ("/system/lib/fake4.so", info->name);
 
   info = maps.Find(0xe500);
   ASSERT_TRUE(info != nullptr);
-  ASSERT_EQ(0xe000U, info->start);
-  ASSERT_EQ(0xf000U, info->end);
-  ASSERT_EQ(0x50U, info->offset);
-  ASSERT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags);
-  ASSERT_EQ("/system/lib/fake5.so", info->name);
+  EXPECT_EQ(0xe000U, info->start);
+  EXPECT_EQ(0xf000U, info->end);
+  EXPECT_EQ(0x50U, info->offset);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags);
+  EXPECT_EQ("/system/lib/fake5.so", info->name);
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 2a02669..3320f77 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -147,28 +147,29 @@
 }
 
 TEST_F(RegsTest, elf_invalid) {
-  Elf invalid_elf(new MemoryFake);
   RegsArm regs_arm;
   RegsArm64 regs_arm64;
   RegsX86 regs_x86;
   RegsX86_64 regs_x86_64;
-  MapInfo map_info{.start = 0x1000, .end = 0x2000};
+  MapInfo map_info(0x1000, 0x2000);
+  Elf* invalid_elf = new Elf(new MemoryFake);
+  map_info.elf = invalid_elf;
 
   regs_arm.set_pc(0x1500);
-  ASSERT_EQ(0x500U, invalid_elf.GetRelPc(regs_arm.pc(), &map_info));
-  ASSERT_EQ(0x500U, regs_arm.GetAdjustedPc(0x500U, &invalid_elf));
+  EXPECT_EQ(0x500U, invalid_elf->GetRelPc(regs_arm.pc(), &map_info));
+  EXPECT_EQ(0x500U, regs_arm.GetAdjustedPc(0x500U, invalid_elf));
 
   regs_arm64.set_pc(0x1600);
-  ASSERT_EQ(0x600U, invalid_elf.GetRelPc(regs_arm64.pc(), &map_info));
-  ASSERT_EQ(0x600U, regs_arm64.GetAdjustedPc(0x600U, &invalid_elf));
+  EXPECT_EQ(0x600U, invalid_elf->GetRelPc(regs_arm64.pc(), &map_info));
+  EXPECT_EQ(0x600U, regs_arm64.GetAdjustedPc(0x600U, invalid_elf));
 
   regs_x86.set_pc(0x1700);
-  ASSERT_EQ(0x700U, invalid_elf.GetRelPc(regs_x86.pc(), &map_info));
-  ASSERT_EQ(0x700U, regs_x86.GetAdjustedPc(0x700U, &invalid_elf));
+  EXPECT_EQ(0x700U, invalid_elf->GetRelPc(regs_x86.pc(), &map_info));
+  EXPECT_EQ(0x700U, regs_x86.GetAdjustedPc(0x700U, invalid_elf));
 
   regs_x86_64.set_pc(0x1800);
-  ASSERT_EQ(0x800U, invalid_elf.GetRelPc(regs_x86_64.pc(), &map_info));
-  ASSERT_EQ(0x800U, regs_x86_64.GetAdjustedPc(0x800U, &invalid_elf));
+  EXPECT_EQ(0x800U, invalid_elf->GetRelPc(regs_x86_64.pc(), &map_info));
+  EXPECT_EQ(0x800U, regs_x86_64.GetAdjustedPc(0x800U, invalid_elf));
 }
 
 TEST_F(RegsTest, arm_set_from_raw) {
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 9f9ca8b..66c8ba6 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -311,4 +311,39 @@
   RemoteThroughSignal(SIGSEGV, SA_SIGINFO);
 }
 
+// Verify that using the same map while unwinding multiple threads at the
+// same time doesn't cause problems.
+TEST_F(UnwindTest, multiple_threads_unwind_same_map) {
+  static constexpr size_t kNumConcurrentThreads = 100;
+
+  LocalMaps maps;
+  ASSERT_TRUE(maps.Parse());
+  auto process_memory(Memory::CreateProcessMemory(getpid()));
+
+  std::vector<std::thread*> threads;
+
+  std::atomic_bool wait;
+  wait = true;
+  size_t frames[kNumConcurrentThreads];
+  for (size_t i = 0; i < kNumConcurrentThreads; i++) {
+    std::thread* thread = new std::thread([i, &frames, &maps, &process_memory, &wait]() {
+      while (wait)
+        ;
+      std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
+      RegsGetLocal(regs.get());
+
+      Unwinder unwinder(512, &maps, regs.get(), process_memory);
+      unwinder.Unwind();
+      frames[i] = unwinder.NumFrames();
+      ASSERT_LE(3U, frames[i]) << "Failed for thread " << i;
+    });
+    threads.push_back(thread);
+  }
+  wait = false;
+  for (auto thread : threads) {
+    thread->join();
+    delete thread;
+  }
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 869d118..098459e 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -45,82 +45,51 @@
 
   void FakeClear() { maps_.clear(); }
 
-  void FakeAddMapInfo(const MapInfo& map_info) { maps_.push_back(map_info); }
+  void FakeAddMapInfo(MapInfo* map_info) { maps_.push_back(map_info); }
 };
 
 class UnwinderTest : public ::testing::Test {
  protected:
   static void SetUpTestCase() {
     maps_.FakeClear();
-    MapInfo info;
-    info.name = "/system/fake/libc.so";
-    info.start = 0x1000;
-    info.end = 0x8000;
-    info.offset = 0;
-    info.flags = PROT_READ | PROT_WRITE;
+    MapInfo* info = new MapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so");
     ElfFake* elf = new ElfFake(nullptr);
-    info.elf = elf;
+    info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
-    info.elf_offset = 0;
     maps_.FakeAddMapInfo(info);
 
-    info.name = "[stack]";
-    info.start = 0x10000;
-    info.end = 0x12000;
-    info.flags = PROT_READ | PROT_WRITE;
-    info.elf = nullptr;
+    info = new MapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
     maps_.FakeAddMapInfo(info);
 
-    info.name = "/dev/fake_device";
-    info.start = 0x13000;
-    info.end = 0x15000;
-    info.flags = PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP;
-    info.elf = nullptr;
+    info = new MapInfo(0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP,
+                       "/dev/fake_device");
     maps_.FakeAddMapInfo(info);
 
-    info.name = "/system/fake/libunwind.so";
-    info.start = 0x20000;
-    info.end = 0x22000;
-    info.flags = PROT_READ | PROT_WRITE;
+    info = new MapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so");
     elf = new ElfFake(nullptr);
-    info.elf = elf;
+    info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
-    info.name = "/fake/libanother.so";
-    info.start = 0x23000;
-    info.end = 0x24000;
-    info.flags = PROT_READ | PROT_WRITE;
+    info = new MapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so");
     elf = new ElfFake(nullptr);
-    info.elf = elf;
+    info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
-    info.name = "/fake/compressed.so";
-    info.start = 0x33000;
-    info.end = 0x34000;
-    info.flags = PROT_READ | PROT_WRITE;
+    info = new MapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so");
     elf = new ElfFake(nullptr);
-    info.elf = elf;
+    info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
-    info.name = "/fake/fake.apk";
-    info.start = 0x43000;
-    info.end = 0x44000;
-    info.offset = 0x1d000;
-    info.flags = PROT_READ | PROT_WRITE;
+    info = new MapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk");
     elf = new ElfFake(nullptr);
-    info.elf = elf;
+    info->elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
-    info.name = "/fake/fake.oat";
-    info.start = 0x53000;
-    info.end = 0x54000;
-    info.offset = 0;
-    info.flags = PROT_READ | PROT_WRITE;
-    info.elf = nullptr;
+    info = new MapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
     maps_.FakeAddMapInfo(info);
   }