[gdb/breakpoints] Fix longjmp master breakpoint with separate debug info

When running test-case gdb.base/longjmp.exp with target board unix/-m32, we
run into:
...
(gdb) next^M
Warning:^M
Cannot insert breakpoint 0.^M
Cannot access memory at address 0x7dbf7353^M
^M
__libc_siglongjmp (env=0x804a040 <env>, val=1) at longjmp.c:28^M
28        longjmps++;^M
(gdb) FAIL: gdb.base/longjmp.exp: next over longjmp(1)
...

The failure to access memory happens in i386_get_longjmp_target and is due to
glibc having pointer encryption (aka "pointer mangling" or "pointer guard") of
the long jump buffer.  This is a known problem.

In create_longjmp_master_breakpoint (which attempts to install a master
longjmp breakpoint) a preference scheme is present, which installs a
probe breakpoint if a libc:longjmp probe is present, and otherwise falls back
to setting breakpoints at the names in the longjmp_names array.

But in fact, both the probe breakpoint and the longjmp_names breakpoints are
set.  The latter ones are set when processing libc.so.debug, and the former
one when processing libc.so.  In other words, this is the longjmp variant of
PR26881, which describes the same problem for master exception breakpoints.

This problem only triggers when the glibc debug info package is installed,
which is not due to the debug info itself in libc.so.debug, but due to the
minimal symbols (because create_longjmp_master_breakpoint uses minimal symbols
to translate the longjmp_names to addresses).

The problem doesn't trigger for -m64, because there tdep->jb_pc_offset is not
set.

Fix this similar to commit 1940319c0ef (the fix for PR26881): only install
longjmp_names breakpoints in libc.so/libc.so.debug if installing the
libc:longjmp probe in libc.so failed.

Tested on x86_64-linux.

gdb/ChangeLog:

2021-01-28  Tom de Vries  <tdevries@suse.de>

	PR breakpoints/27205
	* breakpoint.c (create_longjmp_master_breakpoint_probe)
	(create_longjmp_master_breakpoint_names): New function, factored out
	of ...
	(create_longjmp_master_breakpoint): ... here.  Only try to install
	longjmp_names breakpoints in libc.so/libc.so.debug if installing probe
	breakpoint in libc.so failed.
This commit is contained in:
Tom de Vries
2021-01-28 10:59:42 +01:00
parent def97fb945
commit 2a7f6487d0
2 changed files with 125 additions and 81 deletions

View File

@ -1,3 +1,13 @@
2021-01-28 Tom de Vries <tdevries@suse.de>
PR breakpoints/27205
* breakpoint.c (create_longjmp_master_breakpoint_probe)
(create_longjmp_master_breakpoint_names): New function, factored out
of ...
(create_longjmp_master_breakpoint): ... here. Only try to install
longjmp_names breakpoints in libc.so/libc.so.debug if installing probe
breakpoint in libc.so failed.
2021-01-27 Lancelot SIX <lsix@lancelotsix.com>
PR gdb/27133

View File

@ -3327,24 +3327,15 @@ create_overlay_event_breakpoint (void)
}
}
static void
create_longjmp_master_breakpoint (void)
/* Install a master longjmp breakpoint for OBJFILE using a probe. Return
true if a breakpoint was installed. */
static bool
create_longjmp_master_breakpoint_probe (objfile *objfile)
{
scoped_restore_current_program_space restore_pspace;
for (struct program_space *pspace : program_spaces)
{
set_current_program_space (pspace);
for (objfile *objfile : current_program_space->objfiles ())
{
int i;
struct gdbarch *gdbarch;
struct breakpoint_objfile_data *bp_objfile_data;
gdbarch = objfile->arch ();
bp_objfile_data = get_breakpoint_objfile_data (objfile);
struct gdbarch *gdbarch = objfile->arch ();
struct breakpoint_objfile_data *bp_objfile_data
= get_breakpoint_objfile_data (objfile);
if (!bp_objfile_data->longjmp_searched)
{
@ -3368,8 +3359,9 @@ create_longjmp_master_breakpoint (void)
bp_objfile_data->longjmp_searched = 1;
}
if (!bp_objfile_data->longjmp_probes.empty ())
{
if (bp_objfile_data->longjmp_probes.empty ())
return false;
for (probe *p : bp_objfile_data->longjmp_probes)
{
struct breakpoint *b;
@ -3382,13 +3374,24 @@ create_longjmp_master_breakpoint (void)
b->enable_state = bp_disabled;
}
continue;
return true;
}
if (!gdbarch_get_longjmp_target_p (gdbarch))
continue;
/* Install master longjmp breakpoints for OBJFILE using longjmp_names.
Return true if at least one breakpoint was installed. */
for (i = 0; i < NUM_LONGJMP_NAMES; i++)
static bool
create_longjmp_master_breakpoint_names (objfile *objfile)
{
struct gdbarch *gdbarch = objfile->arch ();
if (!gdbarch_get_longjmp_target_p (gdbarch))
return false;
struct breakpoint_objfile_data *bp_objfile_data
= get_breakpoint_objfile_data (objfile);
unsigned int installed_bp = 0;
for (int i = 0; i < NUM_LONGJMP_NAMES; i++)
{
struct breakpoint *b;
const char *func_name;
@ -3420,7 +3423,38 @@ create_longjmp_master_breakpoint (void)
explicit_loc.function_name = ASTRDUP (func_name);
b->location = new_explicit_location (&explicit_loc);
b->enable_state = bp_disabled;
installed_bp++;
}
return installed_bp > 0;
}
/* Create a master longjmp breakpoint. */
static void
create_longjmp_master_breakpoint (void)
{
scoped_restore_current_program_space restore_pspace;
for (struct program_space *pspace : program_spaces)
{
set_current_program_space (pspace);
for (objfile *obj : current_program_space->objfiles ())
{
/* Skip separate debug object, it's handled in the loop below. */
if (obj->separate_debug_objfile_backlink != nullptr)
continue;
/* Try a probe kind breakpoint on main objfile. */
if (create_longjmp_master_breakpoint_probe (obj))
continue;
/* Try longjmp_names kind breakpoints on main and separate_debug
objfiles. */
for (objfile *debug_objfile : obj->separate_debug_objfiles ())
if (create_longjmp_master_breakpoint_names (debug_objfile))
break;
}
}
}