linker: add more context to link failure error.

This change makes it easier to diagnose mistakes in linker
configuration that result in a library being accidentally loaded in
multiple namespaces without its dependencies available everywhere.

Test: manually tested the error message
Test: bionic-unit-tests
Change-Id: I03a20507f8fc902c2445a7fbbf59767ffffd5ebf
diff --git a/linker/linker.cpp b/linker/linker.cpp
index eedce70..a2ac7c8 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1503,7 +1503,16 @@
   // Open the file.
   int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
   if (fd == -1) {
-    DL_OPEN_ERR("library \"%s\" not found", name);
+    if (task->is_dt_needed()) {
+      if (needed_by->is_main_executable()) {
+        DL_OPEN_ERR("library \"%s\" not found: needed by main executable", name);
+      } else {
+        DL_OPEN_ERR("library \"%s\" not found: needed by %s in namespace %s", name,
+                    needed_by->get_realpath(), task->get_start_from()->get_name());
+      }
+    } else {
+      DL_OPEN_ERR("library \"%s\" not found", name);
+    }
     return false;
   }
 
diff --git a/tests/dl_test.cpp b/tests/dl_test.cpp
index 9e46394..b69da97 100644
--- a/tests/dl_test.cpp
+++ b/tests/dl_test.cpp
@@ -204,7 +204,10 @@
 // The two libs are in ns2/ subdir.
 TEST(dl, exec_without_ld_config_file) {
 #if defined(__BIONIC__)
-  std::string error_message = "CANNOT LINK EXECUTABLE \"" + GetTestlibRoot() + "/ld_config_test_helper/ld_config_test_helper\": library \"ld_config_test_helper_lib1.so\" not found\n";
+  std::string error_message =
+      "CANNOT LINK EXECUTABLE \"" + GetTestlibRoot() +
+      "/ld_config_test_helper/ld_config_test_helper\": library \"ld_config_test_helper_lib1.so\" "
+      "not found: needed by main executable\n";
   std::string helper = GetTestlibRoot() +
       "/ld_config_test_helper/ld_config_test_helper";
   chmod(helper.c_str(), 0755);
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index e98d66f..7e772b8 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -28,6 +28,7 @@
 #include <android/dlext.h>
 #include <android-base/file.h>
 #include <android-base/strings.h>
+#include <android-base/test_utils.h>
 
 #include <sys/mman.h>
 #include <sys/types.h>
@@ -1374,7 +1375,10 @@
 
   void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
   ASSERT_TRUE(handle2 == nullptr);
-  ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror());
+  const char* error = dlerror();
+  ASSERT_MATCH(error,
+               R"(dlopen failed: library "libnstest_private_external.so" not found: needed by )"
+               R"(\S+libnstest_root_not_isolated.so in namespace private_isolated1)");
 
   // Check dlopen by absolute path
   handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
@@ -1502,7 +1506,9 @@
 
   void* handle2 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
   ASSERT_TRUE(handle2 == nullptr);
-  ASSERT_STREQ("dlopen failed: library \"libnstest_private_external.so\" not found", dlerror());
+  ASSERT_MATCH(dlerror(),
+               R"(dlopen failed: library "libnstest_private_external.so" not found: needed by )"
+               R"(\S+libnstest_root_not_isolated.so in namespace private_isolated_shared)");
 
   // Check dlopen by absolute path
   handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo);
@@ -1762,7 +1768,10 @@
 
   handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
   ASSERT_TRUE(handle1 == nullptr);
-  ASSERT_STREQ("dlopen failed: library \"libnstest_public.so\" not found", dlerror());
+  ASSERT_MATCH(
+      dlerror(),
+      R"(dlopen failed: library "libnstest_public.so" not found: needed by \S+libnstest_root.so)"
+      R"( in namespace isolated2)");
 }
 
 TEST(dlext, ns_inaccessible_error_message) {