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 <final>
(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 <final>
gdb/ChangeLog:
2018-04-26 Pedro Alves <palves@redhat.com>
* 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 <palves@redhat.com>
2018-04-26 Pedro Alves <palves@redhat.com>
+ * 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 <palves@redhat.com>
+
* blockframe.c (find_gnu_ifunc_target_type): New function.
(find_function_type): New.
* eval.c (evaluate_var_msym_value): For GNU ifunc types, always
* blockframe.c (find_gnu_ifunc_target_type): New function.
(find_function_type): New.
* eval.c (evaluate_var_msym_value): For GNU ifunc types, always
if (symbol_read_needs_frame (sym.symbol))
innermost_block.update (sym);
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)
{
}
else if ($1.is_a_field_of_this)
{
struct bound_minimal_symbol mo = {minsym, objfile};
msyms->push_back (mo);
struct bound_minimal_symbol mo = {minsym, objfile};
msyms->push_back (mo);
}
/* Search for minimal symbols called NAME. If SEARCH_PSPACE
}
/* Search for minimal symbols called NAME. If SEARCH_PSPACE
add_minsym (msym, objfile, nullptr,
info->state->list_mode,
&minsyms);
add_minsym (msym, objfile, nullptr,
info->state->list_mode,
&minsyms);
{
add_minsym (msym, SYMTAB_OBJFILE (symtab), symtab,
info->state->list_mode, &minsyms);
{
add_minsym (msym, SYMTAB_OBJFILE (symtab), symtab,
info->state->list_mode, &minsyms);
void
iterate_over_minimal_symbols
(struct objfile *objf, const lookup_name_info &lookup_name,
void
iterate_over_minimal_symbols
(struct objfile *objf, const lookup_name_info &lookup_name,
- gdb::function_view<void (struct minimal_symbol *)> callback)
+ gdb::function_view<bool (struct minimal_symbol *)> callback)
{
/* The first pass is over the ordinary hash table. */
{
{
/* The first pass is over the ordinary hash table. */
{
iter = iter->hash_next)
{
if (mangled_cmp (MSYMBOL_LINKAGE_NAME (iter), name) == 0)
iter = iter->hash_next)
{
if (mangled_cmp (MSYMBOL_LINKAGE_NAME (iter), name) == 0)
+ if (callback (iter))
+ return;
iter != NULL;
iter = iter->demangled_hash_next)
if (name_match (MSYMBOL_SEARCH_NAME (iter), lookup_name, NULL))
iter != NULL;
iter = iter->demangled_hash_next)
if (name_match (MSYMBOL_SEARCH_NAME (iter), lookup_name, NULL))
+ if (callback (iter))
+ return;
void iterate_over_minimal_symbols
(struct objfile *objf, const lookup_name_info &name,
void iterate_over_minimal_symbols
(struct objfile *objf, const lookup_name_info &name,
- gdb::function_view<void (struct minimal_symbol *)> callback);
+ gdb::function_view<bool (struct minimal_symbol *)> 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
/* 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
+/* 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
/* Add matching symbols from SYMTAB to the current completion list. */
static void
extern struct type *find_gnu_ifunc_target_type (CORE_ADDR resolver_funaddr);
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. */
extern void clear_pc_function_cache (void);
/* Expand symtab containing PC, SECTION if not already expanded. */