From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22543 invoked by alias); 2 Apr 2002 23:43:33 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 22536 invoked from network); 2 Apr 2002 23:43:30 -0000 Received: from unknown (HELO nevyn.them.org) (128.2.145.6) by sources.redhat.com with SMTP; 2 Apr 2002 23:43:30 -0000 Received: from drow by nevyn.them.org with local (Exim 3.35 #1 (Debian)) id 16sXw5-0003mc-00 for ; Tue, 02 Apr 2002 18:43:33 -0500 Date: Tue, 02 Apr 2002 15:43:00 -0000 From: Daniel Jacobowitz To: gdb-patches@sources.redhat.com Subject: [RFA] Fix watchpoints when stepping over a breakpoint Message-ID: <20020402184333.A8464@nevyn.them.org> Mail-Followup-To: gdb-patches@sources.redhat.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.3.23i X-SW-Source: 2002-04/txt/msg00043.txt.bz2 For some of the history of this problem, see PR gdb/81 and: http://sourceware.cygnus.com/ml/gdb-patches/2000-q1/msg00665.html How Peter's or Jim's patches worked for them, I'm not entirely sure; I suspect there's been a change to shared library debugging since then, and/or a severe deficiency in the testsuite somewhere. When I tried it I got stuck on the bp_shlib_event breakpoint. We would hit it, remove, single-step (trap expected), check where we were... and find ourselves at the shared library breakpoint again because of DECR_PC_AFTER_BREAK! Instead, I now collect only non-breakpoint events. This appears to work fine. It causes no changes in the testsuite; a trivial followup patch to update the formatting in annota2.exp fixes the test in question. Is this OK to commit? Anyone see a problem with my method? -- Daniel Jacobowitz Carnegie Mellon University MontaVista Software Debian GNU/Linux Developer 2002-04-02 Daniel Jacobowitz Fix PR gdb/81 * breakpoint.c (bpstat_stop_status): Add ignore_breakpoints argument. If ignore_breakpoints is nonzero, skip all breakpoint-like events. * breakpoint.h (bpstat_stop_status): Update prototype. * infrun.c (handle_inferior_event): Update calls to bpstat_stop_status. Call bpstat_stop_status even if trap_expected. Index: infrun.c =================================================================== RCS file: /cvs/src/src/gdb/infrun.c,v retrieving revision 1.56 diff -u -p -r1.56 infrun.c --- infrun.c 2002/03/18 02:26:31 1.56 +++ infrun.c 2002/04/02 23:17:48 @@ -1417,6 +1417,7 @@ handle_inferior_event (struct execution_ { CORE_ADDR tmp; int stepped_after_stopped_by_watchpoint; + int ignore_breakpoints; /* Cache the last pid/waitstatus. */ target_last_wait_ptid = ecs->ptid; @@ -1606,7 +1607,8 @@ handle_inferior_event (struct execution_ stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs) && prev_pc != - stop_pc - DECR_PC_AFTER_BREAK); + stop_pc - DECR_PC_AFTER_BREAK, + 0); ecs->random_signal = !bpstat_explains_signal (stop_bpstat); inferior_ptid = ecs->saved_inferior_ptid; goto process_event_stop_test; @@ -1665,7 +1667,8 @@ handle_inferior_event (struct execution_ stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs) && prev_pc != - stop_pc - DECR_PC_AFTER_BREAK); + stop_pc - DECR_PC_AFTER_BREAK, + 0); ecs->random_signal = !bpstat_explains_signal (stop_bpstat); goto process_event_stop_test; @@ -1740,7 +1743,8 @@ handle_inferior_event (struct execution_ stop_bpstat = bpstat_stop_status (&stop_pc, currently_stepping (ecs) && prev_pc != - stop_pc - DECR_PC_AFTER_BREAK); + stop_pc - DECR_PC_AFTER_BREAK, + 0); ecs->random_signal = !bpstat_explains_signal (stop_bpstat); inferior_ptid = ecs->saved_inferior_ptid; goto process_event_stop_test; @@ -2097,44 +2101,45 @@ handle_inferior_event (struct execution_ return; } - /* Don't even think about breakpoints - if just proceeded over a breakpoint. + /* See if there is a breakpoint at the current PC. + Older versions of GDB did not call bpstat_stop_status after + proceeding over a breakpoint, causing missed watchpoints when + proceeding over a breakpoint on an instruction which triggers + a watchpoint. */ - However, if we are trying to proceed over a breakpoint - and end up in sigtramp, then through_sigtramp_breakpoint - will be set and we should check whether we've hit the - step breakpoint. */ if (stop_signal == TARGET_SIGNAL_TRAP && trap_expected && through_sigtramp_breakpoint == NULL) - bpstat_clear (&stop_bpstat); + { + ignore_breakpoints = 1; + } 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 - than hitting a breakpoint. We do this by checking that - 1) stepping is going on and 2) we didn't hit a breakpoint - in a signal handler without an intervening stop in - 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)))) - ); - /* Following in case break condition called a - function. */ + ignore_breakpoints = 0; + /* Following in case break condition called a function. */ stop_print_frame = 1; } + + /* 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 + than hitting a breakpoint. We do this by checking that + 1) stepping is going on and 2) we didn't hit a breakpoint + in a signal handler without an intervening stop in + sigtramp, which is detected by a new stack pointer value + below any usual function calling stack adjustments. */ + (ignore_breakpoints + || (currently_stepping (ecs) + && prev_pc != stop_pc - DECR_PC_AFTER_BREAK + && !(step_range_end + && INNER_THAN (read_sp (), (step_sp - 16))))), + ignore_breakpoints); if (stop_signal == TARGET_SIGNAL_TRAP) ecs->random_signal Index: breakpoint.c =================================================================== RCS file: /cvs/src/src/gdb/breakpoint.c,v retrieving revision 1.68 diff -u -p -r1.68 breakpoint.c --- breakpoint.c 2002/03/28 01:35:55 1.68 +++ breakpoint.c 2002/04/02 23:17:49 @@ -2345,11 +2345,14 @@ which its expression is valid.\n"); watchpoint at which we have stopped. (We may have stopped for several reasons concurrently.) + If IGNORE_BREAKPOINTS, we return only non-breakpoint results + (e.g. any watchpoints we may have hit). + Each element of the chain has valid next, breakpoint_at, commands, FIXME??? fields. */ bpstat -bpstat_stop_status (CORE_ADDR *pc, int not_a_breakpoint) +bpstat_stop_status (CORE_ADDR *pc, int not_a_breakpoint, int ignore_breakpoints) { register struct breakpoint *b, *temp; CORE_ADDR bp_addr; @@ -2390,6 +2393,8 @@ bpstat_stop_status (CORE_ADDR *pc, int n && b->type != bp_catch_catch && b->type != bp_catch_throw) /* a non-watchpoint bp */ { + if (ignore_breakpoints) + continue; if (b->address != bp_addr) /* address doesn't match */ continue; if (overlay_debugging /* unmapped overlay section */ Index: breakpoint.h =================================================================== RCS file: /cvs/src/src/gdb/breakpoint.h,v retrieving revision 1.11 diff -u -p -r1.11 breakpoint.h --- breakpoint.h 2002/02/06 18:31:07 1.11 +++ breakpoint.h 2002/04/02 23:17:49 @@ -322,7 +322,7 @@ extern void bpstat_clear (bpstat *); is part of the bpstat is copied as well. */ extern bpstat bpstat_copy (bpstat); -extern bpstat bpstat_stop_status (CORE_ADDR *, int); +extern bpstat bpstat_stop_status (CORE_ADDR *, int, int); /* This bpstat_what stuff tells wait_for_inferior what to do with a breakpoint (a challenging task). */