Breakpoints, don't skip prologue of ifunc resolvers with debug info

Without this patch, some of the tests added to gdb.base/gnu-ifunc.exp
by a following patch fail like so:

  FAIL: gdb.base/gnu-ifunc.exp: resolver_attr=0: resolver_debug=1: resolved_debug=0: set-break: before resolving: break gnu_ifunc
  FAIL: gdb.base/gnu-ifunc.exp: resolver_attr=0: resolver_debug=1: resolved_debug=0: set-break: before resolving: info breakpoints
  FAIL: gdb.base/gnu-ifunc.exp: resolver_attr=0: resolver_debug=1: resolved_debug=0: set-break: after resolving: break gnu_ifunc
  FAIL: gdb.base/gnu-ifunc.exp: resolver_attr=0: resolver_debug=1: resolved_debug=0: set-break: after resolving: info breakpoints
  FAIL: gdb.base/gnu-ifunc.exp: resolver_attr=0: resolver_debug=1: resolved_debug=1: set-break: before resolving: break gnu_ifunc
  FAIL: gdb.base/gnu-ifunc.exp: resolver_attr=0: resolver_debug=1: resolved_debug=1: set-break: before resolving: info breakpoints
  FAIL: gdb.base/gnu-ifunc.exp: resolver_attr=0: resolver_debug=1: resolved_debug=1: set-break: after resolving: break gnu_ifunc
  FAIL: gdb.base/gnu-ifunc.exp: resolver_attr=0: resolver_debug=1: resolved_debug=1: set-break: after resolving: info breakpoints

All of them trigger iff:

 - you have debug info for the ifunc resolver.
 - the resolver and the user-visible symbol have the same name.

If you have an ifunc that has a resolver with the same name as the
user visible symbol, debug info for the resolver masks out the ifunc
minsym.  When you set a breakpoint by name on the user visible symbol,
GDB finds the DWARF symbol for the resolver, and thinking that it's a
regular function, sets a breakpoint location past its prologue.

Like so, location 1.2, before the ifunc is resolved by the inferior:

  (gdb) break gnu_ifunc
  Breakpoint 2 at 0x7ffff7bd36ea (2 locations)
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  1       breakpoint     keep y   <MULTIPLE>
  1.1                         y     0x00007ffff7bd36ea <gnu_ifunc>
  1.2                         y     0x00007ffff7bd36f2 in gnu_ifunc at src/gdb/testsuite/gdb.base/gnu-ifunc-lib.c:34
  (gdb)

And like so, location 2.2, if you set the breakpoint after the ifunc
is resolved by the inferior (to "final"):

  (gdb) break gnu_ifunc
  Breakpoint 5 at 0x400757 (2 locations)
  (gdb) info breakpoints
  Num     Type           Disp Enb Address            What
  2       breakpoint     keep y   <MULTIPLE>
  2.1                         y     0x000000000040075a in final at src/gdb/testsuite/gdb.base/gnu-ifunc-resd.c:21
  2.2                         y     0x00007ffff7bd36f2 in gnu_ifunc at src/gdb/testsuite/gdb.base/gnu-ifunc-lib.c:34
  (gdb)

I don't think this is right because when users set a breakpoint at an
ifunc, they don't care about debugging the resolver.  Instead what you
should is a single location for the ifunc in the first case, and a
single location of the ifunc target in the second case.

gdb/ChangeLog:
2018-04-26  Pedro Alves  <palves@redhat.com>

	* linespec.c (struct bound_minimal_symbol_search_key): New.
	(convert_linespec_to_sals): Sort minimal symbols earlier.  Don't
	skip first line if we found a GNU ifunc minimal symbol by name.
	(compare_msymbols): Change parameters to work with a destructured
	lhs minsym.
	(compare_msymbols_for_qsort, compare_msymbols_for_bsearch): New
	functions.
