Add indicator that an elf is memory backed.

Modify the unwinder library to indicate that at least one of the stack
frames contains an elf file that is unreadable.

Modify debuggerd to display a note about the unreadable frame and a possible
way to fix it.

Bug: 129769339

Test: New unit tests pass.
Test: Ran an app that crashes and has an unreadable file and verified the
Test: message is displayed. Then setenforce 0 and verify the message is
Test: not displayed.
Change-Id: Ibc4fe1d117e9b5840290454e90914ddc698d3cc2
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 0cf3378..2e226da 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -183,6 +183,12 @@
             ],
         },
     },
+
+    product_variables: {
+        debuggable: {
+            cflags: ["-DROOT_POSSIBLE"],
+        },
+    },
 }
 
 cc_test {
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index 94fcfb2..c606970 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -74,10 +74,7 @@
     return;
   }
 
-  unwinder->SetDisplayBuildID(true);
-  for (size_t i = 0; i < unwinder->NumFrames(); i++) {
-    _LOG(&log, logtype::BACKTRACE, "  %s\n", unwinder->FormatFrame(i).c_str());
-  }
+  log_backtrace(&log, unwinder, "  ");
 }
 
 void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 238c00c..f189c45 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -73,9 +73,12 @@
 void _LOG(log_t* log, logtype ltype, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
 
 namespace unwindstack {
+class Unwinder;
 class Memory;
 }
 
+void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix);
+
 void dump_memory(log_t* log, unwindstack::Memory* backtrace, uint64_t addr, const std::string&);
 
 void read_with_default(const char* path, char* buf, size_t len, const char* default_value);
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index cc337ed..d1726cd 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -371,13 +371,6 @@
   }
 }
 
-void dump_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
-  unwinder->SetDisplayBuildID(true);
-  for (size_t i = 0; i < unwinder->NumFrames(); i++) {
-    _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
-  }
-}
-
 static void print_register_row(log_t* log,
                                const std::vector<std::pair<std::string, uint64_t>>& registers) {
   std::string output;
@@ -470,7 +463,7 @@
     _LOG(log, logtype::THREAD, "Failed to unwind");
   } else {
     _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
-    dump_backtrace(log, unwinder, "    ");
+    log_backtrace(log, unwinder, "    ");
 
     _LOG(log, logtype::STACK, "\nstack:\n");
     dump_stack(log, unwinder->frames(), unwinder->GetMaps(), unwinder->GetProcessMemory().get());
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 7aebea8..9b2779a 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -38,6 +38,7 @@
 #include <debuggerd/handler.h>
 #include <log/log.h>
 #include <unwindstack/Memory.h>
+#include <unwindstack/Unwinder.h>
 
 using android::base::unique_fd;
 
@@ -422,3 +423,22 @@
   // Then give up...
   return "?";
 }
+
+void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
+  if (unwinder->elf_from_memory_not_file()) {
+    _LOG(log, logtype::BACKTRACE,
+         "%sNOTE: Function names and BuildId information is missing for some frames due\n", prefix);
+    _LOG(log, logtype::BACKTRACE,
+         "%sNOTE: to unreadable libraries. For unwinds of apps, only shared libraries\n", prefix);
+    _LOG(log, logtype::BACKTRACE, "%sNOTE: found under the lib/ directory are readable.\n", prefix);
+#if defined(ROOT_POSSIBLE)
+    _LOG(log, logtype::BACKTRACE,
+         "%sNOTE: On this device, run setenforce 0 to make the libraries readable.\n", prefix);
+#endif
+  }
+
+  unwinder->SetDisplayBuildID(true);
+  for (size_t i = 0; i < unwinder->NumFrames(); i++) {
+    _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
+  }
+}
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 28373b2..03658b4 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -161,6 +161,7 @@
   // option is used.
   std::unique_ptr<MemoryRange> memory(new MemoryRange(process_memory, start, end - start, 0));
   if (Elf::IsValidElf(memory.get())) {
+    memory_backed_elf = true;
     return memory.release();
   }
 
@@ -184,6 +185,7 @@
       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));
 
+  memory_backed_elf = true;
   return ranges;
 }
 
@@ -237,6 +239,7 @@
     std::lock_guard<std::mutex> guard(prev_map->mutex_);
     if (prev_map->elf.get() == nullptr) {
       prev_map->elf = elf;
+      prev_map->memory_backed_elf = memory_backed_elf;
     }
   }
   return elf.get();
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index f3d2b5e..26626b5 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -141,6 +141,7 @@
   frames_.clear();
   last_error_.code = ERROR_NONE;
   last_error_.address = 0;
