diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 8db2d8aeb6..67e1babcba 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2018-04-26 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. + 2018-04-26 Pedro Alves * blockframe.c (find_gnu_ifunc_target_type): New function. diff --git a/gdb/c-exp.y b/gdb/c-exp.y index e2ea07cd79..723249c1f5 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 7ef8012ab5..8951c1e8c4 100644 --- a/gdb/linespec.c +++ b/gdb/linespec.c @@ -4343,6 +4343,7 @@ add_minsym (struct minimal_symbol *minsym, struct objfile *objfile, struct bound_minimal_symbol mo = {minsym, objfile}; msyms->push_back (mo); + return; } /* Search for minimal symbols called NAME. If SEARCH_PSPACE @@ -4383,6 +4384,7 @@ search_minsyms_for_name (struct collect_info *info, add_minsym (msym, objfile, nullptr, info->state->list_mode, &minsyms); + return false; }); } } @@ -4398,6 +4400,7 @@ search_minsyms_for_name (struct collect_info *info, { add_minsym (msym, SYMTAB_OBJFILE (symtab), symtab, info->state->list_mode, &minsyms); + return false; }); } } diff --git a/gdb/minsyms.c b/gdb/minsyms.c index 9d23c4fd4f..7ca3fcccbe 100644 --- a/gdb/minsyms.c +++ b/gdb/minsyms.c @@ -471,7 +471,7 @@ linkage_name_str (const lookup_name_info &lookup_name) void iterate_over_minimal_symbols (struct objfile *objf, const lookup_name_info &lookup_name, - gdb::function_view callback) + gdb::function_view callback) { /* The first pass is over the ordinary hash table. */ { @@ -487,7 +487,8 @@ iterate_over_minimal_symbols iter = iter->hash_next) { if (mangled_cmp (MSYMBOL_LINKAGE_NAME (iter), name) == 0) - callback (iter); + if (callback (iter)) + return; } } @@ -506,7 +507,8 @@ iterate_over_minimal_symbols iter != NULL; iter = iter->demangled_hash_next) if (name_match (MSYMBOL_SEARCH_NAME (iter), lookup_name, NULL)) - callback (iter); + if (callback (iter)) + return; } } diff --git a/gdb/minsyms.h b/gdb/minsyms.h index a2b7ddd703..29d8283c21 100644 --- a/gdb/minsyms.h +++ b/gdb/minsyms.h @@ -269,7 +269,7 @@ struct bound_minimal_symbol lookup_minimal_symbol_by_pc (CORE_ADDR); void iterate_over_minimal_symbols (struct objfile *objf, const lookup_name_info &name, - gdb::function_view callback); + 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 diff --git a/gdb/symtab.c b/gdb/symtab.c index c1ead701ec..92b7ed7538 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -4953,6 +4953,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 83ff6f226d..94b6b24bd5 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -1686,6 +1686,9 @@ extern struct type *find_function_type (CORE_ADDR pc); 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. */