This commit is contained in:
Pedro Alves 2018-04-26 13:01:26 +01:00
parent 3467ec66bc
commit 76af0f2635
2 changed files with 55 additions and 15 deletions

View File

@ -1,3 +1,13 @@
2018-04-26 Pedro Alves <palves@redhat.com>
* linespec.c (struct bound_minimal_symbol_search_key): New.
(convert_linespec_to_sals): Sort minimal symbols earlier. Don't
skip first line if we found a GNU ifunc minimal symbol by name.
(compare_msymbols): Change parameters to work with a destructured
lhs minsym.
(compare_msymbols_for_qsort, compare_msymbols_for_bsearch): New
functions.
2018-04-26 Pedro Alves <palves@redhat.com>
* breakpoint.c (set_breakpoint_location_function): Don't resolve

View File

@ -2258,12 +2258,6 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
else if (ls->function_symbols != NULL || ls->minimal_symbols != NULL)
{
/* We have just a bunch of functions and/or methods. */
int i;
struct symtab_and_line sal;
struct symbol *sym;
bound_minimal_symbol_d *elem;
struct program_space *pspace;
if (ls->function_symbols != NULL)
{
/* Sort symbols so that symbols with the same program space are next
@ -2272,30 +2266,66 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
VEC_length (symbolp, ls->function_symbols),
sizeof (symbolp), compare_symbols);
for (i = 0; VEC_iterate (symbolp, ls->function_symbols, i, sym); ++i)
struct symbol *sym;
for (int i = 0; VEC_iterate (symbolp, ls->function_symbols, i, sym); ++i)
{
pspace = SYMTAB_PSPACE (symbol_symtab (sym));
program_space *pspace = SYMTAB_PSPACE (symbol_symtab (sym));
set_current_program_space (pspace);
if (symbol_to_sal (&sal, state->funfirstline, sym)
&& maybe_add_address (state->addr_set, pspace, sal.pc))
add_sal_to_sals (state, &sals, &sal,
SYMBOL_NATURAL_NAME (sym), 0);
/* Don't skip to the first line of the function if we
had found an ifunc minimal symbol for this function,
because that means that this function is an ifunc
resolver with the same name as the ifunc itself. */
bool found_ifunc = false;
if (state->funfirstline
&& ls->minimal_symbols != NULL
&& SYMBOL_CLASS (sym) == LOC_BLOCK)
{
const CORE_ADDR addr
= BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
bound_minimal_symbol_d *elem;
for (int m = 0;
VEC_iterate (bound_minimal_symbol_d, ls->minimal_symbols,
m, elem);
++m)
{
if (MSYMBOL_TYPE (elem->minsym) == mst_text_gnu_ifunc
&& BMSYMBOL_VALUE_ADDRESS (*elem) == addr)
{
found_ifunc = true;
break;
}
}
}
if (!found_ifunc)
{
symtab_and_line sal;
if (symbol_to_sal (&sal, state->funfirstline, sym)
&& maybe_add_address (state->addr_set, pspace, sal.pc))
add_sal_to_sals (state, &sals, &sal,
SYMBOL_NATURAL_NAME (sym), 0);
}
}
}
if (ls->minimal_symbols != NULL)
{
/* Sort minimal symbols by program space, too. */
/* Sort minimal symbols by program space, too */
qsort (VEC_address (bound_minimal_symbol_d, ls->minimal_symbols),
VEC_length (bound_minimal_symbol_d, ls->minimal_symbols),
sizeof (bound_minimal_symbol_d), compare_msymbols);
for (i = 0;
bound_minimal_symbol_d *elem;
for (int i = 0;
VEC_iterate (bound_minimal_symbol_d, ls->minimal_symbols,
i, elem);
++i)
{
pspace = elem->objfile->pspace;
program_space *pspace = elem->objfile->pspace;
set_current_program_space (pspace);
minsym_found (state, elem->objfile, elem->minsym, &sals);
}