[gdb] Fix internal-error in process_event_stop_test

The function create_exception_master_breakpoint in gdb/breakpoint.c attempts
to set a master exception breakpoint in each objfile.  It tries this using
a libgcc/unwind probe, and if that fails then using the
_Unwind_DebugHook symbol:
...
   for (objfile *objfile : current_program_space->objfiles ())
     {
        /* Try using probes.  */
        if (/* successful */)
          continue;

        /* Try using _Unwind_DebugHook */
     }
...

The preference scheme works ok both if the objfile has debug info, and if it's
stripped.

But it doesn't work when the objfile has a .gnu_debuglink to a .debug file
(and the .debug file is present).  What happens is that:
- we first encounter objfile libgcc.debug
- we try using probes, and this fails
- so we try _Unwind_DebugHook, which succeeds
- next we encounter objfile libgcc
- we try using probes, and this succeeds.
So, we end up with a master exception breakpoint in both libgcc (using probes)
and libgcc.debug (using _Unwind_DebugHook).

This eventually causes:
...
(gdb) PASS: gdb.cp/nextoverthrow.exp: post-check - next over a throw 3
next^M
src/gdb/infrun.c:6384: internal-error: \
  void process_event_stop_test(execution_control_state*): \
  Assertion `ecs->event_thread->control.exception_resume_breakpoint != NULL' \
  failed.^M
A problem internal to GDB has been detected,^M
further debugging may prove unreliable.^M
Quit this debugging session? (y or n) FAIL: gdb.cp/nextoverthrow.exp: next
past catch (GDB internal error)
...

To trigger this internal-error, we need to use gcc-10 or later to compile the
test-case, such that it contains the fix for gcc PR97774 - "Incorrect line
info for try/catch".

Fix this by only trying to install the master exception breakpoint in
libgcc.debug using the _Unwind_DebugHook method, if the install using probes
in libgcc failed.

Tested on x86_64-linux.

gdb/ChangeLog:

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

	PR gdb/26881
	* breakpoint.c (create_exception_master_breakpoint_probe)
	(create_exception_master_breakpoint_hook): Factor out
	of ...
	(create_exception_master_breakpoint): ... here.  Only try to install
	the master exception breakpoint in objfile.debug using the
	_Unwind_DebugHook method, if the install using probes in objfile
	failed.
This commit is contained in:
Tom de Vries 2021-01-08 11:11:16 +01:00
parent e343681375
commit 1940319c0e
2 changed files with 122 additions and 77 deletions

View file

@ -1,3 +1,14 @@
2021-01-08 Tom de Vries <tdevries@suse.de>
PR gdb/26881
* breakpoint.c (create_exception_master_breakpoint_probe)
(create_exception_master_breakpoint_hook): Factor out
of ...
(create_exception_master_breakpoint): ... here. Only try to install
the master exception breakpoint in objfile.debug using the
_Unwind_DebugHook method, if the install using probes in objfile
failed.
2021-01-08 Andrew Burgess <andrew.burgess@embecosm.com>
* f-lang.c (fortran_value_subarray): Call value_from_component.

View file

@ -3477,92 +3477,126 @@ create_std_terminate_master_breakpoint (void)
}
}
/* Install a master breakpoint on the unwinder's debug hook for OBJFILE using a
probe. Return true if a breakpoint was installed. */
static bool
create_exception_master_breakpoint_probe (objfile *objfile)
{
struct breakpoint *b;
struct gdbarch *gdbarch;
struct breakpoint_objfile_data *bp_objfile_data;
bp_objfile_data = get_breakpoint_objfile_data (objfile);
/* We prefer the SystemTap probe point if it exists. */
if (!bp_objfile_data->exception_searched)
{
std::vector<probe *> ret
= find_probes_in_objfile (objfile, "libgcc", "unwind");
if (!ret.empty ())
{
/* We are only interested in checking one element. */
probe *p = ret[0];
if (!p->can_evaluate_arguments ())
{
/* We cannot use the probe interface here, because it does
not know how to evaluate arguments. */
ret.clear ();
}
}
bp_objfile_data->exception_probes = ret;
bp_objfile_data->exception_searched = 1;
}
if (bp_objfile_data->exception_probes.empty ())
return false;
gdbarch = objfile->arch ();
for (probe *p : bp_objfile_data->exception_probes)
{
b = create_internal_breakpoint (gdbarch,
p->get_relocated_address (objfile),
bp_exception_master,
&internal_breakpoint_ops);
b->location = new_probe_location ("-probe-stap libgcc:unwind");
b->enable_state = bp_disabled;
}
return true;
}
/* Install a master breakpoint on the unwinder's debug hook for OBJFILE using
_Unwind_DebugHook. Return true if a breakpoint was installed. */
static bool
create_exception_master_breakpoint_hook (objfile *objfile)
{
const char *const func_name = "_Unwind_DebugHook";
struct breakpoint *b;
struct gdbarch *gdbarch;
struct breakpoint_objfile_data *bp_objfile_data;
CORE_ADDR addr;
struct explicit_location explicit_loc;
bp_objfile_data = get_breakpoint_objfile_data (objfile);
if (msym_not_found_p (bp_objfile_data->exception_msym.minsym))
return false;
gdbarch = objfile->arch ();
if (bp_objfile_data->exception_msym.minsym == NULL)
{
struct bound_minimal_symbol debug_hook;
debug_hook = lookup_minimal_symbol (func_name, NULL, objfile);
if (debug_hook.minsym == NULL)
{
bp_objfile_data->exception_msym.minsym = &msym_not_found;
return false;
}
bp_objfile_data->exception_msym = debug_hook;
}
addr = BMSYMBOL_VALUE_ADDRESS (bp_objfile_data->exception_msym);
addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
current_top_target ());
b = create_internal_breakpoint (gdbarch, addr, bp_exception_master,
&internal_breakpoint_ops);
initialize_explicit_location (&explicit_loc);
explicit_loc.function_name = ASTRDUP (func_name);
b->location = new_explicit_location (&explicit_loc);
b->enable_state = bp_disabled;
return true;
}
/* Install a master breakpoint on the unwinder's debug hook. */
static void
create_exception_master_breakpoint (void)
{
const char *const func_name = "_Unwind_DebugHook";
for (objfile *objfile : current_program_space->objfiles ())
for (objfile *obj : current_program_space->objfiles ())
{
struct breakpoint *b;
struct gdbarch *gdbarch;
struct breakpoint_objfile_data *bp_objfile_data;
CORE_ADDR addr;
struct explicit_location explicit_loc;
bp_objfile_data = get_breakpoint_objfile_data (objfile);
/* We prefer the SystemTap probe point if it exists. */
if (!bp_objfile_data->exception_searched)
{
std::vector<probe *> ret
= find_probes_in_objfile (objfile, "libgcc", "unwind");
if (!ret.empty ())
{
/* We are only interested in checking one element. */
probe *p = ret[0];
if (!p->can_evaluate_arguments ())
{
/* We cannot use the probe interface here, because it does
not know how to evaluate arguments. */
ret.clear ();
}
}
bp_objfile_data->exception_probes = ret;
bp_objfile_data->exception_searched = 1;
}
if (!bp_objfile_data->exception_probes.empty ())
{
gdbarch = objfile->arch ();
for (probe *p : bp_objfile_data->exception_probes)
{
b = create_internal_breakpoint (gdbarch,
p->get_relocated_address (objfile),
bp_exception_master,
&internal_breakpoint_ops);
b->location = new_probe_location ("-probe-stap libgcc:unwind");
b->enable_state = bp_disabled;
}
continue;
}
/* Otherwise, try the hook function. */
if (msym_not_found_p (bp_objfile_data->exception_msym.minsym))
/* Skip separate debug object. */
if (obj->separate_debug_objfile_backlink)
continue;
gdbarch = objfile->arch ();
/* Try a probe kind breakpoint. */
if (create_exception_master_breakpoint_probe (obj))
continue;
if (bp_objfile_data->exception_msym.minsym == NULL)
{
struct bound_minimal_symbol debug_hook;
debug_hook = lookup_minimal_symbol (func_name, NULL, objfile);
if (debug_hook.minsym == NULL)
{
bp_objfile_data->exception_msym.minsym = &msym_not_found;
continue;
}
bp_objfile_data->exception_msym = debug_hook;
}
addr = BMSYMBOL_VALUE_ADDRESS (bp_objfile_data->exception_msym);
addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
current_top_target ());
b = create_internal_breakpoint (gdbarch, addr, bp_exception_master,
&internal_breakpoint_ops);
initialize_explicit_location (&explicit_loc);
explicit_loc.function_name = ASTRDUP (func_name);
b->location = new_explicit_location (&explicit_loc);
b->enable_state = bp_disabled;
/* Iterate over separate debug objects and try an _Unwind_DebugHook
kind breakpoint. */
for (objfile *sepdebug = obj->separate_debug_objfile;
sepdebug != nullptr; sepdebug = sepdebug->separate_debug_objfile)
if (create_exception_master_breakpoint_hook (sepdebug))
break;
}
}