This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[PATCH] stepping thru breakpoint traps.
- To: gdb-patches at sources dot redhat dot com
- Subject: [PATCH] stepping thru breakpoint traps.
- From: Michael Snyder <msnyder at cygnus dot com>
- Date: Thu, 28 Jun 2001 12:10:33 -0700
- Organization: Red Hat
This fixes a problem on DECR_PC_AFTER_BREAK targets, wherein if we
singlestep a trap instruction, GDB mis-computes the breakpoint address
and fails to recognize the breakpoint. I've also added some comments
trying to clarify what's going on, and added a minor optimization to
only update the PC after a breakpoint if DECR_PC_AFTER_BREAK is
non-zero. (and one little FIXME complaint).
2001-06-28 Michael Snyder <msnyder@redhat.com>
* infrun.c (handle_inferior_event): Replace prev_pc test in all
calls to bpstat_stop_status (removed in 1999-09-24). This test
helps distinguish stepping over a breakpoint trap from stepping
thru a jump to the instruction after a breakpoint trap.
(handle_inferior_event): Don't bother writing the PC if
DECR_PC_AFTER_BREAK is zero (optimization).
* breakpoint.c (bpstat_stop_status): Add comment explaining the
purpose and usage of the "not_a_breakpoint" argument in computing
the breakpoint address.
Index: infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.39
diff -c -3 -p -r1.39 infrun.c
*** infrun.c 2001/06/26 00:26:42 1.39
--- infrun.c 2001/06/28 18:59:40
*************** handle_inferior_event (struct execution_
*** 1617,1623 ****
stop_pc = read_pc_pid (ecs->ptid);
ecs->saved_inferior_ptid = inferior_ptid;
inferior_ptid = ecs->ptid;
! stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs));
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
inferior_ptid = ecs->saved_inferior_ptid;
goto process_event_stop_test;
--- 1617,1633 ----
stop_pc = read_pc_pid (ecs->ptid);
ecs->saved_inferior_ptid = inferior_ptid;
inferior_ptid = ecs->ptid;
! /* The second argument of bpstat_stop_status is meant to help
! distinguish between a breakpoint trap and a singlestep trap.
! This is only important on targets where DECR_PC_AFTER_BREAK
! is non-zero. The prev_pc test is meant to distinguish between
! singlestepping a trap instruction, and singlestepping thru a
! jump to the instruction following a trap instruction. */
!
! stop_bpstat = bpstat_stop_status (&stop_pc,
! currently_stepping (ecs) &&
! prev_pc !=
! stop_pc - DECR_PC_AFTER_BREAK);
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
inferior_ptid = ecs->saved_inferior_ptid;
goto process_event_stop_test;
*************** handle_inferior_event (struct execution_
*** 1666,1672 ****
}
stop_pc = read_pc ();
! stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs));
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
goto process_event_stop_test;
--- 1676,1692 ----
}
stop_pc = read_pc ();
! /* The second argument of bpstat_stop_status is meant to help
! distinguish between a breakpoint trap and a singlestep trap.
! This is only important on targets where DECR_PC_AFTER_BREAK
! is non-zero. The prev_pc test is meant to distinguish between
! singlestepping a trap instruction, and singlestepping thru a
! jump to the instruction following a trap instruction. */
!
! stop_bpstat = bpstat_stop_status (&stop_pc,
! currently_stepping (ecs) &&
! prev_pc !=
! stop_pc - DECR_PC_AFTER_BREAK);
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
goto process_event_stop_test;
*************** handle_inferior_event (struct execution_
*** 1731,1737 ****
stop_pc = read_pc_pid (ecs->ptid);
ecs->saved_inferior_ptid = inferior_ptid;
inferior_ptid = ecs->ptid;
! stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs));
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
inferior_ptid = ecs->saved_inferior_ptid;
goto process_event_stop_test;
--- 1751,1767 ----
stop_pc = read_pc_pid (ecs->ptid);
ecs->saved_inferior_ptid = inferior_ptid;
inferior_ptid = ecs->ptid;
! /* The second argument of bpstat_stop_status is meant to help
! distinguish between a breakpoint trap and a singlestep trap.
! This is only important on targets where DECR_PC_AFTER_BREAK
! is non-zero. The prev_pc test is meant to distinguish between
! singlestepping a trap instruction, and singlestepping thru a
! jump to the instruction following a trap instruction. */
!
! stop_bpstat = bpstat_stop_status (&stop_pc,
! currently_stepping (ecs) &&
! prev_pc !=
! stop_pc - DECR_PC_AFTER_BREAK);
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
inferior_ptid = ecs->saved_inferior_ptid;
goto process_event_stop_test;
*************** handle_inferior_event (struct execution_
*** 1840,1846 ****
/* Saw a breakpoint, but it was hit by the wrong thread.
Just continue. */
! write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK, ecs->ptid);
remove_status = remove_breakpoints ();
/* Did we fail to remove breakpoints? If so, try
--- 1870,1877 ----
/* Saw a breakpoint, but it was hit by the wrong thread.
Just continue. */
! if (DECR_PC_AFTER_BREAK)
! write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK, ecs->ptid);
remove_status = remove_breakpoints ();
/* Did we fail to remove breakpoints? If so, try
*************** handle_inferior_event (struct execution_
*** 1852,1858 ****
then either :-) or execs. */
if (remove_status != 0)
{
! write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK + 4, ecs->ptid);
/* We need to restart all the threads now,
* unles we're running in scheduler-locked mode.
* Use currently_stepping to determine whether to
--- 1883,1891 ----
then either :-) or execs. */
if (remove_status != 0)
{
! /* FIXME! This is obviously non-portable! */
! write_pc_pid (stop_pc - DECR_PC_AFTER_BREAK + 4,
! ecs->ptid);
/* We need to restart all the threads now,
* unles we're running in scheduler-locked mode.
* Use currently_stepping to determine whether to
*************** handle_inferior_event (struct execution_
*** 2016,2022 ****
includes evaluating watchpoints, things will come to a
stop in the correct manner. */
! write_pc (stop_pc - DECR_PC_AFTER_BREAK);
remove_breakpoints ();
registers_changed ();
--- 2049,2056 ----
includes evaluating watchpoints, things will come to a
stop in the correct manner. */
! if (DECR_PC_AFTER_BREAK)
! write_pc (stop_pc - DECR_PC_AFTER_BREAK);
remove_breakpoints ();
registers_changed ();
*************** handle_inferior_event (struct execution_
*** 2097,2102 ****
--- 2131,2144 ----
else
{
/* See if there is a breakpoint at the current PC. */
+
+ /* The second argument of bpstat_stop_status is meant to help
+ distinguish between a breakpoint trap and a singlestep trap.
+ This is only important on targets where DECR_PC_AFTER_BREAK
+ is non-zero. The prev_pc test is meant to distinguish between
+ singlestepping a trap instruction, and singlestepping thru a
+ jump to the instruction following a trap instruction. */
+
stop_bpstat = bpstat_stop_status
(&stop_pc,
/* Pass TRUE if our reason for stopping is something other
*************** handle_inferior_event (struct execution_
*** 2106,2111 ****
--- 2148,2154 ----
sigtramp, which is detected by a new stack pointer value
below any usual function calling stack adjustments. */
(currently_stepping (ecs)
+ && prev_pc != stop_pc - DECR_PC_AFTER_BREAK
&& !(step_range_end
&& INNER_THAN (read_sp (), (step_sp - 16))))
);
Index: breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.44
diff -c -3 -p -r1.44 breakpoint.c
*** breakpoint.c 2001/06/19 16:19:15 1.44
--- breakpoint.c 2001/06/28 19:04:53
*************** bpstat_stop_status (CORE_ADDR *pc, int n
*** 2409,2415 ****
"Error evaluating expression for watchpoint %d\n";
char message[sizeof (message1) + 30 /* slop */ ];
! /* Get the address where the breakpoint would have been. */
bp_addr = *pc - (not_a_breakpoint && !SOFTWARE_SINGLE_STEP_P () ?
0 : DECR_PC_AFTER_BREAK);
--- 2409,2420 ----
"Error evaluating expression for watchpoint %d\n";
char message[sizeof (message1) + 30 /* slop */ ];
! /* Get the address where the breakpoint would have been.
! The "not_a_breakpoint" argument is meant to distinguish
! between a breakpoint trap event and a trace/singlestep
! trap event. For a trace/singlestep trap event, we would
! not want to subtract DECR_PC_AFTER_BREAK from the PC. */
!
bp_addr = *pc - (not_a_breakpoint && !SOFTWARE_SINGLE_STEP_P () ?
0 : DECR_PC_AFTER_BREAK);