diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c352fd2966..ac1cbee0e3 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,29 @@ +2013-05-23 Yao Qi + Pedro Alves + + * gdbthread.h (struct thread_control_state) : New + field. + * infcmd.c (step_once, until_next_command): Enable range stepping. + * infrun.c (displaced_step_prepare): Disable range stepping. + (resume): Disable range stepping if stepping over a breakpoint or + we have software watchpoints. If range stepping is enabled, + assert the thread is in the stepping range. + (clear_proceed_status_thread): Clear may_range_step. + (handle_inferior_event): Disable range stepping as soon as we know + the thread that hit the event. Re-enable it whenever we're going + to step with a step range. + * remote.c (struct vCont_action_support) : New field. + (use_range_stepping): New global. + (remote_vcont_probe): Handle 'r' action. + (append_resumption): Append an 'r' action if the thread may range + step. + (show_range_stepping): New function. + (set_range_stepping): New function. + (_initialize_remote): Call add_setshow_boolean_cmd to register the + 'set range-stepping' and 'show range-stepping' commands. + * NEWS: Mention range stepping, the new vCont;r action, and the + new "set/show range-stepping" commands. + 2013-05-23 Yao Qi Pedro Alves diff --git a/gdb/NEWS b/gdb/NEWS index c6a5e5dcb9..1a4140d439 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -41,6 +41,10 @@ set debug nios2 show debug nios2 Control display of debugging messages related to Nios II targets. +set range-stepping +show range-stepping + Control whether target-assisted range stepping is enabled. + * You can now use a literal value 'unlimited' for options that interpret 0 or -1 as meaning "unlimited". E.g., "set trace-buffer-size unlimited" is now an alias for "set @@ -78,6 +82,19 @@ show debug nios2 ** ElinOS ** Wind River Linux +* GDB now supports target-assigned range stepping with remote targets. + This improves the performance of stepping source lines by reducing + the number of control packets from/to GDB. See "New remote packets" + below. + +* New remote packets + +vCont;r + + The vCont packet supports a new 'r' action, that tells the remote + stub to step through an address range itself, without GDB + involvemement at each single-step. + *** Changes in GDB 7.6 * Target record has been renamed to record-full. diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index ddc766adc1..7330f295c6 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,11 @@ +2013-05-23 Yao Qi + Pedro Alves + + * gdb.texinfo (Packets): Document 'vCont;r'. + (Continuing and Stepping): Document target-assisted range + stepping, and the 'set range-stepping' and 'show range-stepping' + commands. + 2013-05-23 Joel Brobecker * gdb.texinfo (Installed System-wide Configuration Scripts): diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index b68d2f8b4e..721e96a1bf 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -5219,6 +5219,38 @@ Execute one machine instruction, but if it is a function call, proceed until the function returns. An argument is a repeat count, as in @code{next}. + +@end table + +@anchor{range stepping} +@cindex range stepping +@cindex target-assisted range stepping +By default, and if available, @value{GDBN} makes use of +target-assisted @dfn{range stepping}. In other words, whenever you +use a stepping command (e.g., @code{step}, @code{next}), @value{GDBN} +tells the target to step the corresponding range of instruction +addresses instead of issuing multiple single-steps. This speeds up +line stepping, particularly for remote targets. Ideally, there should +be no reason you would want to turn range stepping off. However, it's +possible that a bug in the debug info, a bug in the remote stub (for +remote targets), or even a bug in @value{GDBN} could make line +stepping behave incorrectly when target-assisted range stepping is +enabled. You can use the following command to turn off range stepping +if necessary: + +@table @code +@kindex set range-stepping +@kindex show range-stepping +@item set range-stepping +@itemx show range-stepping +Control whether range stepping is enabled. + +If @code{on}, and the target supports it, @value{GDBN} tells the +target to step a range of addresses itself, instead of issuing +multiple single-steps. If @code{off}, @value{GDBN} always issues +single-steps, even if range stepping is supported by the target. The +default is @code{on}. + @end table @node Skipping Over Functions and Files @@ -37511,6 +37543,22 @@ Step. Step with signal @var{sig}. The signal @var{sig} should be two hex digits. @item t Stop. +@item r @var{start},@var{end} +Step once, and then keep stepping as long as the thread stops at +addresses between @var{start} (inclusive) and @var{end} (exclusive). +The remote stub reports a stop reply when either the thread goes out +of the range or is stopped due to an unrelated reason, such as hitting +a breakpoint. @xref{range stepping}. + +If the range is empty (@var{start} == @var{end}), then the action +becomes equivalent to the @samp{s} action. In other words, +single-step once, and report the stop (even if the stepped instruction +jumps to @var{start}). + +(A stop reply may be sent at any point even if the PC is still within +the stepping range; for example, it is valid to implement this packet +in a degenerate way as a single instruction step operation.) + @end table The optional argument @var{addr} normally associated with the diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h index a9f8a941df..c3b85dc705 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -65,6 +65,14 @@ struct thread_control_state CORE_ADDR step_range_start; /* Inclusive */ CORE_ADDR step_range_end; /* Exclusive */ + /* If GDB issues a target step request, and this is nonzero, the + target should single-step this thread once, and then continue + single-stepping it without GDB core involvement as long as the + thread stops in the step range above. If this is zero, the + target should ignore the step range, and only issue one single + step. */ + int may_range_step; + /* Stack frame address as of when stepping command was issued. This is how we know when we step into a subroutine call, and how to set the frame for the breakpoint used to step out. */ diff --git a/gdb/infcmd.c b/gdb/infcmd.c index aeb24ff3fc..30621e4ba5 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -1046,9 +1046,14 @@ step_once (int skip_subroutines, int single_inst, int count, int thread) &tp->control.step_range_start, &tp->control.step_range_end); + tp->control.may_range_step = 1; + /* If we have no line info, switch to stepi mode. */ if (tp->control.step_range_end == 0 && step_stop_if_no_debug) - tp->control.step_range_start = tp->control.step_range_end = 1; + { + tp->control.step_range_start = tp->control.step_range_end = 1; + tp->control.may_range_step = 0; + } else if (tp->control.step_range_end == 0) { const char *name; @@ -1337,6 +1342,7 @@ until_next_command (int from_tty) tp->control.step_range_start = BLOCK_START (SYMBOL_BLOCK_VALUE (func)); tp->control.step_range_end = sal.end; } + tp->control.may_range_step = 1; tp->control.step_over_calls = STEP_OVER_ALL; diff --git a/gdb/infrun.c b/gdb/infrun.c index 57c427da6d..376a440d46 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1311,6 +1311,7 @@ static int displaced_step_prepare (ptid_t ptid) { struct cleanup *old_cleanups, *ignore_cleanups; + struct thread_info *tp = find_thread_ptid (ptid); struct regcache *regcache = get_thread_regcache (ptid); struct gdbarch *gdbarch = get_regcache_arch (regcache); CORE_ADDR original, copy; @@ -1323,6 +1324,12 @@ displaced_step_prepare (ptid_t ptid) support displaced stepping. */ gdb_assert (gdbarch_displaced_step_copy_insn_p (gdbarch)); + /* Disable range stepping while executing in the scratch pad. We + want a single-step even if executing the displaced instruction in + the scratch buffer lands within the stepping range (e.g., a + jump/branch). */ + tp->control.may_range_step = 0; + /* We have to displaced step one thread at a time, as we only have access to a single scratch space per inferior. */ @@ -1778,6 +1785,11 @@ how to step past a permanent breakpoint on this architecture. Try using\n\ a command like `return' or `jump' to continue execution.")); } + /* If we have a breakpoint to step over, make sure to do a single + step only. Same if we have software watchpoints. */ + if (tp->control.trap_expected || bpstat_should_step ()) + tp->control.may_range_step = 0; + /* If enabled, step over breakpoints by executing a copy of the instruction at a different address. @@ -1939,6 +1951,16 @@ a command like `return' or `jump' to continue execution.")); displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf)); } + if (tp->control.may_range_step) + { + /* If we're resuming a thread with the PC out of the step + range, then we're doing some nested/finer run control + operation, like stepping the thread out of the dynamic + linker or the displaced stepping scratch pad. We + shouldn't have allowed a range step then. */ + gdb_assert (pc_in_thread_step_range (pc, tp)); + } + /* Install inferior's terminal modes. */ target_terminal_inferior (); @@ -1980,6 +2002,7 @@ clear_proceed_status_thread (struct thread_info *tp) tp->control.trap_expected = 0; tp->control.step_range_start = 0; tp->control.step_range_end = 0; + tp->control.may_range_step = 0; tp->control.step_frame_id = null_frame_id; tp->control.step_stack_frame_id = null_frame_id; tp->control.step_over_calls = STEP_OVER_UNDEBUGGABLE; @@ -3223,6 +3246,10 @@ handle_inferior_event (struct execution_control_state *ecs) /* If it's a new thread, add it to the thread database. */ if (ecs->event_thread == NULL) ecs->event_thread = add_thread (ecs->ptid); + + /* Disable range stepping. If the next step request could use a + range, this will be end up re-enabled then. */ + ecs->event_thread->control.may_range_step = 0; } /* Dependent on valid ECS->EVENT_THREAD. */ @@ -4717,6 +4744,11 @@ process_event_stop_test: paddress (gdbarch, ecs->event_thread->control.step_range_start), paddress (gdbarch, ecs->event_thread->control.step_range_end)); + /* Tentatively re-enable range stepping; `resume' disables it if + necessary (e.g., if we're stepping over a breakpoint or we + have software watchpoints). */ + ecs->event_thread->control.may_range_step = 1; + /* When stepping backward, stop at beginning of line range (unless it's the function entry point, in which case keep going back to the call point). */ @@ -5233,6 +5265,7 @@ process_event_stop_test: ecs->event_thread->control.step_range_start = stop_pc_sal.pc; ecs->event_thread->control.step_range_end = stop_pc_sal.end; + ecs->event_thread->control.may_range_step = 1; set_step_info (frame, stop_pc_sal); if (debug_infrun) diff --git a/gdb/remote.c b/gdb/remote.c index eb58b9454e..658fae2207 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -260,8 +260,15 @@ struct vCont_action_support { /* vCont;t */ int t; + + /* vCont;r */ + int r; }; +/* Controls whether GDB is willing to use range stepping. */ + +static int use_range_stepping = 1; + /* Description of the remote protocol state for the currently connected target. This is per-target state, and independent of the selected architecture. */ @@ -4653,6 +4660,7 @@ remote_vcont_probe (struct remote_state *rs) support_c = 0; support_C = 0; rs->supports_vCont.t = 0; + rs->supports_vCont.r = 0; while (p && *p == ';') { p++; @@ -4666,6 +4674,8 @@ remote_vcont_probe (struct remote_state *rs) support_C = 1; else if (*p == 't' && (*(p + 1) == ';' || *(p + 1) == 0)) rs->supports_vCont.t = 1; + else if (*p == 'r' && (*(p + 1) == ';' || *(p + 1) == 0)) + rs->supports_vCont.r = 1; p = strchr (p, ';'); } @@ -4697,6 +4707,42 @@ append_resumption (char *p, char *endp, if (step && siggnal != GDB_SIGNAL_0) p += xsnprintf (p, endp - p, ";S%02x", siggnal); + else if (step + /* GDB is willing to range step. */ + && use_range_stepping + /* Target supports range stepping. */ + && rs->supports_vCont.r + /* We don't currently support range stepping multiple + threads with a wildcard (though the protocol allows it, + so stubs shouldn't make an active effort to forbid + it). */ + && !(remote_multi_process_p (rs) && ptid_is_pid (ptid))) + { + struct thread_info *tp; + + if (ptid_equal (ptid, minus_one_ptid)) + { + /* If we don't know about the target thread's tid, then + we're resuming magic_null_ptid (see caller). */ + tp = find_thread_ptid (magic_null_ptid); + } + else + tp = find_thread_ptid (ptid); + gdb_assert (tp != NULL); + + if (tp->control.may_range_step) + { + int addr_size = gdbarch_addr_bit (target_gdbarch ()) / 8; + + p += xsnprintf (p, endp - p, ";r%s,%s", + phex_nz (tp->control.step_range_start, + addr_size), + phex_nz (tp->control.step_range_end, + addr_size)); + } + else + p += xsnprintf (p, endp - p, ";s"); + } else if (step) p += xsnprintf (p, endp - p, ";s"); else if (siggnal != GDB_SIGNAL_0) @@ -11659,6 +11705,44 @@ remote_upload_trace_state_variables (struct uploaded_tsv **utsvp) return 0; } +/* The "set/show range-stepping" show hook. */ + +static void +show_range_stepping (struct ui_file *file, int from_tty, + struct cmd_list_element *c, + const char *value) +{ + fprintf_filtered (file, + _("Debugger's willingness to use range stepping " + "is %s.\n"), value); +} + +/* The "set/show range-stepping" set hook. */ + +static void +set_range_stepping (char *ignore_args, int from_tty, + struct cmd_list_element *c) +{ + /* Whene enabling, check whether range stepping is actually + supported by the target, and warn if not. */ + if (use_range_stepping) + { + if (remote_desc != NULL) + { + struct remote_state *rs = get_remote_state (); + + if (remote_protocol_packets[PACKET_vCont].support == PACKET_SUPPORT_UNKNOWN) + remote_vcont_probe (rs); + + if (remote_protocol_packets[PACKET_vCont].support == PACKET_ENABLE + && rs->supports_vCont.r) + return; + } + + warning (_("Range stepping is not supported by the current target")); + } +} + void _initialize_remote (void) { @@ -12056,6 +12140,20 @@ Set the remote pathname for \"run\""), _("\ Show the remote pathname for \"run\""), NULL, NULL, NULL, &remote_set_cmdlist, &remote_show_cmdlist); + add_setshow_boolean_cmd ("range-stepping", class_run, + &use_range_stepping, _("\ +Enable or disable range stepping."), _("\ +Show whether target-assisted range stepping is enabled."), _("\ +If on, and the target supports it, when stepping a source line, GDB\n\ +tells the target to step the corresponding range of addresses itself instead\n\ +of issuing multiple single-steps. This speeds up source level\n\ +stepping. If off, GDB always issues single-steps, even if range\n\ +stepping is supported by the target. The default is on."), + set_range_stepping, + show_range_stepping, + &setlist, + &showlist); + /* Eventually initialize fileio. See fileio.c */ initialize_remote_fileio (remote_set_cmdlist, remote_show_cmdlist);