diff options
author | Pedro Alves <pedro@palves.net> | 2020-08-27 21:03:53 +0100 |
---|---|---|
committer | Pedro Alves <pedro@palves.net> | 2020-08-27 21:03:53 +0100 |
commit | df63178325a5705a609bff94a349162bbb839895 (patch) | |
tree | df44a2706a8aa07bc3523f6c2948576905387e87 /gdb/breakpoint.c | |
parent | b2b38aa45ba2eb2e7e4c70689d679c4c467eda73 (diff) | |
download | gdb-df63178325a5705a609bff94a349162bbb839895.zip gdb-df63178325a5705a609bff94a349162bbb839895.tar.gz gdb-df63178325a5705a609bff94a349162bbb839895.tar.bz2 |
Fix advance/until and multiple locations (PR gdb/26524)
If you do "advance LINESPEC", and LINESPEC expands to more than one
location, GDB just errors out:
if (sals.size () != 1)
error (_("Couldn't get information on specified line."));
For example, advancing to a line in an inlined function, inlined three
times:
(gdb) b 21
Breakpoint 1 at 0x55555555516f: advance.cc:21. (3 locations)
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y <MULTIPLE>
1.1 y 0x000055555555516f in inline_func at advance.cc:21
1.2 y 0x000055555555517e in inline_func at advance.cc:21
1.3 y 0x000055555555518d in inline_func at advance.cc:21
(gdb) advance 21
Couldn't get information on specified line.
(gdb)
Similar issue with the "until" command, as it shares the
implementation with "advance".
Since, as the comment in gdb.base/advance.exp says, "advance <location>"
is really just syntactic sugar for "tbreak <location>;continue",
fix this by making GDB insert a breakpoint at all the resolved
locations.
A new testcase is included, which exercises both "advance" and
"until", in two different cases expanding to multiple locations:
- inlined functions
- C++ overloads
This also exercises the inline frames issue fixed by the previous
patch.
gdb/ChangeLog:
PR gdb/26524
* breakpoint.c (until_break_fsm) <location_breakpoint,
caller_breakpoint>: Delete fields.
<breakpoints>: New field.
<until_break_fsm>: Adjust to save a breakpoint vector instead of
two individual breakpoints.
(until_break_fsm::should_stop): Loop over breakpoints in the
breakpoint vector.
(until_break_fsm::clean_up): Adjust to clear the breakpoints
vector.
(until_break_command): Handle location expanding into multiple
sals.
gdb/testsuite/ChangeLog:
PR gdb/26523
PR gdb/26524
* gdb.base/advance-until-multiple-locations.cc: New.
* gdb.base/advance-until-multiple-locations.exp: New.
Diffstat (limited to 'gdb/breakpoint.c')
-rw-r--r-- | gdb/breakpoint.c | 77 |
1 files changed, 36 insertions, 41 deletions
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index ef8e54f..8f75618 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -10939,20 +10939,15 @@ struct until_break_fsm : public thread_fsm /* The thread that was current when the command was executed. */ int thread; - /* The breakpoint set at the destination location. */ - breakpoint_up location_breakpoint; - - /* Breakpoint set at the return address in the caller frame. May be - NULL. */ - breakpoint_up caller_breakpoint; + /* The breakpoint set at the return address in the caller frame, + plus breakpoints at all the destination locations. */ + std::vector<breakpoint_up> breakpoints; until_break_fsm (struct interp *cmd_interp, int thread, - breakpoint_up &&location_breakpoint, - breakpoint_up &&caller_breakpoint) + std::vector<breakpoint_up> &&breakpoints) : thread_fsm (cmd_interp), thread (thread), - location_breakpoint (std::move (location_breakpoint)), - caller_breakpoint (std::move (caller_breakpoint)) + breakpoints (std::move (breakpoints)) { } @@ -10967,12 +10962,13 @@ struct until_break_fsm : public thread_fsm bool until_break_fsm::should_stop (struct thread_info *tp) { - if (bpstat_find_breakpoint (tp->control.stop_bpstat, - location_breakpoint.get ()) != NULL - || (caller_breakpoint != NULL - && bpstat_find_breakpoint (tp->control.stop_bpstat, - caller_breakpoint.get ()) != NULL)) - set_finished (); + for (const breakpoint_up &bp : breakpoints) + if (bpstat_find_breakpoint (tp->control.stop_bpstat, + bp.get ()) != NULL) + { + set_finished (); + break; + } return true; } @@ -10984,8 +10980,7 @@ void until_break_fsm::clean_up (struct thread_info *) { /* Clean up our temporary breakpoints. */ - location_breakpoint.reset (); - caller_breakpoint.reset (); + breakpoints.clear (); delete_longjmp_breakpoint (thread); } @@ -11023,16 +11018,12 @@ until_break_command (const char *arg, int from_tty, int anywhere) : decode_line_1 (location.get (), DECODE_LINE_FUNFIRSTLINE, NULL, NULL, 0)); - if (sals.size () != 1) + if (sals.empty ()) error (_("Couldn't get information on specified line.")); - symtab_and_line &sal = sals[0]; - if (*arg) error (_("Junk at end of arguments.")); - resolve_sal_pc (&sal); - tp = inferior_thread (); thread = tp->global_num; @@ -11049,7 +11040,7 @@ until_break_command (const char *arg, int from_tty, int anywhere) /* Keep within the current frame, or in frames called by the current one. */ - breakpoint_up caller_breakpoint; + std::vector<breakpoint_up> breakpoints; gdb::optional<delete_longjmp_breakpoint_cleanup> lj_deleter; @@ -11061,10 +11052,11 @@ until_break_command (const char *arg, int from_tty, int anywhere) sal2 = find_pc_line (frame_unwind_caller_pc (frame), 0); sal2.pc = frame_unwind_caller_pc (frame); caller_gdbarch = frame_unwind_caller_arch (frame); - caller_breakpoint = set_momentary_breakpoint (caller_gdbarch, - sal2, - caller_frame_id, - bp_until); + + breakpoint_up caller_breakpoint + = set_momentary_breakpoint (caller_gdbarch, sal2, + caller_frame_id, bp_until); + breakpoints.emplace_back (std::move (caller_breakpoint)); set_longjmp_breakpoint (tp, caller_frame_id); lj_deleter.emplace (thread); @@ -11073,21 +11065,24 @@ until_break_command (const char *arg, int from_tty, int anywhere) /* set_momentary_breakpoint could invalidate FRAME. */ frame = NULL; - breakpoint_up location_breakpoint; - if (anywhere) - /* If the user told us to continue until a specified location, - we don't specify a frame at which we need to stop. */ - location_breakpoint = set_momentary_breakpoint (frame_gdbarch, sal, - null_frame_id, bp_until); - else - /* Otherwise, specify the selected frame, because we want to stop - only at the very same frame. */ - location_breakpoint = set_momentary_breakpoint (frame_gdbarch, sal, - stack_frame_id, bp_until); + /* If the user told us to continue until a specified location, we + don't specify a frame at which we need to stop. Otherwise, + specify the selected frame, because we want to stop only at the + very same frame. */ + frame_id stop_frame_id = anywhere ? null_frame_id : stack_frame_id; + + for (symtab_and_line &sal : sals) + { + resolve_sal_pc (&sal); + + breakpoint_up location_breakpoint + = set_momentary_breakpoint (frame_gdbarch, sal, + stop_frame_id, bp_until); + breakpoints.emplace_back (std::move (location_breakpoint)); + } tp->thread_fsm = new until_break_fsm (command_interp (), tp->global_num, - std::move (location_breakpoint), - std::move (caller_breakpoint)); + std::move (breakpoints)); if (lj_deleter) lj_deleter->release (); |