Wed, 19 Jun 2019 09:42:12 +0900
8225636: SA can't handle prelinked libraries
Reviewed-by: sspitsyn, cjplummer
agent/src/os/linux/ps_core.c | file | annotate | diff | comparison | revisions |
1.1 --- a/agent/src/os/linux/ps_core.c Tue Jun 18 09:33:34 2019 -0400 1.2 +++ b/agent/src/os/linux/ps_core.c Wed Jun 19 09:42:12 2019 +0900 1.3 @@ -865,8 +865,51 @@ 1.4 #define LD_BASE_OFFSET offsetof(struct r_debug, r_ldbase) 1.5 #define LINK_MAP_ADDR_OFFSET offsetof(struct link_map, l_addr) 1.6 #define LINK_MAP_NAME_OFFSET offsetof(struct link_map, l_name) 1.7 +#define LINK_MAP_LD_OFFSET offsetof(struct link_map, l_ld) 1.8 #define LINK_MAP_NEXT_OFFSET offsetof(struct link_map, l_next) 1.9 1.10 +// Calculate the load address of shared library 1.11 +// on prelink-enabled environment. 1.12 +// 1.13 +// In case of GDB, it would be calculated by offset of link_map.l_ld 1.14 +// and the address of .dynamic section. 1.15 +// See GDB implementation: lm_addr_check @ solib-svr4.c 1.16 +static uintptr_t calc_prelinked_load_address(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* elf_ehdr, uintptr_t link_map_addr) { 1.17 + ELF_PHDR *phbuf; 1.18 + uintptr_t lib_ld; 1.19 + uintptr_t lib_dyn_addr = 0L; 1.20 + uintptr_t load_addr; 1.21 + int i; 1.22 + 1.23 + phbuf = read_program_header_table(lib_fd, elf_ehdr); 1.24 + if (phbuf == NULL) { 1.25 + print_debug("can't read program header of shared object\n"); 1.26 + return 0L; 1.27 + } 1.28 + 1.29 + // Get the address of .dynamic section from shared library. 1.30 + for (i = 0; i < elf_ehdr->e_phnum; i++) { 1.31 + if (phbuf[i].p_type == PT_DYNAMIC) { 1.32 + lib_dyn_addr = phbuf[i].p_vaddr; 1.33 + break; 1.34 + } 1.35 + } 1.36 + 1.37 + free(phbuf); 1.38 + 1.39 + if (ps_pdread(ph, (psaddr_t)link_map_addr + LINK_MAP_LD_OFFSET, 1.40 + &lib_ld, sizeof(uintptr_t)) != PS_OK) { 1.41 + print_debug("can't read address of dynamic section in shared object\n"); 1.42 + return 0L; 1.43 + } 1.44 + 1.45 + // Return the load address which is calculated by the address of .dynamic 1.46 + // and link_map.l_ld . 1.47 + load_addr = lib_ld - lib_dyn_addr; 1.48 + print_debug("lib_ld = 0x%lx, lib_dyn_addr = 0x%lx -> lib_base_diff = 0x%lx\n", lib_ld, lib_dyn_addr, load_addr); 1.49 + return load_addr; 1.50 +} 1.51 + 1.52 // read shared library info from runtime linker's data structures. 1.53 // This work is done by librtlb_db in Solaris 1.54 static bool read_shared_lib_info(struct ps_prochandle* ph) { 1.55 @@ -968,6 +1011,14 @@ 1.56 // continue with other libraries... 1.57 } else { 1.58 if (read_elf_header(lib_fd, &elf_ehdr)) { 1.59 + if (lib_base_diff == 0x0L) { 1.60 + lib_base_diff = calc_prelinked_load_address(ph, lib_fd, &elf_ehdr, link_map_addr); 1.61 + if (lib_base_diff == 0x0L) { 1.62 + close(lib_fd); 1.63 + return false; 1.64 + } 1.65 + } 1.66 + 1.67 lib_base = lib_base_diff + find_base_address(lib_fd, &elf_ehdr); 1.68 print_debug("reading library %s @ 0x%lx [ 0x%lx ]\n", 1.69 lib_name, lib_base, lib_base_diff);