diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp index 5a47272c1..18301e0e2 100644 --- a/linker/dlfcn.cpp +++ b/linker/dlfcn.cpp @@ -308,11 +308,11 @@ static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8))); 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.h b/linker/linker.h index 4c89cebcd..0f3094616 100644 --- a/linker/linker.h +++ b/linker/linker.h @@ -99,7 +99,7 @@ enum RelocationKind { 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 f5760231a..612f52f88 100644 --- a/linker/linker_main.cpp +++ b/linker/linker_main.cpp @@ -176,11 +176,12 @@ static void add_vdso() { } // 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(linker_path); + map.l_name = const_cast(info.get_realpath()); phdr_table_get_dynamic_section(info.phdr, info.phnum, info.load_bias, &map.l_ld, nullptr); } @@ -232,9 +233,9 @@ static ExecutableInfo get_executable_info() { } #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 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load 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 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load 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 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load parse_LD_LIBRARY_PATH(ldpath_env); parse_LD_PRELOAD(ldpreload_env); - std::vector namespaces = init_default_namespaces(exe_path.c_str()); + std::vector namespaces = init_default_namespaces(exe_info.path.c_str()); if (!si->prelink_image()) __linker_cannot_link(g_argv[0]); @@ -695,9 +710,8 @@ __linker_init_post_relocation(KernelArgumentBlock& args, soinfo& tmp_linker_so) // 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 5f40528e9..d4b25414e 100644 --- a/linker/linker_soinfo.cpp +++ b/linker/linker_soinfo.cpp @@ -550,6 +550,16 @@ void soinfo::set_nodelete() { 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 80c51af9a..27032c2da 100644 --- a/linker/linker_soinfo.h +++ b/linker/linker_soinfo.h @@ -278,6 +278,7 @@ struct soinfo { 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 @@ struct soinfo { 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_;