diff options
author | Pedro Alves <palves@redhat.com> | 2013-05-23 17:15:35 +0000 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2013-05-23 17:15:35 +0000 |
commit | c1e36e3e919994da4fa0da232b173939f3e44bb8 (patch) | |
tree | 0e355e32e09ba6192768b6ebdd20994848acbdfe /gdb/infrun.c | |
parent | d458bd84a8d3576fa7c2b4e3132ebe96e104e918 (diff) | |
download | gdb-c1e36e3e919994da4fa0da232b173939f3e44bb8.zip gdb-c1e36e3e919994da4fa0da232b173939f3e44bb8.tar.gz gdb-c1e36e3e919994da4fa0da232b173939f3e44bb8.tar.bz2 |
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.
Diffstat (limited to 'gdb/infrun.c')
-rw-r--r-- | gdb/infrun.c | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c index 57c427d..376a440 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) |