From patchwork Fri Mar 9 21:16:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 26268 Received: (qmail 73626 invoked by alias); 9 Mar 2018 21:22:32 -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 73504 invoked by uid 89); 9 Mar 2018 21:22:32 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-23.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_STOCKGEN, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy= X-HELO: mx1.redhat.com Received: from mx3-rdu2.redhat.com (HELO mx1.redhat.com) (66.187.233.73) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 09 Mar 2018 21:22:30 +0000 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id F24B9D1440 for ; Fri, 9 Mar 2018 21:16:16 +0000 (UTC) Received: from localhost.localdomain (ovpn04.gateway.prod.ext.ams2.redhat.com [10.39.146.4]) by smtp.corp.redhat.com (Postfix) with ESMTP id A28742026DFD for ; Fri, 9 Mar 2018 21:16:16 +0000 (UTC) From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH 05/11] Calling ifunc functions when resolver has debug info, user symbol same name Date: Fri, 9 Mar 2018 21:16:06 +0000 Message-Id: <20180309211612.12941-6-palves@redhat.com> In-Reply-To: <20180309211612.12941-1-palves@redhat.com> References: <20180309211612.12941-1-palves@redhat.com> If the GNU ifunc resolver has the same name as the user visible symbol, and the resolver has debug info, then the DWARF info for the resolver masks the ifunc minsym. In that scenario, if you try calling the ifunc from GDB, you call the resolver instead. With the gnu-ifunc.exp testcase added in a following patch, you'd see: (gdb) p gnu_ifunc (3) $1 = (int (*)(int)) 0x400753 (gdb) FAIL: gdb.base/gnu-ifunc.exp: resolver_attr=0: resolver_debug=1: resolved_debug=0: p gnu_ifunc (3) ^^^^^^^^^^^^^^^^ That is, we called the ifunc resolver manually, which returned a pointer to the ifunc target function ("final"). The "final" symbol is the function that GDB should have called automatically, ~~~~~~~~~~~~ int final (int arg) { return arg + 1; } ~~~~~~~~~ which is what happens if you don't have debug info for the resolver: (gdb) p gnu_ifunc (3) $1 = 4 (gdb) PASS: gdb.base/gnu-ifunc.exp: resolver_attr=0: resolver_debug=0: resolved_debug=1: p gnu_ifunc (3) ^^^^^^^^^^^^^^^^ or if the resolver's symbol has a different name from the ifunc (as is the case with modern uses of ifunc via __attribute__ ifunc, such as glibc uses): (gdb) p gnu_ifunc (3) $1 = 4 (gdb) PASS: gdb.base/gnu-ifunc.exp: resolver_attr=1: resolver_debug=1: resolved_debug=0: p gnu_ifunc (3) ^^^^^^^^^^^^^^^ in which case after this patch, you can still call the resolver directly if you want: (gdb) p gnu_ifunc_resolver (3) $1 = (int (*)(int)) 0x400753 We need to tweak lookup_minimal_symbol_by_pc_section to make it possible to prefer the mst_text_gnu_ifunc symbol over the regular mst_text symbol, which is the ifunc resolver in this case. gdb/ChangeLog: yyyy-mm-dd Pedro Alves * c-exp.y (variable production): Prefer ifunc minsyms over regular function symbols. * minsyms.c (lookup_minimal_symbol_by_pc_section_1): Rename to ... (lookup_minimal_symbol_by_pc_section): ... this. Replace 'want_trampoline' parameter by a lookup_msym_prefer parameter. Handle it. (lookup_minimal_symbol_by_pc_section): Delete old implementation. (lookup_minimal_symbol_by_pc): Adjust. (in_gnu_ifunc_stub): Prefer GNU ifunc symbols. (find_gnu_ifunc): New function. (lookup_solib_trampoline_symbol_by_pc): Adjust. * minsyms.h (lookup_msym_prefer): New enum. (lookup_minimal_symbol_by_pc_section): Replace 'want_trampoline' parameter by a lookup_msym_prefer parameter. * symtab.h (find_gnu_ifunc): New declaration. --- gdb/c-exp.y | 35 ++++++++++++++++++++--- gdb/minsyms.c | 91 +++++++++++++++++++++++++++++------------------------------ gdb/minsyms.h | 26 +++++++++++++++-- gdb/symtab.h | 4 +++ 4 files changed, 103 insertions(+), 53 deletions(-) diff --git a/gdb/c-exp.y b/gdb/c-exp.y index e2ea07cd792..8d27887849d 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -1038,13 +1038,40 @@ variable: name_not_typename if (sym.symbol) { + bool skip = false; + if (symbol_read_needs_frame (sym.symbol)) innermost_block.update (sym); - write_exp_elt_opcode (pstate, OP_VAR_VALUE); - write_exp_elt_block (pstate, sym.block); - write_exp_elt_sym (pstate, sym.symbol); - write_exp_elt_opcode (pstate, OP_VAR_VALUE); + /* If we found a function, see if it's + an ifunc resolver that has the same + address as the ifunc symbol itself. + If so, prefer the ifunc symbol. */ + if (SYMBOL_CLASS (sym.symbol) == LOC_BLOCK) + { + CORE_ADDR pc = BLOCK_START (SYMBOL_BLOCK_VALUE + (sym.symbol)); + + bound_minimal_symbol msymbol + = find_gnu_ifunc (pc); + if (msymbol.minsym != NULL + && strcmp (MSYMBOL_LINKAGE_NAME + (msymbol.minsym), + SYMBOL_LINKAGE_NAME + (sym.symbol)) == 0) + { + write_exp_msymbol (pstate, msymbol); + skip = true; + } + } + + if (!skip) + { + write_exp_elt_opcode (pstate, OP_VAR_VALUE); + write_exp_elt_block (pstate, sym.block); + write_exp_elt_sym (pstate, sym.symbol); + write_exp_elt_opcode (pstate, OP_VAR_VALUE); + } } else if ($1.is_a_field_of_this) { diff --git a/gdb/minsyms.c b/gdb/minsyms.c index a55c0718fcb..b88550351fb 100644 --- a/gdb/minsyms.c +++ b/gdb/minsyms.c @@ -670,10 +670,9 @@ frob_address (struct objfile *objfile, CORE_ADDR *pc) there are text and trampoline symbols at the same address. Otherwise prefer mst_text symbols. */ -static struct bound_minimal_symbol -lookup_minimal_symbol_by_pc_section_1 (CORE_ADDR pc_in, - struct obj_section *section, - int want_trampoline) +bound_minimal_symbol +lookup_minimal_symbol_by_pc_section (CORE_ADDR pc_in, struct obj_section *section, + lookup_msym_prefer prefer) { int lo; int hi; @@ -683,10 +682,27 @@ lookup_minimal_symbol_by_pc_section_1 (CORE_ADDR pc_in, struct minimal_symbol *best_symbol = NULL; struct objfile *best_objfile = NULL; struct bound_minimal_symbol result; - enum minimal_symbol_type want_type, other_type; + enum minimal_symbol_type want_type; - want_type = want_trampoline ? mst_solib_trampoline : mst_text; - other_type = want_trampoline ? mst_text : mst_solib_trampoline; + if (section == NULL) + { + section = find_pc_section (pc_in); + if (section == NULL) + return {}; + } + + switch (prefer) + { + case lookup_msym_prefer::TEXT: + want_type = mst_text; + break; + case lookup_msym_prefer::TRAMPOLINE: + want_type = mst_solib_trampoline; + break; + case lookup_msym_prefer::GNU_IFUNC: + want_type = mst_text_gnu_ifunc; + break; + } /* We can not require the symbol found to be in section, because e.g. IRIX 6.5 mdebug relies on this code returning an absolute @@ -805,7 +821,7 @@ lookup_minimal_symbol_by_pc_section_1 (CORE_ADDR pc_in, preceding symbol too. If they are otherwise identical prefer that one. */ if (hi > 0 - && MSYMBOL_TYPE (&msymbol[hi]) == other_type + && MSYMBOL_TYPE (&msymbol[hi]) != want_type && MSYMBOL_TYPE (&msymbol[hi - 1]) == want_type && (MSYMBOL_SIZE (&msymbol[hi]) == MSYMBOL_SIZE (&msymbol[hi - 1])) @@ -902,41 +918,12 @@ lookup_minimal_symbol_by_pc_section_1 (CORE_ADDR pc_in, return result; } -struct bound_minimal_symbol -lookup_minimal_symbol_by_pc_section (CORE_ADDR pc, struct obj_section *section) -{ - if (section == NULL) - { - /* NOTE: cagney/2004-01-27: This was using find_pc_mapped_section to - force the section but that (well unless you're doing overlay - debugging) always returns NULL making the call somewhat useless. */ - section = find_pc_section (pc); - if (section == NULL) - { - struct bound_minimal_symbol result; - - memset (&result, 0, sizeof (result)); - return result; - } - } - return lookup_minimal_symbol_by_pc_section_1 (pc, section, 0); -} - /* See minsyms.h. */ struct bound_minimal_symbol lookup_minimal_symbol_by_pc (CORE_ADDR pc) { - struct obj_section *section = find_pc_section (pc); - - if (section == NULL) - { - struct bound_minimal_symbol result; - - memset (&result, 0, sizeof (result)); - return result; - } - return lookup_minimal_symbol_by_pc_section_1 (pc, section, 0); + return lookup_minimal_symbol_by_pc_section (pc, NULL); } /* Return non-zero iff PC is in an STT_GNU_IFUNC function resolver. */ @@ -944,11 +931,26 @@ lookup_minimal_symbol_by_pc (CORE_ADDR pc) int in_gnu_ifunc_stub (CORE_ADDR pc) { - struct bound_minimal_symbol msymbol = lookup_minimal_symbol_by_pc (pc); - + bound_minimal_symbol msymbol + = lookup_minimal_symbol_by_pc_section (pc, NULL, + lookup_msym_prefer::GNU_IFUNC); return msymbol.minsym && MSYMBOL_TYPE (msymbol.minsym) == mst_text_gnu_ifunc; } +/* See symtab.h. */ + +bound_minimal_symbol +find_gnu_ifunc (CORE_ADDR pc) +{ + bound_minimal_symbol msymbol + = lookup_minimal_symbol_by_pc_section (pc, NULL, + lookup_msym_prefer::GNU_IFUNC); + if (MSYMBOL_TYPE (msymbol.minsym) == mst_text_gnu_ifunc + && BMSYMBOL_VALUE_ADDRESS (msymbol) == pc) + return msymbol; + return {}; +} + /* See elf_gnu_ifunc_resolve_addr for its real implementation. */ static CORE_ADDR @@ -1465,12 +1467,9 @@ terminate_minimal_symbol_table (struct objfile *objfile) static struct minimal_symbol * lookup_solib_trampoline_symbol_by_pc (CORE_ADDR pc) { - struct obj_section *section = find_pc_section (pc); - struct bound_minimal_symbol msymbol; - - if (section == NULL) - return NULL; - msymbol = lookup_minimal_symbol_by_pc_section_1 (pc, section, 1); + bound_minimal_symbol msymbol + = lookup_minimal_symbol_by_pc_section (pc, NULL, + lookup_msym_prefer::TRAMPOLINE); if (msymbol.minsym != NULL && MSYMBOL_TYPE (msymbol.minsym) == mst_solib_trampoline) diff --git a/gdb/minsyms.h b/gdb/minsyms.h index 78b32e8d1c4..ddcb5d01e23 100644 --- a/gdb/minsyms.h +++ b/gdb/minsyms.h @@ -238,6 +238,22 @@ struct bound_minimal_symbol lookup_minimal_symbol_solib_trampoline struct minimal_symbol *lookup_minimal_symbol_by_pc_name (CORE_ADDR, const char *, struct objfile *); +enum class lookup_msym_prefer +{ + /* Prefer mst_text symbols. */ + TEXT, + + /* Prefer mst_solib_trampoline symbols when there are text and + trampoline symbols at the same address. Otherwise prefer + mst_text symbols. */ + TRAMPOLINE, + + /* Prefer mst_text_gnu_ifunc symbols when there are text and ifunc + symbols at the same address. Otherwise prefer mst_text + symbols. */ + GNU_IFUNC, +}; + /* Search through the minimal symbol table for each objfile and find the symbol whose address is the largest address that is still less than or equal to PC, and which matches SECTION. @@ -246,11 +262,15 @@ struct minimal_symbol *lookup_minimal_symbol_by_pc_name instead. The result has a non-NULL 'minsym' member if such a symbol is - found, or NULL if PC is not in a suitable range. */ + found, or NULL if PC is not in a suitable range. + + See definition of lookup_msym_prefer for description of PREFER. By + default mst_text symbols are preferred. */ struct bound_minimal_symbol lookup_minimal_symbol_by_pc_section - (CORE_ADDR, - struct obj_section *); + (CORE_ADDR, + struct obj_section *, + lookup_msym_prefer prefer = lookup_msym_prefer::TEXT); /* Backward compatibility: search through the minimal symbol table for a matching PC (no section given). diff --git a/gdb/symtab.h b/gdb/symtab.h index 22b52019ee3..5dc52c58e0e 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -1720,6 +1720,10 @@ extern struct type *basic_lookup_transparent_type (const char *); extern int in_gnu_ifunc_stub (CORE_ADDR pc); +/* Look for a STT_GNU_IFUNC symbol at PC. */ + +extern bound_minimal_symbol find_gnu_ifunc (CORE_ADDR pc); + /* Functions for resolving STT_GNU_IFUNC symbols which are implemented only for ELF symbol files. */