Update for accurate unreadable elf files.

The functionality moved from the Unwinder object to the MapInfo
object and means that the individual unreadable files can be
displayed now.

Included adding the unreadable elfs per thread in the protobuf.

Updated the unwinder test.

Test: All unit tests pass.
Change-Id: I7140bde16938736da005f926e10bbdb3dbc0f6f5
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 85adbea..a5e2413 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -1825,9 +1825,9 @@
 TEST_F(CrasherTest, unreadable_elf) {
   int intercept_result;
   unique_fd output_fd;
-  StartProcess([]() {
+  std::string tmp_so_name;
+  StartProcess([&tmp_so_name]() {
     TemporaryDir td;
-    std::string tmp_so_name;
     if (!CopySharedLibrary(td.path, &tmp_so_name)) {
       _exit(1);
     }
@@ -1857,6 +1857,8 @@
   std::string result;
   ConsumeFd(std::move(output_fd), &result);
   ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
+  std::string match_str = "NOTE:   " + tmp_so_name;
+  ASSERT_MATCH(result, match_str);
 }
 
 TEST(tombstoned, proto) {
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp
index 3e31bb7..bee4a67 100644
--- a/debuggerd/libdebuggerd/tombstone_proto.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto.cpp
@@ -35,6 +35,7 @@
 
 #include <memory>
 #include <optional>
+#include <set>
 #include <string>
 
 #include <async_safe/log.h>
@@ -419,18 +420,29 @@
     return;
   }
 
-  if (unwinder->elf_from_memory_not_file()) {
+  unwinder->SetDisplayBuildID(true);
+  std::set<std::string> unreadable_elf_files;
+  for (const auto& frame : unwinder->frames()) {
+    BacktraceFrame* f = thread.add_current_backtrace();
+    fill_in_backtrace_frame(f, frame);
+    if (frame.map_info != nullptr && frame.map_info->ElfFileNotReadable()) {
+      unreadable_elf_files.emplace(frame.map_info->name());
+    }
+  }
+
+  if (!unreadable_elf_files.empty()) {
+    auto unreadable_elf_files_proto = thread.mutable_unreadable_elf_files();
     auto backtrace_note = thread.mutable_backtrace_note();
     *backtrace_note->Add() =
         "Function names and BuildId information is missing for some frames due";
     *backtrace_note->Add() = "to unreadable libraries. For unwinds of apps, only shared libraries";
     *backtrace_note->Add() = "found under the lib/ directory are readable.";
     *backtrace_note->Add() = "On this device, run setenforce 0 to make the libraries readable.";
-  }
-  unwinder->SetDisplayBuildID(true);
-  for (const auto& frame : unwinder->frames()) {
-    BacktraceFrame* f = thread.add_current_backtrace();
-    fill_in_backtrace_frame(f, frame);
+    *backtrace_note->Add() = "Unreadable libraries:";
+    for (auto& name : unreadable_elf_files) {
+      *backtrace_note->Add() = "  " + name;
+      *unreadable_elf_files_proto->Add() = name;
+    }
   }
 }
 
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 543a67c..ecd98a4 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -28,6 +28,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <set>
 #include <string>
 
 #include <android-base/properties.h>
@@ -483,7 +484,16 @@
 }
 
 void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
-  if (unwinder->elf_from_memory_not_file()) {
+  std::set<std::string> unreadable_elf_files;
+  unwinder->SetDisplayBuildID(true);
+  for (const auto& frame : unwinder->frames()) {
+    if (frame.map_info != nullptr && frame.map_info->ElfFileNotReadable()) {
+      unreadable_elf_files.emplace(frame.map_info->name());
+    }
+  }
+
+  // Put the preamble ahead of the backtrace.
+  if (!unreadable_elf_files.empty()) {
     _LOG(log, logtype::BACKTRACE,
          "%sNOTE: Function names and BuildId information is missing for some frames due\n", prefix);
     _LOG(log, logtype::BACKTRACE,
@@ -493,10 +503,13 @@
     _LOG(log, logtype::BACKTRACE,
          "%sNOTE: On this device, run setenforce 0 to make the libraries readable.\n", prefix);
 #endif
+    _LOG(log, logtype::BACKTRACE, "%sNOTE: Unreadable libraries:\n", prefix);
+    for (auto& name : unreadable_elf_files) {
+      _LOG(log, logtype::BACKTRACE, "%sNOTE:   %s\n", prefix, name.c_str());
+    }
   }
 
-  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());
+  for (const auto& frame : unwinder->frames()) {
+    _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(frame).c_str());
   }
 }
diff --git a/debuggerd/proto/tombstone.proto b/debuggerd/proto/tombstone.proto
index 40a942e..a0f2f82 100644
--- a/debuggerd/proto/tombstone.proto
+++ b/debuggerd/proto/tombstone.proto
@@ -123,12 +123,13 @@
   string name = 2;
   repeated Register registers = 3;
   repeated string backtrace_note = 7;
+  repeated string unreadable_elf_files = 9;
   repeated BacktraceFrame current_backtrace = 4;
   repeated MemoryDump memory_dump = 5;
   int64 tagged_addr_ctrl = 6;
   int64 pac_enabled_keys = 8;
 
-  reserved 9 to 999;
+  reserved 10 to 999;
 }
 
 message BacktraceFrame {