ltrace: Fix incompatibilities with Android linker

- Find libraries in LD_LIBRARY_PATH if relative path is found in debug
  link_map
- Skip main executable
- Skip /system/bin/linker and [vdso]
- Only set proc->e_machine once, as it might be set wrongly if we later
  try to load library that we couldn't find
This commit is contained in:
Michał Bednarski 2016-05-14 17:22:21 +02:00
parent 4a9eb8522e
commit 1fac669cf3
2 changed files with 79 additions and 3 deletions

View File

@ -1,6 +1,8 @@
--- ltrace-2def9f1217374cc8371105993003b2c663aefda7/ltrace-elf.c 2016-04-11 21:30:04.000000000 +0200
+++ src/ltrace-elf.c 2016-05-07 21:23:17.999754862 +0200
@@ -423,7 +423,9 @@
diff --git a/ltrace-elf.c b/ltrace-elf.c
index f439cb0..60f1941 100644
--- a/ltrace-elf.c
+++ b/ltrace-elf.c
@@ -423,7 +423,9 @@ ltelf_destroy(struct ltelf *lte)
debug(DEBUG_FUNCTION, "close_elf()");
elf_end(lte->elf);
close(lte->fd);
@ -11,3 +13,18 @@
}
static void
@@ -1149,9 +1151,11 @@ read_module(struct library *lib, struct process *proc,
* determine whether ABI is supported. This is to get
* reasonable error messages when trying to run 64-bit binary
* with 32-bit ltrace. It is desirable to preserve this. */
- proc->e_machine = lte.ehdr.e_machine;
- proc->e_class = lte.ehdr.e_ident[EI_CLASS];
- get_arch_dep(proc);
+ if (proc->e_machine == 0) {
+ proc->e_machine = lte.ehdr.e_machine;
+ proc->e_class = lte.ehdr.e_ident[EI_CLASS];
+ get_arch_dep(proc);
+ }
/* Find out the base address. For PIE main binaries we look
* into auxv, otherwise we scan phdrs. */

View File

@ -0,0 +1,59 @@
diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c
index 953fd86..bdb96cb 100644
--- a/sysdeps/linux-gnu/proc.c
+++ b/sysdeps/linux-gnu/proc.c
@@ -524,9 +524,53 @@ crawl_linkmap(struct process *proc, struct lt_r_debug_64 *dbg)
|| strcmp(lib_name, "linux-vdso.so.1") == 0
|| strcmp(lib_name, "linux-gate.so.1") == 0
|| strcmp(lib_name, "linux-vdso32.so.1") == 0
- || strcmp(lib_name, "linux-vdso64.so.1") == 0)
+ || strcmp(lib_name, "linux-vdso64.so.1") == 0
+ || strcmp(lib_name, "[vdso]") == 0
+ /* Android linker includes itself in list of libraries
+ * on GNU linker it appears as empty string */
+ || strcmp(lib_name, "/system/bin/linker") == 0
+ || strcmp(lib_name, "/system/bin/linker64") == 0)
continue;
+ /* On Android main executable is included in library list
+ * On GNU it appears as empty string */
+ if (rlm.l_prev == 0 && strstr(lib_name, ".so") == NULL) {
+ continue;
+ }
+
+ /* Android < 6 provides just library name without full path,
+ * will find full path ourselves */
+ if (lib_name[0] != '/') {
+ char local_path[1024];
+ /* Include path from LD_LIBRARY_PATH */
+ const char *path = getenv("LD_LIBRARY_PATH");
+ if (path) {
+ strlcpy(local_path, path, sizeof(local_path));
+ } else {
+ local_path[0] = '\0';
+ }
+ /* Include default path (hardcoded in /system/bin/linker) */
+ strlcat(
+ local_path,
+ select_32_64(proc, ":/vendor/lib:/system/lib", ":/vendor/lib64:/system/lib64"),
+ sizeof(local_path)
+ );
+
+ char *local_path_ptr = local_path;
+ const char *tested_path;
+ char full_lib_name[BUFSIZ];
+ while ((tested_path = strsep(&local_path_ptr, ":"))) {
+ if (tested_path[0] == '\0') {
+ continue;
+ }
+ snprintf(full_lib_name, sizeof(full_lib_name), "%s/%s", tested_path, lib_name);
+ if (access(full_lib_name, F_OK) == 0) {
+ strlcpy(lib_name, full_lib_name, sizeof(lib_name));
+ break;
+ }
+ }
+ }
+
/* Do we have that library already? */
if (proc_each_library(proc, NULL, library_with_key_cb, &key))
continue;