From patchwork Sun Mar 25 19:19:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 26475 Received: (qmail 34275 invoked by alias); 25 Mar 2018 19:25:10 -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 34206 invoked by uid 89); 25 Mar 2018 19:25:09 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-23.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, KAM_STOCKGEN, T_FILL_THIS_FORM_SHORT, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=Compute, exclude, Exclude 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; Sun, 25 Mar 2018 19:25:07 +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 89676406EA52 for ; Sun, 25 Mar 2018 19:19:47 +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 2F040202699A for ; Sun, 25 Mar 2018 19:19:47 +0000 (UTC) From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH v2 04/15] Calling ifunc functions when resolver has debug info, user symbol same name Date: Sun, 25 Mar 2018 20:19:32 +0100 Message-Id: <20180325191943.8246-5-palves@redhat.com> In-Reply-To: <20180325191943.8246-1-palves@redhat.com> References: <20180325191943.8246-1-palves@redhat.com> In v2: - find_gnu_ifunc is now based on name search. Need exposed by PP64 (see later patches in the series). - Added iterate_over_minimal_symbols function_view overload for that, and made it possible to stop the search if the callback says so. 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 gdb/ChangeLog: yyyy-mm-dd Pedro Alves * c-exp.y (variable production): Prefer ifunc minsyms over regular function symbols. * symtab.c (find_gnu_ifunc): New function. * 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 | 20 ++++++++++++++++---- gdb/linespec.c | 7 ++++--- gdb/minsyms.c | 30 +++++++++++++++++++++++------- gdb/minsyms.h | 13 +++++++++++-- gdb/symtab.c | 32 ++++++++++++++++++++++++++++++++ gdb/symtab.h | 3 +++ 6 files changed, 89 insertions(+), 16 deletions(-) diff --git a/gdb/c-exp.y b/gdb/c-exp.y index e2ea07cd792..723249c1f58 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -1041,10 +1041,22 @@ variable: name_not_typename 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. */ + + bound_minimal_symbol resolver + = find_gnu_ifunc (sym.symbol); + if (resolver.minsym != NULL) + write_exp_msymbol (pstate, resolver); + else + { + 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/linespec.c b/gdb/linespec.c index 1236b3f4754..7ff8dcf3a5b 100644 --- a/gdb/linespec.c +++ b/gdb/linespec.c @@ -4431,7 +4431,7 @@ compare_msyms (const void *a, const void *b) /* Callback for iterate_over_minimal_symbols that adds the symbol to the result. */ -static void +static bool add_minsym (struct minimal_symbol *minsym, void *d) { struct collect_minsyms *info = (struct collect_minsyms *) d; @@ -4446,16 +4446,17 @@ add_minsym (struct minimal_symbol *minsym, void *d) symtab_and_line sal = find_pc_sect_line (func_addr, NULL, 0); if (info->symtab != sal.symtab) - return; + return false; } } /* Exclude data symbols when looking for breakpoint locations. */ if (!info->list_mode && !msymbol_is_function (info->objfile, minsym)) - return; + return false; bound_minimal_symbol_d mo = {minsym, info->objfile}; VEC_safe_push (bound_minimal_symbol_d, info->msyms, &mo); + return false; } /* Search for minimal symbols called NAME. If SEARCH_PSPACE diff --git a/gdb/minsyms.c b/gdb/minsyms.c index 72969b77787..c75c316c08d 100644 --- a/gdb/minsyms.c +++ b/gdb/minsyms.c @@ -469,11 +469,10 @@ linkage_name_str (const lookup_name_info &lookup_name) /* See minsyms.h. */ void -iterate_over_minimal_symbols (struct objfile *objf, - const lookup_name_info &lookup_name, - void (*callback) (struct minimal_symbol *, - void *), - void *user_data) +iterate_over_minimal_symbols + (struct objfile *objf, + const lookup_name_info &lookup_name, + gdb::function_view callback) { /* The first pass is over the ordinary hash table. */ @@ -490,7 +489,8 @@ iterate_over_minimal_symbols (struct objfile *objf, iter = iter->hash_next) { if (mangled_cmp (MSYMBOL_LINKAGE_NAME (iter), name) == 0) - (*callback) (iter, user_data); + if (callback (iter)) + return; } } @@ -509,12 +509,28 @@ iterate_over_minimal_symbols (struct objfile *objf, iter != NULL; iter = iter->demangled_hash_next) if (name_match (MSYMBOL_SEARCH_NAME (iter), lookup_name, NULL)) - (*callback) (iter, user_data); + if (callback (iter)) + return; } } /* See minsyms.h. */ +void +iterate_over_minimal_symbols (struct objfile *objf, + const lookup_name_info &lookup_name, + bool (*callback) (struct minimal_symbol *, + void *), + void *user_data) +{ + iterate_over_minimal_symbols (objf, lookup_name, [&] (minimal_symbol *iter) + { + return callback (iter, user_data); + }); +} + +/* See minsyms.h. */ + struct bound_minimal_symbol lookup_minimal_symbol_text (const char *name, struct objfile *objf) { diff --git a/gdb/minsyms.h b/gdb/minsyms.h index 11a202025d3..6bd34a58058 100644 --- a/gdb/minsyms.h +++ b/gdb/minsyms.h @@ -20,6 +20,8 @@ #ifndef MINSYMS_H #define MINSYMS_H +#include "common/function-view.h" + struct type; /* Several lookup functions return both a minimal symbol and the @@ -266,14 +268,21 @@ struct bound_minimal_symbol lookup_minimal_symbol_by_pc (CORE_ADDR); should that need to be done. For each matching symbol, CALLBACK is called with the symbol and - USER_DATA as arguments. */ + USER_DATA as arguments. If CALLBACK returns true, the search + stops. */ void iterate_over_minimal_symbols (struct objfile *objf, const lookup_name_info &name, - void (*callback) (struct minimal_symbol *, + bool (*callback) (struct minimal_symbol *, void *), void *user_data); +/* Same, but use a gdb::function_view as callback type. */ +void iterate_over_minimal_symbols + (struct objfile *objf, + const lookup_name_info &name, + gdb::function_view callback); + /* Compute the upper bound of MINSYM. The upper bound is the last address thought to be part of the symbol. If the symbol has a size, it is used. Otherwise use the lesser of the next minimal diff --git a/gdb/symtab.c b/gdb/symtab.c index 2b1f9558abe..9d9d447776e 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -4945,6 +4945,38 @@ symbol_is_function_or_method (minimal_symbol *msymbol) } } +/* See symtab.h. */ + +bound_minimal_symbol +find_gnu_ifunc (const symbol *sym) +{ + if (SYMBOL_CLASS (sym) != LOC_BLOCK) + return {}; + + lookup_name_info lookup_name (SYMBOL_SEARCH_NAME (sym), + symbol_name_match_type::SEARCH_NAME); + struct objfile *objfile = symbol_objfile (sym); + + CORE_ADDR address = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); + minimal_symbol *ifunc = NULL; + + iterate_over_minimal_symbols (objfile, lookup_name, + [&] (minimal_symbol *minsym) + { + if (MSYMBOL_TYPE (minsym) == mst_text_gnu_ifunc + && MSYMBOL_VALUE_ADDRESS (objfile, minsym) == address) + { + ifunc = minsym; + return true; + } + return false; + }); + + if (ifunc != NULL) + return {ifunc, objfile}; + return {}; +} + /* Add matching symbols from SYMTAB to the current completion list. */ static void diff --git a/gdb/symtab.h b/gdb/symtab.h index 22b52019ee3..ddf4cb2e310 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -1681,6 +1681,9 @@ extern int find_pc_partial_function (CORE_ADDR, const char **, CORE_ADDR *, extern struct type *find_gnu_ifunc_target_type (CORE_ADDR resolver_funaddr); +/* Find the GNU ifunc minimal symbol that matches SYM. */ +extern bound_minimal_symbol find_gnu_ifunc (const symbol *sym); + extern void clear_pc_function_cache (void); /* Expand symtab containing PC, SECTION if not already expanded. */