range stepping: gdb

This patch teaches GDB to take advantage of target-assisted range
stepping.  It adds a new 'r ADDR1,ADDR2' action to vCont (vCont;r),
meaning, "step once, and keep stepping as long as the thread is in the
[ADDR1,ADDR2) range".

Rationale:

When user issues the "step" command on the following line of source,

   a = b + c + d * e - a;

GDB single-steps every single instruction until the program reaches a
new different line.  E.g., on x86_64, that line compiles to:

   0x08048434 <+65>:    mov    0x1c(%esp),%eax
   0x08048438 <+69>:    mov    0x30(%esp),%edx
   0x0804843c <+73>:    add    %eax,%edx
   0x0804843e <+75>:    mov    0x18(%esp),%eax
   0x08048442 <+79>:    imul   0x2c(%esp),%eax
   0x08048447 <+84>:    add    %edx,%eax
   0x08048449 <+86>:    sub    0x34(%esp),%eax
   0x0804844d <+90>:    mov    %eax,0x34(%esp)
   0x08048451 <+94>:    mov    0x1c(%esp),%eax

and the following is the RSP traffic between GDB and GDBserver:

 --> vCont;s:p2e13.2e13;c
 <-- T0505:68efffbf;04:30efffbf;08:3c840408;thread:p2e13.2e13;core:1;
 --> vCont;s:p2e13.2e13;c
 <-- T0505:68efffbf;04:30efffbf;08:3e840408;thread:p2e13.2e13;core:2;
 --> vCont;s:p2e13.2e13;c
 <-- T0505:68efffbf;04:30efffbf;08:42840408;thread:p2e13.2e13;core:2;
 --> vCont;s:p2e13.2e13;c
 <-- T0505:68efffbf;04:30efffbf;08:47840408;thread:p2e13.2e13;core:0;
 --> vCont;s:p2e13.2e13;c
 <-- T0505:68efffbf;04:30efffbf;08:49840408;thread:p2e13.2e13;core:0;
 --> vCont;s:p2e13.2e13;c
 <-- T0505:68efffbf;04:30efffbf;08:4d840408;thread:p2e13.2e13;core:0;
 --> vCont;s:p2e13.2e13;c
 <-- T0505:68efffbf;04:30efffbf;08:51840408;thread:p2e13.2e13;core:0;

IOW, a lot of roundtrips between GDB and GDBserver.

If we add a new command to the RSP, meaning "keep stepping and don't
report a stop until the program goes out of the [0x08048434,
0x08048451) address range", then the RSP traffic can be reduced down
to:

 --> vCont;r8048434,8048451:p2db0.2db0;c
 <-- T0505:68efffbf;04:30efffbf;08:51840408;thread:p2db0.2db0;core:1;

As number of packets is reduced dramatically, the performance of
stepping source lines is much improved.

In case something is wrong with range stepping on the stub side, the
debug info or even gdb, this adds a "set/show range-stepping" command
to be able to turn range stepping off.

gdb/
2013-05-23  Yao Qi  <yao@codesourcery.com>
	    Pedro Alves  <palves@redhat.com>

	* gdbthread.h (struct thread_control_state) <may_range_step>: 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) <r>: 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.

gdb/doc/
2013-05-23  Yao Qi  <yao@codesourcery.com>
	    Pedro Alves  <palves@redhat.com>

	* gdb.texinfo (Packets): Document 'vCont;r'.
	(Continuing and Stepping): Document target-assisted range
	stepping, and the 'set range-stepping' and 'show range-stepping'
	commands.
This commit is contained in:
Pedro Alves
2013-05-23 17:15:35 +00:00
parent d458bd84a8
commit c1e36e3e91
8 changed files with 245 additions and 1 deletions

View File

@@ -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);