+  elf_from_memory_not_file_ = false;
 
   ArchEnum arch = regs_->Arch();
 
@@ -164,6 +165,12 @@
         break;
       }
       elf = map_info->GetElf(process_memory_, arch);
+      // If this elf is memory backed, and there is a valid file, then set
+      // an indicator that we couldn't open the file.
+      if (!elf_from_memory_not_file_ && map_info->memory_backed_elf && !map_info->name.empty() &&
+          map_info->name[0] != '[') {
+        elf_from_memory_not_file_ = true;
+      }
       step_pc = regs_->pc();
       rel_pc = elf->GetRelPc(step_pc, map_info);
       // Everyone except elf data in gdb jit debug maps uses the relative pc.
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index e938986..025fd98 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -75,6 +75,9 @@
   // make it easier to move to a fine grained lock in the future.
   std::atomic_uintptr_t build_id;
 
+  // Set to true if the elf file data is coming from memory.
+  bool memory_backed_elf = false;
+
   // This function guarantees it will never return nullptr.
   Elf* GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch);
 
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 75be209..52b3578 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -111,6 +111,8 @@
   void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
 #endif
 
+  bool elf_from_memory_not_file() { return elf_from_memory_not_file_; }
+
   ErrorCode LastErrorCode() { return last_error_.code; }
   uint64_t LastErrorAddress() { return last_error_.address; }
 
@@ -132,6 +134,9 @@
   bool resolve_names_ = true;
   bool embedded_soname_ = true;
   bool display_build_id_ = false;
+  // True if at least one elf file is coming from memory and not the related
+  // file. This is only true if there is an actual file backing up the elf.
+  bool elf_from_memory_not_file_ = false;
   ErrorData last_error_;
 };
 
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 2ddadef..6be8bdc 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -108,6 +108,7 @@
   info.end = 0x101;
   memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
 }
 
 // Verify that if the offset is non-zero but there is no elf at the offset,
@@ -117,6 +118,7 @@
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0x100U, info.elf_offset);
   EXPECT_EQ(0x100U, info.elf_start_offset);
 
@@ -140,32 +142,40 @@
   // offset to zero.
   info.elf_offset = 0;
   info.elf_start_offset = 0;
+  info.memory_backed_elf = false;
   memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   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;
+  info.memory_backed_elf = false;
   memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   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;
+  info.memory_backed_elf = false;
   memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   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;
+  info.memory_backed_elf = false;
   memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0x100U, info.elf_offset);
   EXPECT_EQ(0U, info.elf_start_offset);
 }
@@ -177,6 +187,7 @@
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0U, info.elf_offset);
   EXPECT_EQ(0x1000U, info.elf_start_offset);
 
@@ -201,6 +212,7 @@
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0U, info.elf_offset);
   EXPECT_EQ(0x1000U, info.elf_start_offset);
 
@@ -218,6 +230,7 @@
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0U, info.elf_offset);
   EXPECT_EQ(0x2000U, info.elf_start_offset);
 
@@ -259,6 +272,7 @@
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_TRUE(info.memory_backed_elf);
 
   memset(buffer.data(), 0, buffer.size());
   ASSERT_TRUE(memory->ReadFully(0, buffer.data(), buffer.size()));
@@ -290,6 +304,7 @@
 
   std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
   ASSERT_TRUE(mem.get() != nullptr);
+  EXPECT_TRUE(map_info->memory_backed_elf);
   EXPECT_EQ(0x4000UL, map_info->elf_offset);
   EXPECT_EQ(0x4000UL, map_info->offset);
   EXPECT_EQ(0U, map_info->elf_start_offset);
@@ -336,6 +351,7 @@
 
   std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
   ASSERT_TRUE(mem.get() != nullptr);
+  EXPECT_TRUE(map_info->memory_backed_elf);
   EXPECT_EQ(0x1000UL, map_info->elf_offset);
   EXPECT_EQ(0xb000UL, map_info->offset);
   EXPECT_EQ(0xa000UL, map_info->elf_start_offset);
@@ -374,6 +390,7 @@
   // extend over the executable segment.
   std::unique_ptr<Memory> memory(map_info->CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(map_info->memory_backed_elf);
   std::vector<uint8_t> buffer(0x100);
   EXPECT_EQ(0x2000U, map_info->offset);
   EXPECT_EQ(0U, map_info->elf_offset);
@@ -388,7 +405,9 @@
   ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET));
   ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr)));
 
