ANDROID: Support debugging libraries loaded by the embedded linker am: bd9a6009ce

Original change: https://android-review.googlesource.com/c/platform/external/musl/+/2088983

Change-Id: If14b631a571d996aeb413d415a58b0c60dfaf64d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/Android.bp b/Android.bp
index 7b7e22e..36fbafd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -444,6 +444,7 @@
     srcs: [
         ":musl_linker_asm",
         "android/ldso_trampoline.cpp",
+        "android/ldso_trampoline_debugger.c",
     ],
     cflags: [
         // These are required to make sure the C code in ldso_trampoline.c
diff --git a/android/ldso_trampoline_debugger.c b/android/ldso_trampoline_debugger.c
new file mode 100644
index 0000000..e316a60
--- /dev/null
+++ b/android/ldso_trampoline_debugger.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Normally gdb and lldb look for a symbol named "_dl_debug_state" in the
+// interpreter to get notified when the dynamic loader has modified the
+// list of shared libraries.  When using the embeded linker, the debugger is not
+// aware of the interpreter (PT_INTERP is unset and auxv AT_BASE is 0) so it
+// doesn't know where to look for the symbol.  It falls back to looking in the
+// executable, so provide a symbol for it to find.  The dynamic loader will
+// need to forward its calls to its own _dl_debug_state symbol to this one.
+//
+// This has to be defined in a .c file because lldb looks for a symbol with
+// DWARF language type DW_LANG_C.
+extern void _dl_debug_state() {
+}
diff --git a/ldso/dynlink.c b/ldso/dynlink.c
index fd0d38e..4bff7ae 100644
--- a/ldso/dynlink.c
+++ b/ldso/dynlink.c
@@ -151,6 +151,7 @@
 static struct fdpic_dummy_loadmap app_dummy_loadmap;
 
 struct debug *_dl_debug_addr = &debug;
+static void (*exe_dl_debug_state)(void) = 0;
 
 extern hidden int __malloc_replaced;
 
@@ -1561,6 +1562,8 @@
 
 static void dl_debug_state(void)
 {
+	if (exe_dl_debug_state)
+		exe_dl_debug_state();
 }
 
 weak_alias(dl_debug_state, _dl_debug_state);
@@ -1983,6 +1986,12 @@
 	if (find_sym(head, "aligned_alloc", 1).dso != &ldso)
 		__aligned_alloc_replaced = 1;
 
+	/* Determine if another DSO is providing the _dl_debug_state symbol
+	 * and forward calls to it. */
+	struct symdef debug_sym = find_sym(head, "_dl_debug_state", 1);
+	if (debug_sym.dso != &ldso)
+		exe_dl_debug_state = (void (*)(void))laddr(debug_sym.dso, debug_sym.sym->st_value);
+
 	/* Switch to runtime mode: any further failures in the dynamic
 	 * linker are a reportable failure rather than a fatal startup
 	 * error. */