Merge "fortify: import tests from Chrome OS"
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 5a47272..18301e0 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -308,11 +308,11 @@
 static soinfo* __libdl_info = nullptr;
 
 // This is used by the dynamic linker. Every process gets these symbols for free.
-soinfo* get_libdl_info(const char* linker_path, const soinfo& linker_si) {
+soinfo* get_libdl_info(const soinfo& linker_si) {
   CHECK((linker_si.flags_ & FLAG_GNU_HASH) != 0);
 
   if (__libdl_info == nullptr) {
-    __libdl_info = new (__libdl_info_buf) soinfo(&g_default_namespace, linker_path, nullptr, 0, 0);
+    __libdl_info = new (__libdl_info_buf) soinfo(&g_default_namespace, nullptr, nullptr, 0, 0);
     __libdl_info->flags_ |= (FLAG_LINKED | FLAG_GNU_HASH);
     __libdl_info->strtab_ = linker_si.strtab_;
     __libdl_info->symtab_ = linker_si.symtab_;
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 7bc3529..9bb6557 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1222,12 +1222,14 @@
                                          off64_t file_offset,
                                          bool search_linked_namespaces,
                                          soinfo** candidate) {
+  if (file_stat.st_dev == 0 || file_stat.st_ino == 0) {
+    *candidate = nullptr;
+    return false;
+  }
 
   auto predicate = [&](soinfo* si) {
-    return si->get_st_dev() != 0 &&
-           si->get_st_ino() != 0 &&
+    return si->get_st_ino() == file_stat.st_ino &&
            si->get_st_dev() == file_stat.st_dev &&
-           si->get_st_ino() == file_stat.st_ino &&
            si->get_file_offset() == file_offset;
   };
 
diff --git a/linker/linker.h b/linker/linker.h
index 4c89ceb..0f30946 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -99,7 +99,7 @@
 
 void count_relocation(RelocationKind kind);
 
-soinfo* get_libdl_info(const char* linker_path, const soinfo& linker_si);
+soinfo* get_libdl_info(const soinfo& linker_si);
 
 soinfo* find_containing_library(const void* p);
 
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index f576023..612f52f 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -176,11 +176,12 @@
 }
 
 // Initializes an soinfo's link_map_head field using other fields from the
-// soinfo (phdr, phnum, load_bias).
-static void init_link_map_head(soinfo& info, const char* linker_path) {
+// soinfo (phdr, phnum, load_bias). The soinfo's realpath must not change after
+// this function is called.
+static void init_link_map_head(soinfo& info) {
   auto& map = info.link_map_head;
   map.l_addr = info.load_bias;
-  map.l_name = const_cast<char*>(linker_path);
+  map.l_name = const_cast<char*>(info.get_realpath());
   phdr_table_get_dynamic_section(info.phdr, info.phnum, info.load_bias, &map.l_ld, nullptr);
 }
 
@@ -232,9 +233,9 @@
 }
 
 #if defined(__LP64__)
-static char kLinkerPath[] = "/system/bin/linker64";
+static char kFallbackLinkerPath[] = "/system/bin/linker64";
 #else
-static char kLinkerPath[] = "/system/bin/linker";
+static char kFallbackLinkerPath[] = "/system/bin/linker";
 #endif
 
 __printflike(1, 2)
@@ -350,15 +351,11 @@
   const ExecutableInfo exe_info = exe_to_load ? load_executable(exe_to_load) :
                                                 get_executable_info();
 
-  // Assign to a static variable for the sake of the debug map, which needs
-  // a C-style string to last until the program exits.
-  static std::string exe_path = exe_info.path;
-
-  INFO("[ Linking executable \"%s\" ]", exe_path.c_str());
+  INFO("[ Linking executable \"%s\" ]", exe_info.path.c_str());
 
   // Initialize the main exe's soinfo.
   soinfo* si = soinfo_alloc(&g_default_namespace,
-                            exe_path.c_str(), &exe_info.file_stat,
+                            exe_info.path.c_str(), &exe_info.file_stat,
                             0, RTLD_GLOBAL);
   somain = si;
   si->phdr = exe_info.phdr;
@@ -367,7 +364,25 @@
   si->size = phdr_table_get_load_size(si->phdr, si->phnum);
   si->dynamic = nullptr;
   si->set_main_executable();
-  init_link_map_head(*si, exe_path.c_str());
+  init_link_map_head(*si);
+
+  // Use the executable's PT_INTERP string as the solinker filename in the
+  // dynamic linker's module list. gdb reads both PT_INTERP and the module list,
+  // and if the paths for the linker are different, gdb will report that the
+  // PT_INTERP linker path was unloaded once the module list is initialized.
+  // There are three situations to handle:
+  //  - the APEX linker (/system/bin/linker[64] -> /apex/.../linker[64])
+  //  - the ASAN linker (/system/bin/linker_asan[64] -> /apex/.../linker[64])
+  //  - the bootstrap linker (/system/bin/bootstrap/linker[64])
+  const char *interp = phdr_table_get_interpreter_name(somain->phdr, somain->phnum,
+                                                       somain->load_bias);
+  if (interp == nullptr) {
+    // This case can happen if the linker attempts to execute itself
+    // (e.g. "linker64 /system/bin/linker64").
+    interp = kFallbackLinkerPath;
+  }
+  solinker->set_realpath(interp);
+  init_link_map_head(*solinker);
 
   // Register the main executable and the linker upfront to have
   // gdb aware of them before loading the rest of the dependency
@@ -405,7 +420,7 @@
   parse_LD_LIBRARY_PATH(ldpath_env);
   parse_LD_PRELOAD(ldpreload_env);
 
-  std::vector<android_namespace_t*> namespaces = init_default_namespaces(exe_path.c_str());
+  std::vector<android_namespace_t*> namespaces = init_default_namespaces(exe_info.path.c_str());
 
   if (!si->prelink_image()) __linker_cannot_link(g_argv[0]);
 
@@ -695,9 +710,8 @@
   // Initialize static variables. Note that in order to
   // get correct libdl_info we need to call constructors
   // before get_libdl_info().
-  sonext = solist = solinker = get_libdl_info(kLinkerPath, tmp_linker_so);
+  sonext = solist = solinker = get_libdl_info(tmp_linker_so);
   g_default_namespace.add_soinfo(solinker);
-  init_link_map_head(*solinker, kLinkerPath);
 
   ElfW(Addr) start_address = linker_main(args, exe_to_load);
 
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 5f40528..d4b2541 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -550,6 +550,16 @@
   rtld_flags_ |= RTLD_NODELETE;
 }
 
+void soinfo::set_realpath(const char* path) {
+#if defined(__work_around_b_24465209__)
+  if (has_min_version(2)) {
+    realpath_ = path;
+  }
+#else
+  realpath_ = path;
+#endif
+}
+
 const char* soinfo::get_realpath() const {
 #if defined(__work_around_b_24465209__)
   if (has_min_version(2)) {
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index 80c51af..27032c2 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -278,6 +278,7 @@
 
   void set_soname(const char* soname);
   const char* get_soname() const;
+  void set_realpath(const char* path);
   const char* get_realpath() const;
   const ElfW(Versym)* get_versym(size_t n) const;
   ElfW(Addr) get_verneed_ptr() const;
@@ -372,7 +373,7 @@
   android_namespace_list_t secondary_namespaces_;
   uintptr_t handle_;
 
-  friend soinfo* get_libdl_info(const char* linker_path, const soinfo& linker_si);
+  friend soinfo* get_libdl_info(const soinfo& linker_si);
 
   // version >= 4
   ElfW(Relr)* relr_;