From: Matthew Fortune Date: Thu, 11 Jun 2015 09:37:31 +0000 (+0100) Subject: Add support for DT_MIPS_RLD_MAP_REL. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a738da3abe2bc02d70521086cf1d0e23565b8fbe;p=binutils-gdb.git Add support for DT_MIPS_RLD_MAP_REL. This tag allows debugging of MIPS position independent executables and provides access to shared library information. gdb/gdbserver/ * linux-low.c (get_r_debug): Handle DT_MIPS_RLD_MAP_REL. gdb/ * solib-svr4.c (read_program_header): Add base_addr argument to report the runtime address of the segment. (find_program_interpreter): Update read_program_header call to pass a NULL pointer for the new argument. (scan_dyntag): Add ptr_addr argument to report the runtime address of the tag payload. (scan_dyntag_auxv): Likewise and use thew new base_addr argument of read_program_header to get the base address of the dynamic segment. (elf_locate_base): Update uses of scan_dyntag, scan_dyntag_auxv and read_program_header. (elf_locate_base): Scan for and handle DT_MIPS_RLD_MAP_REL. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3354358a9b3..be3248e3a1e 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,17 @@ +2015-08-14 Matthew Fortune + + * solib-svr4.c (read_program_header): Add base_addr argument to + report the runtime address of the segment. + (find_program_interpreter): Update read_program_header call to pass + a NULL pointer for the new argument. + (scan_dyntag): Add ptr_addr argument to report the runtime address + of the tag payload. + (scan_dyntag_auxv): Likewise and use thew new base_addr argument of + read_program_header to get the base address of the dynamic segment. + (elf_locate_base): Update uses of scan_dyntag, scan_dyntag_auxv and + read_program_header. + (elf_locate_base): Scan for and handle DT_MIPS_RLD_MAP_REL. + 2015-08-14 Matthew Fortune * MAINTAINERS (Write After Approval): Add Matthew Fortune. diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 4f64e43cbcb..7f52fb8f9fc 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,7 @@ +2015-08-14 Matthew Fortune + + * linux-low.c (get_r_debug): Handle DT_MIPS_RLD_MAP_REL. + 2015-08-06 Pedro Alves * tracepoint.c (expr_eval_result): Now an int. diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 792c1782b0e..c37c6d2f3d5 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -6324,14 +6324,15 @@ get_r_debug (const int pid, const int is_elf64) if (is_elf64) { Elf64_Dyn *const dyn = (Elf64_Dyn *) buf; -#ifdef DT_MIPS_RLD_MAP +#if defined DT_MIPS_RLD_MAP || defined DT_MIPS_RLD_MAP_REL union { Elf64_Xword map; unsigned char buf[sizeof (Elf64_Xword)]; } rld_map; - +#endif +#ifdef DT_MIPS_RLD_MAP if (dyn->d_tag == DT_MIPS_RLD_MAP) { if (linux_read_memory (dyn->d_un.d_val, @@ -6341,6 +6342,16 @@ get_r_debug (const int pid, const int is_elf64) break; } #endif /* DT_MIPS_RLD_MAP */ +#ifdef DT_MIPS_RLD_MAP_REL + if (dyn->d_tag == DT_MIPS_RLD_MAP_REL) + { + if (linux_read_memory (dyn->d_un.d_val + dynamic_memaddr, + rld_map.buf, sizeof (rld_map.buf)) == 0) + return rld_map.map; + else + break; + } +#endif /* DT_MIPS_RLD_MAP_REL */ if (dyn->d_tag == DT_DEBUG && map == -1) map = dyn->d_un.d_val; @@ -6351,14 +6362,15 @@ get_r_debug (const int pid, const int is_elf64) else { Elf32_Dyn *const dyn = (Elf32_Dyn *) buf; -#ifdef DT_MIPS_RLD_MAP +#if defined DT_MIPS_RLD_MAP || defined DT_MIPS_RLD_MAP_REL union { Elf32_Word map; unsigned char buf[sizeof (Elf32_Word)]; } rld_map; - +#endif +#ifdef DT_MIPS_RLD_MAP if (dyn->d_tag == DT_MIPS_RLD_MAP) { if (linux_read_memory (dyn->d_un.d_val, @@ -6368,6 +6380,16 @@ get_r_debug (const int pid, const int is_elf64) break; } #endif /* DT_MIPS_RLD_MAP */ +#ifdef DT_MIPS_RLD_MAP_REL + if (dyn->d_tag == DT_MIPS_RLD_MAP_REL) + { + if (linux_read_memory (dyn->d_un.d_val + dynamic_memaddr, + rld_map.buf, sizeof (rld_map.buf)) == 0) + return rld_map.map; + else + break; + } +#endif /* DT_MIPS_RLD_MAP_REL */ if (dyn->d_tag == DT_DEBUG && map == -1) map = dyn->d_un.d_val; diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index 104530cad5b..1fb07d51b6d 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -443,10 +443,12 @@ static int match_main (const char *); Return a pointer to allocated memory holding the program header contents, or NULL on failure. If sucessful, and unless P_SECT_SIZE is NULL, the size of those contents is returned to P_SECT_SIZE. Likewise, the target - architecture size (32-bit or 64-bit) is returned to P_ARCH_SIZE. */ + architecture size (32-bit or 64-bit) is returned to P_ARCH_SIZE and + the base address of the section is returned in BASE_ADDR. */ static gdb_byte * -read_program_header (int type, int *p_sect_size, int *p_arch_size) +read_program_header (int type, int *p_sect_size, int *p_arch_size, + CORE_ADDR *base_addr) { enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); CORE_ADDR at_phdr, at_phent, at_phnum, pt_phdr = 0; @@ -576,6 +578,8 @@ read_program_header (int type, int *p_sect_size, int *p_arch_size) *p_arch_size = arch_size; if (p_sect_size) *p_sect_size = sect_size; + if (base_addr) + *base_addr = sect_addr; return buf; } @@ -605,7 +609,7 @@ find_program_interpreter (void) /* If we didn't find it, use the target auxillary vector. */ if (!buf) - buf = read_program_header (PT_INTERP, NULL, NULL); + buf = read_program_header (PT_INTERP, NULL, NULL, NULL); return (char *) buf; } @@ -615,7 +619,8 @@ find_program_interpreter (void) found, 1 is returned and the corresponding PTR is set. */ static int -scan_dyntag (const int desired_dyntag, bfd *abfd, CORE_ADDR *ptr) +scan_dyntag (const int desired_dyntag, bfd *abfd, CORE_ADDR *ptr, + CORE_ADDR *ptr_addr) { int arch_size, step, sect_size; long current_dyntag; @@ -695,13 +700,15 @@ scan_dyntag (const int desired_dyntag, bfd *abfd, CORE_ADDR *ptr) { struct type *ptr_type; gdb_byte ptr_buf[8]; - CORE_ADDR ptr_addr; + CORE_ADDR ptr_addr_1; ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; - ptr_addr = dyn_addr + (buf - bufstart) + arch_size / 8; - if (target_read_memory (ptr_addr, ptr_buf, arch_size / 8) == 0) + ptr_addr_1 = dyn_addr + (buf - bufstart) + arch_size / 8; + if (target_read_memory (ptr_addr_1, ptr_buf, arch_size / 8) == 0) dyn_ptr = extract_typed_address (ptr_buf, ptr_type); *ptr = dyn_ptr; + if (ptr_addr) + *ptr_addr = dyn_addr + (buf - bufstart); } return 1; } @@ -715,16 +722,19 @@ scan_dyntag (const int desired_dyntag, bfd *abfd, CORE_ADDR *ptr) is returned and the corresponding PTR is set. */ static int -scan_dyntag_auxv (const int desired_dyntag, CORE_ADDR *ptr) +scan_dyntag_auxv (const int desired_dyntag, CORE_ADDR *ptr, + CORE_ADDR *ptr_addr) { enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); int sect_size, arch_size, step; long current_dyntag; CORE_ADDR dyn_ptr; + CORE_ADDR base_addr; gdb_byte *bufend, *bufstart, *buf; /* Read in .dynamic section. */ - buf = bufstart = read_program_header (PT_DYNAMIC, §_size, &arch_size); + buf = bufstart = read_program_header (PT_DYNAMIC, §_size, &arch_size, + &base_addr); if (!buf) return 0; @@ -761,6 +771,9 @@ scan_dyntag_auxv (const int desired_dyntag, CORE_ADDR *ptr) if (ptr) *ptr = dyn_ptr; + if (ptr_addr) + *ptr_addr = base_addr + buf - bufstart; + xfree (bufstart); return 1; } @@ -786,13 +799,13 @@ static CORE_ADDR elf_locate_base (void) { struct bound_minimal_symbol msymbol; - CORE_ADDR dyn_ptr; + CORE_ADDR dyn_ptr, dyn_ptr_addr; /* Look for DT_MIPS_RLD_MAP first. MIPS executables use this instead of DT_DEBUG, although they sometimes contain an unused DT_DEBUG. */ - if (scan_dyntag (DT_MIPS_RLD_MAP, exec_bfd, &dyn_ptr) - || scan_dyntag_auxv (DT_MIPS_RLD_MAP, &dyn_ptr)) + if (scan_dyntag (DT_MIPS_RLD_MAP, exec_bfd, &dyn_ptr, NULL) + || scan_dyntag_auxv (DT_MIPS_RLD_MAP, &dyn_ptr, NULL)) { struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; gdb_byte *pbuf; @@ -806,9 +819,27 @@ elf_locate_base (void) return extract_typed_address (pbuf, ptr_type); } + /* Then check DT_MIPS_RLD_MAP_REL. MIPS executables now use this form + because of needing to support PIE. DT_MIPS_RLD_MAP will also exist + in non-PIE. */ + if (scan_dyntag (DT_MIPS_RLD_MAP_REL, exec_bfd, &dyn_ptr, &dyn_ptr_addr) + || scan_dyntag_auxv (DT_MIPS_RLD_MAP_REL, &dyn_ptr, &dyn_ptr_addr)) + { + struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr; + gdb_byte *pbuf; + int pbuf_size = TYPE_LENGTH (ptr_type); + + pbuf = alloca (pbuf_size); + /* DT_MIPS_RLD_MAP_REL contains an offset from the address of the + DT slot to the address of the dynamic link structure. */ + if (target_read_memory (dyn_ptr + dyn_ptr_addr, pbuf, pbuf_size)) + return 0; + return extract_typed_address (pbuf, ptr_type); + } + /* Find DT_DEBUG. */ - if (scan_dyntag (DT_DEBUG, exec_bfd, &dyn_ptr) - || scan_dyntag_auxv (DT_DEBUG, &dyn_ptr)) + if (scan_dyntag (DT_DEBUG, exec_bfd, &dyn_ptr, NULL) + || scan_dyntag_auxv (DT_DEBUG, &dyn_ptr, NULL)) return dyn_ptr; /* This may be a static executable. Look for the symbol @@ -2607,7 +2638,7 @@ svr4_exec_displacement (CORE_ADDR *displacementp) gdb_byte *buf, *buf2; int arch_size; - buf = read_program_header (-1, &phdrs_size, &arch_size); + buf = read_program_header (-1, &phdrs_size, &arch_size, NULL); buf2 = read_program_headers_from_bfd (exec_bfd, &phdrs2_size); if (buf != NULL && buf2 != NULL) { @@ -3228,7 +3259,7 @@ elf_lookup_lib_symbol (struct objfile *objfile, abfd = objfile->obfd; } - if (abfd == NULL || scan_dyntag (DT_SYMBOLIC, abfd, NULL) != 1) + if (abfd == NULL || scan_dyntag (DT_SYMBOLIC, abfd, NULL, NULL) != 1) return (struct block_symbol) {NULL, NULL}; return lookup_global_symbol_from_objfile (objfile, name, domain);