[PATCH] stepping thru breakpoint traps.

Michael Snyder msnyder@cygnus.com
Thu Jun 28 12:10:00 GMT 2001


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


More information about the Gdb-patches mailing list