Merge "Set elf_start_offset for invalid elf maps."
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index b7650a1..5423de5 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -241,6 +241,7 @@
         "tests/files/offline/debug_frame_first_x86/*",
         "tests/files/offline/debug_frame_load_bias_arm/*",
         "tests/files/offline/eh_frame_hdr_begin_x86_64/*",
+        "tests/files/offline/invalid_elf_offset_arm/*",
         "tests/files/offline/jit_debug_arm/*",
         "tests/files/offline/jit_debug_x86/*",
         "tests/files/offline/jit_map_arm/*",
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 03658b4..d3cec06 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -231,11 +231,13 @@
     }
   }
 
-  // If there is a read-only map then a read-execute map that represents the
-  // same elf object, make sure the previous map is using the same elf
-  // object if it hasn't already been set.
-  if (prev_map != nullptr && elf_start_offset != offset && prev_map->offset == elf_start_offset &&
-      prev_map->name == name) {
+  if (!elf->valid()) {
+    elf_start_offset = offset;
+  } else if (prev_map != nullptr && elf_start_offset != offset &&
+             prev_map->offset == elf_start_offset && prev_map->name == name) {
+    // If there is a read-only map then a read-execute map that represents the
+    // same elf object, make sure the previous map is using the same elf
+    // object if it hasn't already been set.
     std::lock_guard<std::mutex> guard(prev_map->mutex_);
     if (prev_map->elf.get() == nullptr) {
       prev_map->elf = elf;
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 6c64c40..553b344 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -62,7 +62,7 @@
     free(cwd_);
   }
 
-  void Init(const char* file_dir, ArchEnum arch) {
+  void Init(const char* file_dir, ArchEnum arch, bool add_stack = true) {
     dir_ = TestGetFileDirectory() + "offline/" + file_dir;
 
     std::string data;
@@ -71,23 +71,25 @@
     maps_.reset(new BufferMaps(data.c_str()));
     ASSERT_TRUE(maps_->Parse());
 
-    std::string stack_name(dir_ + "stack.data");
-    struct stat st;
-    if (stat(stack_name.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
-      std::unique_ptr<MemoryOffline> stack_memory(new MemoryOffline);
-      ASSERT_TRUE(stack_memory->Init((dir_ + "stack.data").c_str(), 0));
-      process_memory_.reset(stack_memory.release());
-    } else {
-      std::unique_ptr<MemoryOfflineParts> stack_memory(new MemoryOfflineParts);
-      for (size_t i = 0;; i++) {
-        stack_name = dir_ + "stack" + std::to_string(i) + ".data";
-        if (stat(stack_name.c_str(), &st) == -1 || !S_ISREG(st.st_mode)) {
-          ASSERT_TRUE(i != 0) << "No stack data files found.";
-          break;
+    if (add_stack) {
+      std::string stack_name(dir_ + "stack.data");
+      struct stat st;
+      if (stat(stack_name.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
+        std::unique_ptr<MemoryOffline> stack_memory(new MemoryOffline);
+        ASSERT_TRUE(stack_memory->Init((dir_ + "stack.data").c_str(), 0));
+        process_memory_.reset(stack_memory.release());
+      } else {
+        std::unique_ptr<MemoryOfflineParts> stack_memory(new MemoryOfflineParts);
+        for (size_t i = 0;; i++) {
+          stack_name = dir_ + "stack" + std::to_string(i) + ".data";
+          if (stat(stack_name.c_str(), &st) == -1 || !S_ISREG(st.st_mode)) {
+            ASSERT_TRUE(i != 0) << "No stack data files found.";
+            break;
+          }
+          AddMemory(stack_name, stack_memory.get());
         }
-        AddMemory(stack_name, stack_memory.get());
+        process_memory_.reset(stack_memory.release());
       }
-      process_memory_.reset(stack_memory.release());
     }
 
     switch (arch) {
@@ -1442,4 +1444,17 @@
   EXPECT_EQ(0x7be4f07d20ULL, unwinder.frames()[12].sp);
 }
 
+TEST_F(UnwindOfflineTest, invalid_elf_offset_arm) {
+  ASSERT_NO_FATAL_FAILURE(Init("invalid_elf_offset_arm/", ARCH_ARM, false));
+
+  Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+  unwinder.Unwind();
+
+  std::string frame_info(DumpFrames(unwinder));
+  ASSERT_EQ(1U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+  EXPECT_EQ("  #00 pc 00aa7508  invalid.apk (offset 0x12e4000)\n", frame_info);
+  EXPECT_EQ(0xc898f508, unwinder.frames()[0].pc);
+  EXPECT_EQ(0xc2044218, unwinder.frames()[0].sp);
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/files/offline/invalid_elf_offset_arm/maps.txt b/libunwindstack/tests/files/offline/invalid_elf_offset_arm/maps.txt
new file mode 100644
index 0000000..022404c
--- /dev/null
+++ b/libunwindstack/tests/files/offline/invalid_elf_offset_arm/maps.txt
@@ -0,0 +1 @@
+c7ee8000-c8c52fff r-xp  12e4000    00:00 0  invalid.apk
diff --git a/libunwindstack/tests/files/offline/invalid_elf_offset_arm/regs.txt b/libunwindstack/tests/files/offline/invalid_elf_offset_arm/regs.txt
new file mode 100644
index 0000000..b7f10ef
--- /dev/null
+++ b/libunwindstack/tests/files/offline/invalid_elf_offset_arm/regs.txt
@@ -0,0 +1,16 @@
+r0: c0434c00
+r1: 2a4c9fbc
+r2: 00000000
+r3: c83ef1f9
+r4: 00000004
+r5: c2044904
+r6: 00000000
+r7: c20443b8
+r8: 000b33ff
+r9: c20444b0
+r10: cac90740
+r11: 00000000
+ip: ed891ca4
+sp: c2044218
+lr: ed807265
+pc: c898f508