diff options
Diffstat (limited to 'gdb/infrun.c')
-rw-r--r-- | gdb/infrun.c | 149 |
1 files changed, 56 insertions, 93 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c index bf0632e..2efbd51 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -2081,6 +2081,8 @@ start_step_over (void) step_over_what step_what; int must_be_in_line; + gdb_assert (!tp->stop_requested); + next = thread_step_over_chain_next (tp); /* If this inferior already has a displaced step in process, @@ -2329,6 +2331,8 @@ do_target_resume (ptid_t resume_ptid, int step, enum gdb_signal sig) { struct thread_info *tp = inferior_thread (); + gdb_assert (!tp->stop_requested); + /* Install inferior's terminal modes. */ target_terminal_inferior (); @@ -2393,6 +2397,7 @@ resume (enum gdb_signal sig) single-step). */ int step; + gdb_assert (!tp->stop_requested); gdb_assert (!thread_is_in_step_over_chain (tp)); QUIT; @@ -3274,65 +3279,6 @@ static void keep_going (struct execution_control_state *ecs); static void process_event_stop_test (struct execution_control_state *ecs); static int switch_back_to_stepped_thread (struct execution_control_state *ecs); -/* Callback for iterate over threads. If the thread is stopped, but - the user/frontend doesn't know about that yet, go through - normal_stop, as if the thread had just stopped now. ARG points at - a ptid. If PTID is MINUS_ONE_PTID, applies to all threads. If - ptid_is_pid(PTID) is true, applies to all threads of the process - pointed at by PTID. Otherwise, apply only to the thread pointed by - PTID. */ - -static int -infrun_thread_stop_requested_callback (struct thread_info *info, void *arg) -{ - ptid_t ptid = * (ptid_t *) arg; - - if ((ptid_equal (info->ptid, ptid) - || ptid_equal (minus_one_ptid, ptid) - || (ptid_is_pid (ptid) - && ptid_get_pid (ptid) == ptid_get_pid (info->ptid))) - && is_running (info->ptid) - && !is_executing (info->ptid)) - { - struct cleanup *old_chain; - struct execution_control_state ecss; - struct execution_control_state *ecs = &ecss; - - memset (ecs, 0, sizeof (*ecs)); - - old_chain = make_cleanup_restore_current_thread (); - - overlay_cache_invalid = 1; - /* Flush target cache before starting to handle each event. - Target was running and cache could be stale. This is just a - heuristic. Running threads may modify target memory, but we - don't get any event. */ - target_dcache_invalidate (); - - /* Go through handle_inferior_event/normal_stop, so we always - have consistent output as if the stop event had been - reported. */ - ecs->ptid = info->ptid; - ecs->event_thread = info; - ecs->ws.kind = TARGET_WAITKIND_STOPPED; - ecs->ws.value.sig = GDB_SIGNAL_0; - - handle_inferior_event (ecs); - - if (!ecs->wait_some_more) - { - /* Cancel any running execution command. */ - thread_cancel_execution_command (info); - - normal_stop (); - } - - do_cleanups (old_chain); - } - - return 0; -} - /* This function is attached as a "thread_stop_requested" observer. Cleanup local state that assumed the PTID was to be resumed, and report the stop to the frontend. */ @@ -3342,17 +3288,51 @@ infrun_thread_stop_requested (ptid_t ptid) { struct thread_info *tp; - /* PTID was requested to stop. Remove matching threads from the - step-over queue, so we don't try to resume them - automatically. */ + /* PTID was requested to stop. If the thread was already stopped, + but the user/frontend doesn't know about that yet (e.g., the + thread had been temporarily paused for some step-over), set up + for reporting the stop now. */ ALL_NON_EXITED_THREADS (tp) if (ptid_match (tp->ptid, ptid)) { + if (tp->state != THREAD_RUNNING) + continue; + if (tp->executing) + continue; + + /* Remove matching threads from the step-over queue, so + start_step_over doesn't try to resume them + automatically. */ if (thread_is_in_step_over_chain (tp)) thread_step_over_chain_remove (tp); - } - iterate_over_threads (infrun_thread_stop_requested_callback, &ptid); + /* If the thread is stopped, but the user/frontend doesn't + know about that yet, queue a pending event, as if the + thread had just stopped now. Unless the thread already had + a pending event. */ + if (!tp->suspend.waitstatus_pending_p) + { + tp->suspend.waitstatus_pending_p = 1; + tp->suspend.waitstatus.kind = TARGET_WAITKIND_STOPPED; + tp->suspend.waitstatus.value.sig = GDB_SIGNAL_0; + } + + /* Clear the inline-frame state, since we're re-processing the + stop. */ + clear_inline_frame_state (tp->ptid); + + /* If this thread was paused because some other thread was + doing an inline-step over, let that finish first. Once + that happens, we'll restart all threads and consume pending + stop events then. */ + if (step_over_info_valid_p ()) + continue; + + /* Otherwise we can process the (new) pending event now. Set + it so this pending event is considered by + do_target_wait. */ + tp->resumed = 1; + } } static void @@ -5480,6 +5460,8 @@ restart_threads (struct thread_info *event_thread) continue; } + gdb_assert (!tp->stop_requested); + /* If some thread needs to start a step-over at this point, it should still be in the step-over queue, and thus skipped above. */ @@ -5549,8 +5531,7 @@ finish_step_over (struct execution_control_state *ecs) back an event. */ gdb_assert (ecs->event_thread->control.trap_expected); - if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP) - clear_step_over_info (); + clear_step_over_info (); } if (!target_is_non_stop_p ()) @@ -6051,6 +6032,15 @@ handle_signal_stop (struct execution_control_state *ecs) if (random_signal) random_signal = !stopped_by_watchpoint; + /* Always stop if the user explicitly requested this thread to + remain stopped. */ + if (ecs->event_thread->stop_requested) + { + random_signal = 1; + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "infrun: user-requested stop\n"); + } + /* For the program's own signals, act according to the signal handling tables. */ @@ -6097,8 +6087,6 @@ handle_signal_stop (struct execution_control_state *ecs) && ecs->event_thread->control.trap_expected && ecs->event_thread->control.step_resume_breakpoint == NULL) { - int was_in_line; - /* We were just starting a new sequence, attempting to single-step off of a breakpoint and expecting a SIGTRAP. Instead this signal arrives. This signal will take us out @@ -6114,34 +6102,11 @@ handle_signal_stop (struct execution_control_state *ecs) "infrun: signal arrived while stepping over " "breakpoint\n"); - was_in_line = step_over_info_valid_p (); - clear_step_over_info (); insert_hp_step_resume_breakpoint_at_frame (frame); ecs->event_thread->step_after_step_resume_breakpoint = 1; /* Reset trap_expected to ensure breakpoints are re-inserted. */ ecs->event_thread->control.trap_expected = 0; - if (target_is_non_stop_p ()) - { - /* Either "set non-stop" is "on", or the target is - always in non-stop mode. In this case, we have a bit - more work to do. Resume the current thread, and if - we had paused all threads, restart them while the - signal handler runs. */ - keep_going (ecs); - - if (was_in_line) - { - restart_threads (ecs->event_thread); - } - else if (debug_infrun) - { - fprintf_unfiltered (gdb_stdlog, - "infrun: no need to restart threads\n"); - } - return; - } - /* If we were nexting/stepping some other thread, switch to it, so that we don't continue it, losing control. */ if (!switch_back_to_stepped_thread (ecs)) @@ -7682,8 +7647,6 @@ stop_waiting (struct execution_control_state *ecs) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: stop_waiting\n"); - clear_step_over_info (); - /* Let callers know we don't want to wait for the inferior anymore. */ ecs->wait_some_more = 0; |