+  map_info->memory_backed_elf = false;
   memory.reset(map_info->CreateMemory(process_memory_));
+  EXPECT_FALSE(map_info->memory_backed_elf);
   EXPECT_EQ(0x2000U, map_info->offset);
   EXPECT_EQ(0x1000U, map_info->elf_offset);
   EXPECT_EQ(0x1000U, map_info->elf_start_offset);
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 48e038e..f635021 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -108,6 +108,24 @@
     const auto& info2 = *--maps_->end();
     info2->elf_offset = 0x8000;
 
+    elf = new ElfFake(new MemoryFake);
+    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    AddMapInfo(0xc0000, 0xc1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/unreadable.so", elf);
+    const auto& info3 = *--maps_->end();
+    info3->memory_backed_elf = true;
+
+    elf = new ElfFake(new MemoryFake);
+    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    AddMapInfo(0xc1000, 0xc2000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "[vdso]", elf);
+    const auto& info4 = *--maps_->end();
+    info4->memory_backed_elf = true;
+
+    elf = new ElfFake(new MemoryFake);
+    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    AddMapInfo(0xc2000, 0xc3000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "", elf);
+    const auto& info5 = *--maps_->end();
+    info5->memory_backed_elf = true;
+
     process_memory_.reset(new MemoryFake);
   }
 
@@ -140,6 +158,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -204,6 +223,7 @@
   unwinder.SetResolveNames(false);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -263,6 +283,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -292,6 +313,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -321,6 +343,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -351,6 +374,7 @@
   unwinder.SetEmbeddedSoname(false);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -387,6 +411,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -419,6 +444,7 @@
   Unwinder unwinder(20, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(20U, unwinder.NumFrames());
 
@@ -461,6 +487,7 @@
   std::vector<std::string> skip_libs{"libunwind.so", "libanother.so"};
   unwinder.Unwind(&skip_libs);
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -522,6 +549,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -569,6 +597,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 }
@@ -588,6 +617,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 }
@@ -602,6 +632,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -638,6 +669,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -703,6 +735,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -752,6 +785,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -799,6 +833,7 @@
   std::vector<std::string> skip_names{"libanother.so"};
   unwinder.Unwind(&skip_names);
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(0U, unwinder.NumFrames());
 }
@@ -821,6 +856,7 @@
   std::vector<std::string> suffixes{"oat"};
   unwinder.Unwind(nullptr, &suffixes);
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
   // Make sure the elf was not initialized.
@@ -879,6 +915,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -937,6 +974,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -980,6 +1018,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -1026,6 +1065,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -1084,6 +1124,7 @@
   Unwinder unwinder(1, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -1103,6 +1144,96 @@
   EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
 }
 
+TEST_F(UnwinderTest, elf_from_memory_not_file) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+  regs_.set_pc(0xc0050);
+  regs_.set_sp(0x10000);
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_TRUE(unwinder.elf_from_memory_not_file());
+
+  ASSERT_EQ(1U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x50U, frame->rel_pc);
+  EXPECT_EQ(0xc0050U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("/fake/unreadable.so", frame->map_name);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
+  EXPECT_EQ(0xc0000U, frame->map_start);
+  EXPECT_EQ(0xc1000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
+TEST_F(UnwinderTest, elf_from_memory_but_no_valid_file_with_bracket) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+  regs_.set_pc(0xc1050);
+  regs_.set_sp(0x10000);
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
+
+  ASSERT_EQ(1U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x50U, frame->rel_pc);
+  EXPECT_EQ(0xc1050U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("[vdso]", frame->map_name);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
+  EXPECT_EQ(0xc1000U, frame->map_start);
+  EXPECT_EQ(0xc2000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
+TEST_F(UnwinderTest, elf_from_memory_but_empty_filename) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+  regs_.set_pc(0xc2050);
+  regs_.set_sp(0x10000);
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
+
+  ASSERT_EQ(1U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x50U, frame->rel_pc);
+  EXPECT_EQ(0xc2050U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("", frame->map_name);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
+  EXPECT_EQ(0xc2000U, frame->map_start);
+  EXPECT_EQ(0xc3000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
 // Verify format frame code.
 TEST_F(UnwinderTest, format_frame) {
   RegsFake regs_arm(10);