From patchwork Tue Jun 23 15:22:53 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Fortune X-Patchwork-Id: 7301 Received: (qmail 53183 invoked by alias); 23 Jun 2015 15:23:01 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 53171 invoked by uid 89); 23 Jun 2015 15:23:00 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.6 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mailapp01.imgtec.com Received: from mailapp01.imgtec.com (HELO mailapp01.imgtec.com) (195.59.15.196) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 23 Jun 2015 15:22:59 +0000 Received: from KLMAIL01.kl.imgtec.org (unknown [192.168.5.35]) by Websense Email Security Gateway with ESMTPS id 7182C17CDE840 for ; Tue, 23 Jun 2015 16:22:52 +0100 (IST) Received: from LEMAIL01.le.imgtec.org (192.168.152.62) by KLMAIL01.kl.imgtec.org (192.168.5.35) with Microsoft SMTP Server (TLS) id 14.3.195.1; Tue, 23 Jun 2015 16:22:55 +0100 Received: from LEMAIL01.le.imgtec.org ([fe80::5ae:ee16:f4b9:cda9]) by LEMAIL01.le.imgtec.org ([fe80::5ae:ee16:f4b9:cda9%17]) with mapi id 14.03.0210.002; Tue, 23 Jun 2015 16:22:54 +0100 From: Matthew Fortune To: "gdb-patches@sourceware.org" Subject: [PATCH, MIPS] Support shared library debug with MIPS PIE (gdb) Date: Tue, 23 Jun 2015 15:22:53 +0000 Message-ID: <6D39441BF12EF246A7ABCE6654B02353211760FA@LEMAIL01.le.imgtec.org> MIME-Version: 1.0 Following on from binutils and glibc submission of DT_MIPS_RLD_MAP2: http://sourceware.org/ml/binutils/2015-06/msg00226.html http://sourceware.org/ml/libc-alpha/2015-06/msg00766.html It is not currently possible to extract dynamic linker maps for MIPS position independent executables. MIPS does not use the DT_DEBUG tag as MIPS has a read-only dynamic section and the MIPS specific DT_MIPS_RLD_MAP tag stores an absolute address of the debug map pointer which is unusable for a PIE. Following previous discussions we are introducing a new dynamic tag as defined below. New dynamic tag: DT_MIPS_RLD_MAP2 - 0x70000035 Definition: This member is used by debugging. It contains a relative offset from the tag's runtime location of a 32-bit word in the .data section which is supplied by the compilation environment. The word's contents are not specified and programs using this value are not ABI - compliant. Please note that the new DT_MIPS_RLD_MAP2 support will not be enabled unless the host's elf.h header has the new tag defined in it. For cross compiled GDB this may mean hacking the solib-svr4.c file to define the macro until such time as distributions update glibc. I'm open to suggestions if anyone can see a neater way to achieve this support in GDB. A number of support functions had to be extended to get the data required. Manually tested with pre and post DT_MIPS_RLD_MAP2 executables and verified that the info sharedlibrary command now works for MIPS PIE. OK to commit? Thanks, Matthew gdb/gdbserver/ * linux-low.c (get_r_debug): Handle DT_MIPS_RLD_MAP2. 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) [DT_MIPS_RLD_MAP2]: Scan for and handle DT_MIPS_RLD_MAP2. --- gdb/gdbserver/linux-low.c | 30 +++++++++++++++++++--- gdb/solib-svr4.c | 65 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 75 insertions(+), 20 deletions(-) diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 3774d17..6ec6bd8 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -6102,14 +6102,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_MAP2 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, @@ -6119,6 +6120,16 @@ get_r_debug (const int pid, const int is_elf64) break; } #endif /* DT_MIPS_RLD_MAP */ +#ifdef DT_MIPS_RLD_MAP2 + if (dyn->d_tag == DT_MIPS_RLD_MAP2) + { + 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_MAP2 */ if (dyn->d_tag == DT_DEBUG && map == -1) map = dyn->d_un.d_val; @@ -6129,14 +6140,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_MAP2 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, @@ -6146,6 +6158,16 @@ get_r_debug (const int pid, const int is_elf64) break; } #endif /* DT_MIPS_RLD_MAP */ +#ifdef DT_MIPS_RLD_MAP2 + if (dyn->d_tag == DT_MIPS_RLD_MAP2) + { + 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_MAP2 */ 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 909dfb7..dd2cdf0 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,29 @@ elf_locate_base (void) return extract_typed_address (pbuf, ptr_type); } +#ifdef DT_MIPS_RLD_MAP2 + /* Then check DT_MIPS_RLD_MAP2. 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_MAP2, exec_bfd, &dyn_ptr, &dyn_ptr_addr) + || scan_dyntag_auxv (DT_MIPS_RLD_MAP2, &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_MAP2 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); + } +#endif /* DT_MIPS_RLD_MAP2 */ + /* 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 +2640,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 +3261,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 NULL; return lookup_global_symbol_from_objfile (objfile, name, domain);