aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog10
-rw-r--r--gdb/c-exp.y20
-rw-r--r--gdb/linespec.c3
-rw-r--r--gdb/minsyms.c8
-rw-r--r--gdb/minsyms.h2
-rw-r--r--gdb/symtab.c32
-rw-r--r--gdb/symtab.h3
7 files changed, 70 insertions, 8 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 8db2d8a..67e1bab 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,15 @@
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
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index e2ea07c..723249c 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 7ef8012..8951c1e 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 9d23c4f..7ca3fcc 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<void (struct minimal_symbol *)> callback)
+ gdb::function_view<bool (struct minimal_symbol *)> 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 a2b7ddd..29d8283 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<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
diff --git a/gdb/symtab.c b/gdb/symtab.c
index c1ead70..92b7ed7 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 83ff6f2..94b6b24 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. */