diff options
author | Ulrich Weigand <uweigand@de.ibm.com> | 2008-11-17 18:50:22 +0000 |
---|---|---|
committer | Ulrich Weigand <uweigand@de.ibm.com> | 2008-11-17 18:50:22 +0000 |
commit | a721238407980aeb5617769fefde3cc3ed08aff8 (patch) | |
tree | ff1c521cac93f303e010c79e87b373692d50720d /gdb/infrun.c | |
parent | 764c62eb0185bc1f92441726066d895194ac5785 (diff) | |
download | gdb-a721238407980aeb5617769fefde3cc3ed08aff8.zip gdb-a721238407980aeb5617769fefde3cc3ed08aff8.tar.gz gdb-a721238407980aeb5617769fefde3cc3ed08aff8.tar.bz2 |
PR gdb/2250
* infrun.c (clear_proceed_status_thread): New function.
(clear_proceed_status_callback): New function.
(clear_proceed_status): In all-stop mode, clear per-thread
proceed status of *all* threads, not only the current.
(handle_inferior_event): In all-stop mode, if we're stepping
one thread, but got some inferior event in another thread
that does not cause GDB to break to the user interface,
ensure the interrupted stepping operation continues in the
original thread.
(currently_stepping): Move thread-related tests to ...
(currently_stepping_thread): ... this new function.
(currently_stepping_callback): New function.
Diffstat (limited to 'gdb/infrun.c')
-rw-r--r-- | gdb/infrun.c | 124 |
1 files changed, 102 insertions, 22 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c index 292200f..fbe0af0 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -75,6 +75,8 @@ static void set_schedlock_func (char *args, int from_tty, static int currently_stepping (struct thread_info *tp); +static int currently_stepping_callback (struct thread_info *tp, void *data); + static void xdb_handle_command (char *args, int from_tty); static int prepare_to_proceed (int); @@ -1161,31 +1163,59 @@ a command like `return' or `jump' to continue execution.")); /* Clear out all variables saying what to do when inferior is continued. First do this, then set the ones you want, then call `proceed'. */ -void -clear_proceed_status (void) +static void +clear_proceed_status_thread (struct thread_info *tp) { - if (!ptid_equal (inferior_ptid, null_ptid)) - { - struct thread_info *tp; - struct inferior *inferior; + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: clear_proceed_status_thread (%s)\n", + target_pid_to_str (tp->ptid)); - tp = inferior_thread (); + tp->trap_expected = 0; + tp->step_range_start = 0; + tp->step_range_end = 0; + tp->step_frame_id = null_frame_id; + tp->step_over_calls = STEP_OVER_UNDEBUGGABLE; + tp->stop_requested = 0; - tp->trap_expected = 0; - tp->step_range_start = 0; - tp->step_range_end = 0; - tp->step_frame_id = null_frame_id; - tp->step_over_calls = STEP_OVER_UNDEBUGGABLE; - tp->stop_requested = 0; + tp->stop_step = 0; - tp->stop_step = 0; + tp->proceed_to_finish = 0; - tp->proceed_to_finish = 0; + /* Discard any remaining commands or status from previous stop. */ + bpstat_clear (&tp->stop_bpstat); +} - /* Discard any remaining commands or status from previous - stop. */ - bpstat_clear (&tp->stop_bpstat); +static int +clear_proceed_status_callback (struct thread_info *tp, void *data) +{ + if (is_exited (tp->ptid)) + return 0; + clear_proceed_status_thread (tp); + return 0; +} + +void +clear_proceed_status (void) +{ + if (!ptid_equal (inferior_ptid, null_ptid)) + { + struct inferior *inferior; + + if (non_stop) + { + /* If in non-stop mode, only delete the per-thread status + of the current thread. */ + clear_proceed_status_thread (inferior_thread ()); + } + else + { + /* In all-stop mode, delete the per-thread status of + *all* threads. */ + iterate_over_threads (clear_proceed_status_callback, NULL); + } + inferior = current_inferior (); inferior->stop_soon = NO_STOP_QUIETLY; } @@ -3185,6 +3215,43 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); test for stepping. But, if not stepping, do not stop. */ + /* In all-stop mode, if we're currently stepping but have stopped in + some other thread, we need to switch back to the stepped thread. */ + if (!non_stop) + { + struct thread_info *tp; + tp = iterate_over_threads (currently_stepping_callback, + ecs->event_thread); + if (tp) + { + /* However, if the current thread is blocked on some internal + breakpoint, and we simply need to step over that breakpoint + to get it going again, do that first. */ + if ((ecs->event_thread->trap_expected + && ecs->event_thread->stop_signal != TARGET_SIGNAL_TRAP) + || ecs->event_thread->stepping_over_breakpoint) + { + keep_going (ecs); + return; + } + + /* Otherwise, we no longer expect a trap in the current thread. + Clear the trap_expected flag before switching back -- this is + what keep_going would do as well, if we called it. */ + ecs->event_thread->trap_expected = 0; + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: switching back to stepped thread\n"); + + ecs->event_thread = tp; + ecs->ptid = tp->ptid; + context_switch (ecs->ptid); + keep_going (ecs); + return; + } + } + /* Are we stepping to get the inferior out of the dynamic linker's hook (and possibly the dld itself) after catching a shlib event? */ @@ -3604,12 +3671,25 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); /* Are we in the middle of stepping? */ static int +currently_stepping_thread (struct thread_info *tp) +{ + return (tp->step_range_end && tp->step_resume_breakpoint == NULL) + || tp->trap_expected + || tp->stepping_through_solib_after_catch; +} + +static int +currently_stepping_callback (struct thread_info *tp, void *data) +{ + /* Return true if any thread *but* the one passed in "data" is + in the middle of stepping. */ + return tp != data && currently_stepping_thread (tp); +} + +static int currently_stepping (struct thread_info *tp) { - return (((tp->step_range_end && tp->step_resume_breakpoint == NULL) - || tp->trap_expected) - || tp->stepping_through_solib_after_catch - || bpstat_should_step ()); + return currently_stepping_thread (tp) || bpstat_should_step (); } /* Inferior has stepped into a subroutine call with source code that |