X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Finfrun.c;h=85d889a5a29f043a2ca653faa8614745a46abeea;hb=4303944388ea72f96de9b1b662e45ac8f86cc741;hp=1a8556775ac7afff589c4f78765bd18fb147549c;hpb=f4c1edd8e5cf0259b98f7c64b0b88adef1d21d3c;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/infrun.c b/gdb/infrun.c index 1a8556775a..85d889a5a2 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -583,15 +583,41 @@ a command like `return' or `jump' to continue execution.")); resume_ptid = RESUME_ALL; /* Default */ - if ((step || singlestep_breakpoints_inserted_p) - && (stepping_past_singlestep_breakpoint - || (!breakpoints_inserted && breakpoint_here_p (read_pc ())))) + /* If STEP is set, it's a request to use hardware stepping + facilities. But in that case, we should never + use singlestep breakpoint. */ + gdb_assert (!(singlestep_breakpoints_inserted_p && step)); + + if (singlestep_breakpoints_inserted_p + && stepping_past_singlestep_breakpoint) { - /* Stepping past a breakpoint without inserting breakpoints. - Make sure only the current thread gets to step, so that - other threads don't sneak past breakpoints while they are - not inserted. */ + /* The situation here is as follows. In thread T1 we wanted to + single-step. Lacking hardware single-stepping we've + set breakpoint at the PC of the next instruction -- call it + P. After resuming, we've hit that breakpoint in thread T2. + Now we've removed original breakpoint, inserted breakpoint + at P+1, and try to step to advance T2 past breakpoint. + We need to step only T2, as if T1 is allowed to freely run, + it can run past P, and if other threads are allowed to run, + they can hit breakpoint at P+1, and nested hits of single-step + breakpoints is not something we'd want -- that's complicated + to support, and has no value. */ + resume_ptid = inferior_ptid; + } + if (step && breakpoint_here_p (read_pc ()) + && !breakpoint_inserted_here_p (read_pc ())) + { + /* We're stepping, have breakpoint at PC, and it's + not inserted. Most likely, proceed has noticed that + we have breakpoint and tries to single-step over it, + so that it's not hit. In which case, we need to + single-step only this thread, and keep others stopped, + as they can miss this breakpoint if allowed to run. + + The current code either has all breakpoints inserted, + or all removed, so if we let other threads run, + we can actually miss any breakpoint, not the one at PC. */ resume_ptid = inferior_ptid; } @@ -881,6 +907,7 @@ enum infwait_states { infwait_normal_state, infwait_thread_hop_state, + infwait_step_watch_state, infwait_nonstep_watch_state }; @@ -1220,17 +1247,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 +1272,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: @@ -1337,10 +1366,6 @@ handle_inferior_event (struct execution_control_state *ecs) #endif target_terminal_inferior (); - /* Try to reenable shared library breakpoints, additional - code segments in shared libraries might be mapped in now. */ - re_enable_breakpoints_in_shlibs (); - /* If requested, stop when the dynamic linker notifies gdb of events. This allows the user to get control and place breakpoints in initializer routines for @@ -1439,7 +1464,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); @@ -1487,7 +1512,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; @@ -1800,24 +1825,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 @@ -1827,31 +1848,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; @@ -1973,8 +1994,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. */ @@ -2276,10 +2296,6 @@ process_event_stop_test: #endif target_terminal_inferior (); - /* Try to reenable shared library breakpoints, additional - code segments in shared libraries might be mapped in now. */ - re_enable_breakpoints_in_shlibs (); - /* If requested, stop when the dynamic linker notifies gdb of events. This allows the user to get control and place breakpoints in initializer routines for @@ -2736,8 +2752,10 @@ process_event_stop_test: function. Fortunately, those days are nearly upon us. */ #endif { - struct frame_id current_frame = get_frame_id (get_current_frame ()); - if (!(frame_id_inner (current_frame, step_frame_id))) + struct frame_info *frame = get_current_frame (); + struct frame_id current_frame = get_frame_id (frame); + if (!(frame_id_inner (get_frame_arch (frame), current_frame, + step_frame_id))) step_frame_id = current_frame; }