diff options
author | Daniel Jacobowitz <drow@false.org> | 2007-10-01 00:17:58 +0000 |
---|---|---|
committer | Daniel Jacobowitz <drow@false.org> | 2007-10-01 00:17:58 +0000 |
commit | d983da9c3dfa91e6840fee2a7479d98ee4759f13 (patch) | |
tree | 9a1c14b44f1a2de2d2c087b00d987deb2fe8274d /gdb/infrun.c | |
parent | d830e0e0c9d4b1827385c473cb545e07a72c9b81 (diff) | |
download | gdb-d983da9c3dfa91e6840fee2a7479d98ee4759f13.zip gdb-d983da9c3dfa91e6840fee2a7479d98ee4759f13.tar.gz gdb-d983da9c3dfa91e6840fee2a7479d98ee4759f13.tar.bz2 |
2007-09-16 Daniel Jacobowitz <dan@codesourcery.com>
Jeff Johnston <jjohnstn@redhat.com>
* breakpoint.c (watchpoints_triggered): New.
(bpstat_stop_status): Remove STOPPED_BY_WATCHPOINT argument.
Check watchpoint_triggered instead. Combine handling for software
and hardware watchpoints. Do not use target_stopped_data_address
here. Always check a watchpoint if its scope breakpoint triggers.
Do not stop for thread or overlay events. Improve check for
triggered watchpoints without a value change.
(watch_command_1): Insert the scope breakpoint first. Link the
scope breakpoint to the watchpoint.
* breakpoint.h (enum watchpoint_triggered): New.
(struct breakpoint): Add watchpoint_triggered.
(bpstat_stop_status): Update prototype.
(watchpoints_triggered): Declare.
* infrun.c (enum infwait_status): Add infwait_step_watch_state.
(stepped_after_stopped_by_watchpoint): Delete.
(handle_inferior_event): Make stepped_after_stopped_by_watchpoint
local. Handle infwait_step_watch_state. Update calls to
bpstat_stop_status. Use watchpoints_triggered to check
watchpoints.
* remote.c (stepped_after_stopped_by_watchpoint): Remove extern.
(remote_stopped_data_address): Do not check it.
* gdb.texinfo (Setting Watchpoints): Adjust warning text about
multi-threaded watchpoints.
* gdbint.texinfo (Watchpoints): Describe how watchpoints are
checked. Describe sticky notification. Expand description
of steppable and continuable watchpoints.
(Watchpoints and Threads): New subsection.
* gdb.threads/watchthreads.c (thread_function): Sleep between
iterations.
* gdb.threads/watchthreads.exp: Allow two watchpoints to trigger
at once for S/390. Generate matching fails and passes.
Diffstat (limited to 'gdb/infrun.c')
-rw-r--r-- | gdb/infrun.c | 86 |
1 files changed, 42 insertions, 44 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c index f1a96a3..f03a5f2 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -881,6 +881,7 @@ enum infwait_states { infwait_normal_state, infwait_thread_hop_state, + infwait_step_watch_state, infwait_nonstep_watch_state }; @@ -1220,17 +1221,12 @@ adjust_pc_after_break (struct execution_control_state *ecs) by an event from the inferior, figure out what it means and take appropriate action. */ -int stepped_after_stopped_by_watchpoint; - void handle_inferior_event (struct execution_control_state *ecs) { - /* NOTE: bje/2005-05-02: If you're looking at this code and thinking - that the variable stepped_after_stopped_by_watchpoint isn't used, - then you're wrong! See remote.c:remote_stopped_data_address. */ - int sw_single_step_trap_p = 0; - int stopped_by_watchpoint = -1; /* Mark as unknown. */ + int stopped_by_watchpoint; + int stepped_after_stopped_by_watchpoint = 0; /* Cache the last pid/waitstatus. */ target_last_wait_ptid = ecs->ptid; @@ -1250,7 +1246,14 @@ handle_inferior_event (struct execution_control_state *ecs) case infwait_normal_state: if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: infwait_normal_state\n"); - stepped_after_stopped_by_watchpoint = 0; + break; + + case infwait_step_watch_state: + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: infwait_step_watch_state\n"); + + stepped_after_stopped_by_watchpoint = 1; break; case infwait_nonstep_watch_state: @@ -1435,7 +1438,7 @@ handle_inferior_event (struct execution_control_state *ecs) stop_pc = read_pc (); - stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid, 0); + stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); ecs->random_signal = !bpstat_explains_signal (stop_bpstat); @@ -1483,7 +1486,7 @@ handle_inferior_event (struct execution_control_state *ecs) ecs->saved_inferior_ptid = inferior_ptid; inferior_ptid = ecs->ptid; - stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid, 0); + stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); ecs->random_signal = !bpstat_explains_signal (stop_bpstat); inferior_ptid = ecs->saved_inferior_ptid; @@ -1796,24 +1799,20 @@ handle_inferior_event (struct execution_control_state *ecs) singlestep_breakpoints_inserted_p = 0; } - /* It may not be necessary to disable the watchpoint to stop over - it. For example, the PA can (with some kernel cooperation) - single step over a watchpoint without disabling the watchpoint. */ - if (HAVE_STEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws)) + if (stepped_after_stopped_by_watchpoint) + stopped_by_watchpoint = 0; + else + stopped_by_watchpoint = watchpoints_triggered (&ecs->ws); + + /* If necessary, step over this watchpoint. We'll be back to display + it in a moment. */ + if (stopped_by_watchpoint + && (HAVE_STEPPABLE_WATCHPOINT + || gdbarch_have_nonsteppable_watchpoint (current_gdbarch))) { if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n"); - resume (1, 0); - prepare_to_wait (ecs); - return; - } - /* It is far more common to need to disable a watchpoint to step - the inferior over it. FIXME. What else might a debug - register or page protection watchpoint scheme need here? */ - if (gdbarch_have_nonsteppable_watchpoint (current_gdbarch) - && STOPPED_BY_WATCHPOINT (ecs->ws)) - { /* At this point, we are stopped at an instruction which has attempted to write to a piece of memory under control of a watchpoint. The instruction hasn't actually executed @@ -1823,31 +1822,31 @@ handle_inferior_event (struct execution_control_state *ecs) In order to make watchpoints work `right', we really need to complete the memory write, and then evaluate the - watchpoint expression. The following code does that by - removing the watchpoint (actually, all watchpoints and - breakpoints), single-stepping the target, re-inserting - watchpoints, and then falling through to let normal - single-step processing handle proceed. Since this - includes evaluating watchpoints, things will come to a - stop in the correct manner. */ - - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n"); - remove_breakpoints (); + watchpoint expression. We do this by single-stepping the + target. + + It may not be necessary to disable the watchpoint to stop over + it. For example, the PA can (with some kernel cooperation) + single step over a watchpoint without disabling the watchpoint. + + It is far more common to need to disable a watchpoint to step + the inferior over it. If we have non-steppable watchpoints, + we must disable the current watchpoint; it's simplest to + disable all watchpoints and breakpoints. */ + + if (!HAVE_STEPPABLE_WATCHPOINT) + remove_breakpoints (); registers_changed (); target_resume (ecs->ptid, 1, TARGET_SIGNAL_0); /* Single step */ - ecs->waiton_ptid = ecs->ptid; - ecs->wp = &(ecs->ws); - ecs->infwait_state = infwait_nonstep_watch_state; + if (HAVE_STEPPABLE_WATCHPOINT) + ecs->infwait_state = infwait_step_watch_state; + else + ecs->infwait_state = infwait_nonstep_watch_state; prepare_to_wait (ecs); return; } - /* It may be possible to simply continue after a watchpoint. */ - if (HAVE_CONTINUABLE_WATCHPOINT) - stopped_by_watchpoint = STOPPED_BY_WATCHPOINT (ecs->ws); - ecs->stop_func_start = 0; ecs->stop_func_end = 0; ecs->stop_func_name = 0; @@ -1969,8 +1968,7 @@ handle_inferior_event (struct execution_control_state *ecs) else { /* See if there is a breakpoint at the current PC. */ - stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid, - stopped_by_watchpoint); + stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid); /* Following in case break condition called a function. */ |