X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Finfrun.c;h=70a0790b9ac6c52340d41da5da55e06ac9124366;hb=dac790e1b9048a318e1882979d7188d82c3bd757;hp=71cf208e41fe63a809c1cfbcd620eaf362385488;hpb=46c03469b37d2ccb6a1eaa3ea4e21c57d07246fc;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/infrun.c b/gdb/infrun.c index 71cf208e41..70a0790b9a 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1,7 +1,7 @@ /* Target-struct-independent code to start (run) and stop an inferior process. - Copyright (C) 1986-2015 Free Software Foundation, Inc. + Copyright (C) 1986-2016 Free Software Foundation, Inc. This file is part of GDB. @@ -61,6 +61,9 @@ #include "target-dcache.h" #include "terminal.h" #include "solist.h" +#include "event-loop.h" +#include "thread-fsm.h" +#include "common/enum-flags.h" /* Prototypes for local functions */ @@ -101,6 +104,43 @@ static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR); static int maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc); +/* Asynchronous signal handler registered as event loop source for + when we have pending events ready to be passed to the core. */ +static struct async_event_handler *infrun_async_inferior_event_token; + +/* Stores whether infrun_async was previously enabled or disabled. + Starts off as -1, indicating "never enabled/disabled". */ +static int infrun_is_async = -1; + +/* See infrun.h. */ + +void +infrun_async (int enable) +{ + if (infrun_is_async != enable) + { + infrun_is_async = enable; + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: infrun_async(%d)\n", + enable); + + if (enable) + mark_async_event_handler (infrun_async_inferior_event_token); + else + clear_async_event_handler (infrun_async_inferior_event_token); + } +} + +/* See infrun.h. */ + +void +mark_infrun_async_event_handler (void) +{ + mark_async_event_handler (infrun_async_inferior_event_token); +} + /* When set, stop the 'step' command if we enter a function which has no line number information. The normal behavior is that we step over such function. */ @@ -112,10 +152,6 @@ show_step_stop_if_no_debug (struct ui_file *file, int from_tty, fprintf_filtered (file, _("Mode of the step operation is %s.\n"), value); } -/* In asynchronous mode, but simulating synchronous execution. */ - -int sync_execution = 0; - /* proceed and normal_stop use this to notify the user when the inferior stopped in a different thread than it had been running in. */ @@ -348,11 +384,6 @@ show_stop_on_solib_events (struct ui_file *file, int from_tty, value); } -/* Nonzero means expecting a trace trap - and should stop the inferior and return silently when it happens. */ - -int stop_after_trap; - /* Nonzero after stop if current stack frame should be printed. */ static int stop_print_frame; @@ -407,7 +438,7 @@ follow_fork_inferior (int follow_child, int detach_fork) if (has_vforked && !non_stop /* Non-stop always resumes both branches. */ - && (!target_is_async_p () || sync_execution) + && current_ui->prompt_state == PROMPT_BLOCKED && !(follow_child || detach_fork || sched_multi)) { /* The parent stays blocked inside the vfork syscall until the @@ -428,8 +459,6 @@ holding the child stopped. Try \"set detach-on-fork\" or \ /* Detach new forked process? */ if (detach_fork) { - struct cleanup *old_chain; - /* Before detaching from the child, remove all breakpoints from it. If we forked, then this has already been taken care of by infrun.c. If we vforked however, any @@ -445,11 +474,14 @@ holding the child stopped. Try \"set detach-on-fork\" or \ if (info_verbose || debug_infrun) { + /* Ensure that we have a process ptid. */ + ptid_t process_ptid = pid_to_ptid (ptid_get_pid (child_ptid)); + target_terminal_ours_for_output (); fprintf_filtered (gdb_stdlog, _("Detaching after %s from child %s.\n"), has_vforked ? "vfork" : "fork", - target_pid_to_str (child_ptid)); + target_pid_to_str (process_ptid)); } } else @@ -578,11 +610,14 @@ holding the child stopped. Try \"set detach-on-fork\" or \ { if (info_verbose || debug_infrun) { + /* Ensure that we have a process ptid. */ + ptid_t process_ptid = pid_to_ptid (ptid_get_pid (child_ptid)); + target_terminal_ours_for_output (); fprintf_filtered (gdb_stdlog, _("Detaching after fork from " "child %s.\n"), - target_pid_to_str (child_ptid)); + target_pid_to_str (process_ptid)); } target_detach (NULL, 0); @@ -646,7 +681,7 @@ follow_fork (void) CORE_ADDR step_range_start = 0; CORE_ADDR step_range_end = 0; struct frame_id step_frame_id = { 0 }; - struct interp *command_interp = NULL; + struct thread_fsm *thread_fsm = NULL; if (!non_stop) { @@ -698,7 +733,7 @@ follow_fork (void) step_frame_id = tp->control.step_frame_id; exception_resume_breakpoint = clone_momentary_breakpoint (tp->control.exception_resume_breakpoint); - command_interp = tp->control.command_interp; + thread_fsm = tp->thread_fsm; /* For now, delete the parent's sr breakpoint, otherwise, parent/child sr breakpoints are considered duplicates, @@ -710,7 +745,7 @@ follow_fork (void) tp->control.step_range_end = 0; tp->control.step_frame_id = null_frame_id; delete_exception_resume_breakpoint (tp); - tp->control.command_interp = NULL; + tp->thread_fsm = NULL; } parent = inferior_ptid; @@ -756,7 +791,7 @@ follow_fork (void) tp->control.step_frame_id = step_frame_id; tp->control.exception_resume_breakpoint = exception_resume_breakpoint; - tp->control.command_interp = command_interp; + tp->thread_fsm = thread_fsm; } else { @@ -767,7 +802,7 @@ follow_fork (void) issued is most likely not applicable to the child, so just warn, and refuse to resume. */ warning (_("Not resuming: switched threads " - "before following fork child.\n")); + "before following fork child.")); } /* Reset breakpoints in the child as appropriate. */ @@ -1050,6 +1085,7 @@ follow_exec (ptid_t ptid, char *execd_pathname) struct thread_info *th, *tmp; struct inferior *inf = current_inferior (); int pid = ptid_get_pid (ptid); + ptid_t process_ptid; /* This is an exec event that we actually wish to pay attention to. Refresh our symbol table to the newly exec'd program, remove any @@ -1116,8 +1152,9 @@ follow_exec (ptid_t ptid, char *execd_pathname) update_breakpoints_after_exec (); /* What is this a.out's name? */ + process_ptid = pid_to_ptid (pid); printf_unfiltered (_("%s is executing new program: %s\n"), - target_pid_to_str (inferior_ptid), + target_pid_to_str (process_ptid), execd_pathname); /* We've followed the inferior through an exec. Therefore, the @@ -1127,11 +1164,11 @@ follow_exec (ptid_t ptid, char *execd_pathname) breakpoint_init_inferior (inf_execd); - if (gdb_sysroot != NULL && *gdb_sysroot != '\0') + if (*gdb_sysroot != '\0') { char *name = exec_file_find (execd_pathname, NULL); - execd_pathname = alloca (strlen (name) + 1); + execd_pathname = (char *) alloca (strlen (name) + 1); strcpy (execd_pathname, name); xfree (name); } @@ -1146,20 +1183,21 @@ follow_exec (ptid_t ptid, char *execd_pathname) if (follow_exec_mode_string == follow_exec_mode_new) { - struct program_space *pspace; - /* The user wants to keep the old inferior and program spaces around. Create a new fresh one, and switch to it. */ - inf = add_inferior (current_inferior ()->pid); - pspace = add_program_space (maybe_new_address_space ()); - inf->pspace = pspace; - inf->aspace = pspace->aspace; - + /* Do exit processing for the original inferior before adding + the new inferior so we don't have two active inferiors with + the same ptid, which can confuse find_inferior_ptid. */ exit_inferior_num_silent (current_inferior ()->num); + inf = add_inferior_with_spaces (); + inf->pid = pid; + target_follow_exec (inf, execd_pathname); + set_current_inferior (inf); - set_current_program_space (pspace); + set_current_program_space (inf->pspace); + add_thread (ptid); } else { @@ -1215,6 +1253,29 @@ follow_exec (ptid_t ptid, char *execd_pathname) matically get reset there in the new process.). */ } +/* The queue of threads that need to do a step-over operation to get + past e.g., a breakpoint. What technique is used to step over the + breakpoint/watchpoint does not matter -- all threads end up in the + same queue, to maintain rough temporal order of execution, in order + to avoid starvation, otherwise, we could e.g., find ourselves + constantly stepping the same couple threads past their breakpoints + over and over, if the single-step finish fast enough. */ +struct thread_info *step_over_queue_head; + +/* Bit flags indicating what the thread needs to step over. */ + +enum step_over_what_flag + { + /* Step over a breakpoint. */ + STEP_OVER_BREAKPOINT = 1, + + /* Step past a non-continuable watchpoint, in order to let the + instruction execute so we can evaluate the watchpoint + expression. */ + STEP_OVER_WATCHPOINT = 2 + }; +DEF_ENUM_FLAGS_TYPE (enum step_over_what_flag, step_over_what); + /* Info about an instruction that is being stepped over. */ struct step_over_info @@ -1229,6 +1290,9 @@ struct step_over_info /* The instruction being stepped over triggers a nonsteppable watchpoint. If true, we'll skip inserting watchpoints. */ int nonsteppable_watchpoint_p; + + /* The thread's global number. */ + int thread; }; /* The step-over info of the location that is being stepped over. @@ -1262,11 +1326,13 @@ static struct step_over_info step_over_info; static void set_step_over_info (struct address_space *aspace, CORE_ADDR address, - int nonsteppable_watchpoint_p) + int nonsteppable_watchpoint_p, + int thread) { step_over_info.aspace = aspace; step_over_info.address = address; step_over_info.nonsteppable_watchpoint_p = nonsteppable_watchpoint_p; + step_over_info.thread = thread; } /* Called when we're not longer stepping over a breakpoint / an @@ -1275,9 +1341,13 @@ set_step_over_info (struct address_space *aspace, CORE_ADDR address, static void clear_step_over_info (void) { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: clear_step_over_info\n"); step_over_info.aspace = NULL; step_over_info.address = 0; step_over_info.nonsteppable_watchpoint_p = 0; + step_over_info.thread = -1; } /* See infrun.h. */ @@ -1294,6 +1364,15 @@ stepping_past_instruction_at (struct address_space *aspace, /* See infrun.h. */ +int +thread_is_stepping_over_breakpoint (int thread) +{ + return (step_over_info.thread != -1 + && thread == step_over_info.thread); +} + +/* See infrun.h. */ + int stepping_past_nonsteppable_watchpoint (void) { @@ -1398,12 +1477,6 @@ step_over_info_valid_p (void) displaced step operation on it. See displaced_step_prepare and displaced_step_fixup for details. */ -struct displaced_step_request -{ - ptid_t ptid; - struct displaced_step_request *next; -}; - /* Per-inferior displaced stepping state. */ struct displaced_step_inferior_state { @@ -1413,9 +1486,9 @@ struct displaced_step_inferior_state /* The process this displaced step state refers to. */ int pid; - /* A queue of pending displaced stepping requests. One entry per - thread that needs to do a displaced step. */ - struct displaced_step_request *step_request_queue; + /* True if preparing a displaced step ever failed. If so, we won't + try displaced stepping for this inferior again. */ + int failed_before; /* If this is not null_ptid, this is the thread carrying out a displaced single-step in process PID. This thread's state will @@ -1457,6 +1530,38 @@ get_displaced_stepping_state (int pid) return NULL; } +/* Returns true if any inferior has a thread doing a displaced + step. */ + +static int +displaced_step_in_progress_any_inferior (void) +{ + struct displaced_step_inferior_state *state; + + for (state = displaced_step_inferior_states; + state != NULL; + state = state->next) + if (!ptid_equal (state->step_ptid, null_ptid)) + return 1; + + return 0; +} + +/* Return true if thread represented by PTID is doing a displaced + step. */ + +static int +displaced_step_in_progress_thread (ptid_t ptid) +{ + struct displaced_step_inferior_state *displaced; + + gdb_assert (!ptid_equal (ptid, null_ptid)); + + displaced = get_displaced_stepping_state (ptid_get_pid (ptid)); + + return (displaced != NULL && ptid_equal (displaced->step_ptid, ptid)); +} + /* Return true if process PID has a thread doing a displaced step. */ static int @@ -1486,7 +1591,7 @@ add_displaced_stepping_state (int pid) if (state->pid == pid) return state; - state = xcalloc (1, sizeof (*state)); + state = XCNEW (struct displaced_step_inferior_state); state->pid = pid; state->next = displaced_step_inferior_states; displaced_step_inferior_states = state; @@ -1562,7 +1667,7 @@ show_can_use_displaced_stepping (struct ui_file *file, int from_tty, fprintf_filtered (file, _("Debugger's willingness to use displaced stepping " "to step over breakpoints is %s (currently %s).\n"), - value, non_stop ? "on" : "off"); + value, target_is_non_stop_p () ? "on" : "off"); else fprintf_filtered (file, _("Debugger's willingness to use displaced stepping " @@ -1570,15 +1675,24 @@ show_can_use_displaced_stepping (struct ui_file *file, int from_tty, } /* Return non-zero if displaced stepping can/should be used to step - over breakpoints. */ + over breakpoints of thread TP. */ static int -use_displaced_stepping (struct gdbarch *gdbarch) +use_displaced_stepping (struct thread_info *tp) { - return (((can_use_displaced_stepping == AUTO_BOOLEAN_AUTO && non_stop) + struct regcache *regcache = get_thread_regcache (tp->ptid); + struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct displaced_step_inferior_state *displaced_state; + + displaced_state = get_displaced_stepping_state (ptid_get_pid (tp->ptid)); + + return (((can_use_displaced_stepping == AUTO_BOOLEAN_AUTO + && target_is_non_stop_p ()) || can_use_displaced_stepping == AUTO_BOOLEAN_TRUE) && gdbarch_displaced_step_copy_insn_p (gdbarch) - && find_record_target () == NULL); + && find_record_target () == NULL + && (displaced_state == NULL + || !displaced_state->failed_before)); } /* Clean out any stray displaced stepping state. */ @@ -1599,7 +1713,8 @@ displaced_step_clear (struct displaced_step_inferior_state *displaced) static void displaced_step_clear_cleanup (void *arg) { - struct displaced_step_inferior_state *state = arg; + struct displaced_step_inferior_state *state + = (struct displaced_step_inferior_state *) arg; displaced_step_clear (state); } @@ -1630,14 +1745,17 @@ displaced_step_dump_bytes (struct ui_file *file, explain how we handle this case instead. Returns 1 if preparing was successful -- this thread is going to be - stepped now; or 0 if displaced stepping this thread got queued. */ + stepped now; 0 if displaced stepping this thread got queued; or -1 + if this instruction can't be displaced stepped. */ + static int -displaced_step_prepare (ptid_t ptid) +displaced_step_prepare_throw (ptid_t ptid) { struct cleanup *old_cleanups, *ignore_cleanups; struct thread_info *tp = find_thread_ptid (ptid); struct regcache *regcache = get_thread_regcache (ptid); struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct address_space *aspace = get_regcache_aspace (regcache); CORE_ADDR original, copy; ULONGEST len; struct displaced_step_closure *closure; @@ -1648,6 +1766,9 @@ displaced_step_prepare (ptid_t ptid) support displaced stepping. */ gdb_assert (gdbarch_displaced_step_copy_insn_p (gdbarch)); + /* Nor if the thread isn't meant to step over a breakpoint. */ + gdb_assert (tp->control.trap_expected); + /* Disable range stepping while executing in the scratch pad. We want a single-step even if executing the displaced instruction in the scratch buffer lands within the stepping range (e.g., a @@ -1663,28 +1784,13 @@ displaced_step_prepare (ptid_t ptid) { /* Already waiting for a displaced step to finish. Defer this request and place in queue. */ - struct displaced_step_request *req, *new_req; if (debug_displaced) fprintf_unfiltered (gdb_stdlog, - "displaced: defering step of %s\n", + "displaced: deferring step of %s\n", target_pid_to_str (ptid)); - new_req = xmalloc (sizeof (*new_req)); - new_req->ptid = ptid; - new_req->next = NULL; - - if (displaced->step_request_queue) - { - for (req = displaced->step_request_queue; - req && req->next; - req = req->next) - ; - req->next = new_req; - } - else - displaced->step_request_queue = new_req; - + thread_step_over_chain_enqueue (tp); return 0; } else @@ -1705,8 +1811,30 @@ displaced_step_prepare (ptid_t ptid) copy = gdbarch_displaced_step_location (gdbarch); len = gdbarch_max_insn_length (gdbarch); + if (breakpoint_in_range_p (aspace, copy, len)) + { + /* There's a breakpoint set in the scratch pad location range + (which is usually around the entry point). We'd either + install it before resuming, which would overwrite/corrupt the + scratch pad, or if it was already inserted, this displaced + step would overwrite it. The latter is OK in the sense that + we already assume that no thread is going to execute the code + in the scratch pad range (after initial startup) anyway, but + the former is unacceptable. Simply punt and fallback to + stepping over this breakpoint in-line. */ + if (debug_displaced) + { + fprintf_unfiltered (gdb_stdlog, + "displaced: breakpoint set in scratch pad. " + "Stepping over breakpoint in-line instead.\n"); + } + + do_cleanups (old_cleanups); + return -1; + } + /* Save the original contents of the copy area. */ - displaced->step_saved_copy = xmalloc (len); + displaced->step_saved_copy = (gdb_byte *) xmalloc (len); ignore_cleanups = make_cleanup (free_current_contents, &displaced->step_saved_copy); status = target_read_memory (copy, displaced->step_saved_copy, len); @@ -1726,9 +1854,14 @@ displaced_step_prepare (ptid_t ptid) closure = gdbarch_displaced_step_copy_insn (gdbarch, original, copy, regcache); - - /* We don't support the fully-simulated case at present. */ - gdb_assert (closure); + if (closure == NULL) + { + /* The architecture doesn't know how or want to displaced step + this instruction or instruction sequence. Fallback to + stepping over the breakpoint in-line. */ + do_cleanups (old_cleanups); + return -1; + } /* Save the information we need to fix things up if the step succeeds. */ @@ -1754,6 +1887,51 @@ displaced_step_prepare (ptid_t ptid) return 1; } +/* Wrapper for displaced_step_prepare_throw that disabled further + attempts at displaced stepping if we get a memory error. */ + +static int +displaced_step_prepare (ptid_t ptid) +{ + int prepared = -1; + + TRY + { + prepared = displaced_step_prepare_throw (ptid); + } + CATCH (ex, RETURN_MASK_ERROR) + { + struct displaced_step_inferior_state *displaced_state; + + if (ex.error != MEMORY_ERROR + && ex.error != NOT_SUPPORTED_ERROR) + throw_exception (ex); + + if (debug_infrun) + { + fprintf_unfiltered (gdb_stdlog, + "infrun: disabling displaced stepping: %s\n", + ex.message); + } + + /* Be verbose if "set displaced-stepping" is "on", silent if + "auto". */ + if (can_use_displaced_stepping == AUTO_BOOLEAN_TRUE) + { + warning (_("disabling displaced stepping: %s"), + ex.message); + } + + /* Disable further displaced stepping attempts. */ + displaced_state + = get_displaced_stepping_state (ptid_get_pid (ptid)); + displaced_state->failed_before = 1; + } + END_CATCH + + return prepared; +} + static void write_memory_ptid (ptid_t ptid, CORE_ADDR memaddr, const gdb_byte *myaddr, int len) @@ -1782,21 +1960,28 @@ displaced_step_restore (struct displaced_step_inferior_state *displaced, displaced->step_copy)); } -static void +/* If we displaced stepped an instruction successfully, adjust + registers and memory to yield the same effect the instruction would + have had if we had executed it at its original address, and return + 1. If the instruction didn't complete, relocate the PC and return + -1. If the thread wasn't displaced stepping, return 0. */ + +static int displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal) { struct cleanup *old_cleanups; struct displaced_step_inferior_state *displaced = get_displaced_stepping_state (ptid_get_pid (event_ptid)); + int ret; /* Was any thread of this process doing a displaced step? */ if (displaced == NULL) - return; + return 0; /* Was this event for the pid we displaced? */ if (ptid_equal (displaced->step_ptid, null_ptid) || ! ptid_equal (displaced->step_ptid, event_ptid)) - return; + return 0; old_cleanups = make_cleanup (displaced_step_clear_cleanup, displaced); @@ -1819,6 +2004,7 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal) displaced->step_original, displaced->step_copy, get_thread_regcache (displaced->step_ptid)); + ret = 1; } else { @@ -1829,92 +2015,164 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal) pc = displaced->step_original + (pc - displaced->step_copy); regcache_write_pc (regcache, pc); + ret = -1; } do_cleanups (old_cleanups); displaced->step_ptid = null_ptid; - /* Are there any pending displaced stepping requests? If so, run - one now. Leave the state object around, since we're likely to - need it again soon. */ - while (displaced->step_request_queue) - { - struct displaced_step_request *head; - ptid_t ptid; - struct regcache *regcache; - struct gdbarch *gdbarch; - CORE_ADDR actual_pc; - struct address_space *aspace; + return ret; +} - head = displaced->step_request_queue; - ptid = head->ptid; - displaced->step_request_queue = head->next; - xfree (head); +/* Data to be passed around while handling an event. This data is + discarded between events. */ +struct execution_control_state +{ + ptid_t ptid; + /* The thread that got the event, if this was a thread event; NULL + otherwise. */ + struct thread_info *event_thread; - context_switch (ptid); + struct target_waitstatus ws; + int stop_func_filled_in; + CORE_ADDR stop_func_start; + CORE_ADDR stop_func_end; + const char *stop_func_name; + int wait_some_more; - regcache = get_thread_regcache (ptid); - actual_pc = regcache_read_pc (regcache); - aspace = get_regcache_aspace (regcache); - gdbarch = get_regcache_arch (regcache); + /* True if the event thread hit the single-step breakpoint of + another thread. Thus the event doesn't cause a stop, the thread + needs to be single-stepped past the single-step breakpoint before + we can switch back to the original stepping thread. */ + int hit_singlestep_breakpoint; +}; - if (breakpoint_here_p (aspace, actual_pc)) - { - if (debug_displaced) - fprintf_unfiltered (gdb_stdlog, - "displaced: stepping queued %s now\n", - target_pid_to_str (ptid)); +/* Clear ECS and set it to point at TP. */ - displaced_step_prepare (ptid); +static void +reset_ecs (struct execution_control_state *ecs, struct thread_info *tp) +{ + memset (ecs, 0, sizeof (*ecs)); + ecs->event_thread = tp; + ecs->ptid = tp->ptid; +} - if (debug_displaced) - { - CORE_ADDR actual_pc = regcache_read_pc (regcache); - gdb_byte buf[4]; +static void keep_going_pass_signal (struct execution_control_state *ecs); +static void prepare_to_wait (struct execution_control_state *ecs); +static int keep_going_stepped_thread (struct thread_info *tp); +static step_over_what thread_still_needs_step_over (struct thread_info *tp); - fprintf_unfiltered (gdb_stdlog, "displaced: run %s: ", - paddress (gdbarch, actual_pc)); - read_memory (actual_pc, buf, sizeof (buf)); - displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf)); - } +/* Are there any pending step-over requests? If so, run all we can + now and return true. Otherwise, return false. */ - if (gdbarch_displaced_step_hw_singlestep (gdbarch, - displaced->step_closure)) - target_resume (ptid, 1, GDB_SIGNAL_0); - else - target_resume (ptid, 0, GDB_SIGNAL_0); +static int +start_step_over (void) +{ + struct thread_info *tp, *next; + + /* Don't start a new step-over if we already have an in-line + step-over operation ongoing. */ + if (step_over_info_valid_p ()) + return 0; + + for (tp = step_over_queue_head; tp != NULL; tp = next) + { + struct execution_control_state ecss; + struct execution_control_state *ecs = &ecss; + step_over_what step_what; + int must_be_in_line; + + next = thread_step_over_chain_next (tp); + + /* If this inferior already has a displaced step in process, + don't start a new one. */ + if (displaced_step_in_progress (ptid_get_pid (tp->ptid))) + continue; + + step_what = thread_still_needs_step_over (tp); + must_be_in_line = ((step_what & STEP_OVER_WATCHPOINT) + || ((step_what & STEP_OVER_BREAKPOINT) + && !use_displaced_stepping (tp))); + + /* We currently stop all threads of all processes to step-over + in-line. If we need to start a new in-line step-over, let + any pending displaced steps finish first. */ + if (must_be_in_line && displaced_step_in_progress_any_inferior ()) + return 0; + + thread_step_over_chain_remove (tp); - /* Done, we're stepping a thread. */ - break; + if (step_over_queue_head == NULL) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: step-over queue now empty\n"); } - else + + if (tp->control.trap_expected + || tp->resumed + || tp->executing) { - int step; - struct thread_info *tp = inferior_thread (); + internal_error (__FILE__, __LINE__, + "[%s] has inconsistent state: " + "trap_expected=%d, resumed=%d, executing=%d\n", + target_pid_to_str (tp->ptid), + tp->control.trap_expected, + tp->resumed, + tp->executing); + } - /* The breakpoint we were sitting under has since been - removed. */ - tp->control.trap_expected = 0; + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: resuming [%s] for step-over\n", + target_pid_to_str (tp->ptid)); + + /* keep_going_pass_signal skips the step-over if the breakpoint + is no longer inserted. In all-stop, we want to keep looking + for a thread that needs a step-over instead of resuming TP, + because we wouldn't be able to resume anything else until the + target stops again. In non-stop, the resume always resumes + only TP, so it's OK to let the thread resume freely. */ + if (!target_is_non_stop_p () && !step_what) + continue; - /* Go back to what we were trying to do. */ - step = currently_stepping (tp); + switch_to_thread (tp->ptid); + reset_ecs (ecs, tp); + keep_going_pass_signal (ecs); - if (step) - step = maybe_software_singlestep (gdbarch, actual_pc); + if (!ecs->wait_some_more) + error (_("Command aborted.")); - if (debug_displaced) - fprintf_unfiltered (gdb_stdlog, - "displaced: breakpoint is gone: %s, step(%d)\n", - target_pid_to_str (tp->ptid), step); + gdb_assert (tp->resumed); - target_resume (ptid, step, GDB_SIGNAL_0); - tp->suspend.stop_signal = GDB_SIGNAL_0; + /* If we started a new in-line step-over, we're done. */ + if (step_over_info_valid_p ()) + { + gdb_assert (tp->control.trap_expected); + return 1; + } - /* This request was discarded. See if there's any other - thread waiting for its turn. */ + if (!target_is_non_stop_p ()) + { + /* On all-stop, shouldn't have resumed unless we needed a + step over. */ + gdb_assert (tp->control.trap_expected + || tp->step_after_step_resume_breakpoint); + + /* With remote targets (at least), in all-stop, we can't + issue any further remote commands until the program stops + again. */ + return 1; } + + /* Either the thread no longer needed a step-over, or a new + displaced stepping sequence started. Even in the latter + case, continue looking. Maybe we can also start another + displaced step on a thread of other process. */ } + + return 0; } /* Update global variables holding ptids to hold NEW_PTID if they were @@ -1922,7 +2180,6 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal) static void infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid) { - struct displaced_step_request *it; struct displaced_step_inferior_state *displaced; if (ptid_equal (inferior_ptid, old_ptid)) @@ -1934,10 +2191,6 @@ infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid) { if (ptid_equal (displaced->step_ptid, old_ptid)) displaced->step_ptid = new_ptid; - - for (it = displaced->step_request_queue; it; it = it->next) - if (ptid_equal (it->ptid, old_ptid)) - it->ptid = new_ptid; } } @@ -1957,13 +2210,15 @@ resume_cleanups (void *ignore) static const char schedlock_off[] = "off"; static const char schedlock_on[] = "on"; static const char schedlock_step[] = "step"; +static const char schedlock_replay[] = "replay"; static const char *const scheduler_enums[] = { schedlock_off, schedlock_on, schedlock_step, + schedlock_replay, NULL }; -static const char *scheduler_mode = schedlock_off; +static const char *scheduler_mode = schedlock_replay; static void show_scheduler_mode (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -2029,6 +2284,13 @@ user_visible_resume_ptid (int step) resume. */ resume_ptid = inferior_ptid; } + else if ((scheduler_mode == schedlock_replay) + && target_record_will_replay (minus_one_ptid, execution_direction)) + { + /* User-settable 'scheduler' mode requires solo thread resume in replay + mode. */ + resume_ptid = inferior_ptid; + } else if (!sched_multi && target_supports_multi_process ()) { /* Resume all threads of the current process (and none of other @@ -2044,6 +2306,25 @@ user_visible_resume_ptid (int step) return resume_ptid; } +/* Return a ptid representing the set of threads that we will resume, + in the perspective of the target, assuming run control handling + does not require leaving some threads stopped (e.g., stepping past + breakpoint). USER_STEP indicates whether we're about to start the + target for a stepping command. */ + +static ptid_t +internal_resume_ptid (int user_step) +{ + /* In non-stop, we always control threads individually. Note that + the target may always work in non-stop mode even with "set + non-stop off", in which case user_visible_resume_ptid could + return a wildcard ptid. */ + if (target_is_non_stop_p ()) + return inferior_ptid; + else + return user_visible_resume_ptid (user_step); +} + /* Wrapper for target_resume, that handles infrun-specific bookkeeping. */ @@ -2114,10 +2395,46 @@ resume (enum gdb_signal sig) single-step). */ int step; - tp->stepped_breakpoint = 0; + gdb_assert (!thread_is_in_step_over_chain (tp)); QUIT; + if (tp->suspend.waitstatus_pending_p) + { + if (debug_infrun) + { + char *statstr; + + statstr = target_waitstatus_to_string (&tp->suspend.waitstatus); + fprintf_unfiltered (gdb_stdlog, + "infrun: resume: thread %s has pending wait status %s " + "(currently_stepping=%d).\n", + target_pid_to_str (tp->ptid), statstr, + currently_stepping (tp)); + xfree (statstr); + } + + tp->resumed = 1; + + /* FIXME: What should we do if we are supposed to resume this + thread with a signal? Maybe we should maintain a queue of + pending signals to deliver. */ + if (sig != GDB_SIGNAL_0) + { + warning (_("Couldn't deliver signal %s to %s."), + gdb_signal_to_name (sig), target_pid_to_str (tp->ptid)); + } + + tp->suspend.stop_signal = GDB_SIGNAL_0; + discard_cleanups (old_cleanups); + + if (target_can_async_p ()) + target_async (1); + return; + } + + tp->stepped_breakpoint = 0; + /* Depends on stepped_breakpoint. */ step = currently_stepping (tp); @@ -2219,9 +2536,10 @@ resume (enum gdb_signal sig) insert_single_step_breakpoint (gdbarch, aspace, pc); insert_breakpoints (); - resume_ptid = user_visible_resume_ptid (user_step); + resume_ptid = internal_resume_ptid (user_step); do_target_resume (resume_ptid, 0, GDB_SIGNAL_0); discard_cleanups (old_cleanups); + tp->resumed = 1; return; } } @@ -2243,37 +2561,50 @@ resume (enum gdb_signal sig) We can't use displaced stepping when we are waiting for vfork_done event, displaced stepping breaks the vfork child similarly as single step software breakpoint. */ - if (use_displaced_stepping (gdbarch) - && tp->control.trap_expected + if (tp->control.trap_expected + && use_displaced_stepping (tp) && !step_over_info_valid_p () && sig == GDB_SIGNAL_0 && !current_inferior ()->waiting_for_vfork_done) { - struct displaced_step_inferior_state *displaced; + int prepared = displaced_step_prepare (inferior_ptid); - if (!displaced_step_prepare (inferior_ptid)) + if (prepared == 0) { - /* Got placed in displaced stepping queue. Will be resumed - later when all the currently queued displaced stepping - requests finish. The thread is not executing at this - point, and the call to set_executing will be made later. - But we need to call set_running here, since from the - user/frontend's point of view, threads were set running. - Unless we're calling an inferior function, as in that - case we pretend the inferior doesn't run at all. */ - if (!tp->control.in_infcall) - set_running (user_visible_resume_ptid (user_step), 1); + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "Got placed in step-over queue\n"); + + tp->control.trap_expected = 0; discard_cleanups (old_cleanups); return; } + else if (prepared < 0) + { + /* Fallback to stepping over the breakpoint in-line. */ + + if (target_is_non_stop_p ()) + stop_all_threads (); + + set_step_over_info (get_regcache_aspace (regcache), + regcache_read_pc (regcache), 0, tp->global_num); + + step = maybe_software_singlestep (gdbarch, pc); + + insert_breakpoints (); + } + else if (prepared > 0) + { + struct displaced_step_inferior_state *displaced; - /* Update pc to reflect the new address from which we will execute - instructions due to displaced stepping. */ - pc = regcache_read_pc (get_thread_regcache (inferior_ptid)); + /* Update pc to reflect the new address from which we will + execute instructions due to displaced stepping. */ + pc = regcache_read_pc (get_thread_regcache (inferior_ptid)); - displaced = get_displaced_stepping_state (ptid_get_pid (inferior_ptid)); - step = gdbarch_displaced_step_hw_singlestep (gdbarch, - displaced->step_closure); + displaced = get_displaced_stepping_state (ptid_get_pid (inferior_ptid)); + step = gdbarch_displaced_step_hw_singlestep (gdbarch, + displaced->step_closure); + } } /* Do we need to do it the hard way, w/temp breakpoints? */ @@ -2332,39 +2663,32 @@ resume (enum gdb_signal sig) use singlestep breakpoint. */ gdb_assert (!(thread_has_single_step_breakpoints_set (tp) && step)); - /* Decide the set of threads to ask the target to resume. Start - by assuming everything will be resumed, than narrow the set - by applying increasingly restricting conditions. */ - resume_ptid = user_visible_resume_ptid (user_step); - - /* Even if RESUME_PTID is a wildcard, and we end up resuming less - (e.g., we might need to step over a breakpoint), from the - user/frontend's point of view, all threads in RESUME_PTID are now - running. Unless we're calling an inferior function, as in that - case pretend we inferior doesn't run at all. */ - if (!tp->control.in_infcall) - set_running (resume_ptid, 1); - - /* Maybe resume a single thread after all. */ - if ((step || thread_has_single_step_breakpoints_set (tp)) - && tp->control.trap_expected) + /* Decide the set of threads to ask the target to resume. */ + if (tp->control.trap_expected) { /* We're allowing a thread to run past a breakpoint it has - hit, by single-stepping the thread with the breakpoint - removed. 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. */ + hit, either by single-stepping the thread with the breakpoint + removed, or by displaced stepping, with the breakpoint inserted. + In the former case, we need to single-step only this thread, + and keep others stopped, as they can miss this breakpoint if + allowed to run. That's not really a problem for displaced + stepping, but, we still keep other threads stopped, in case + another thread is also stopped for a breakpoint waiting for + its turn in the displaced stepping queue. */ resume_ptid = inferior_ptid; } + else + resume_ptid = internal_resume_ptid (user_step); if (execution_direction != EXEC_REVERSE && step && breakpoint_inserted_here_p (aspace, pc)) { - /* The only case we currently need to step a breakpoint - instruction is when we have a signal to deliver. See - handle_signal_stop where we handle random signals that could - take out us out of the stepping range. Normally, in that - case we end up continuing (instead of stepping) over the + /* There are two cases where we currently need to step a + breakpoint instruction when we have a signal to deliver: + + - See handle_signal_stop where we handle random signals that + could take out us out of the stepping range. Normally, in + that case we end up continuing (instead of stepping) over the signal handler with a breakpoint at PC, but there are cases where we should _always_ single-step, even if we have a step-resume breakpoint, like when a software watchpoint is @@ -2377,8 +2701,20 @@ resume (enum gdb_signal sig) recurses and executes PC again, it'll miss the breakpoint. So we leave the breakpoint inserted anyway, but we need to record that we tried to step a breakpoint instruction, so - that adjust_pc_after_break doesn't end up confused. */ - gdb_assert (sig != GDB_SIGNAL_0); + that adjust_pc_after_break doesn't end up confused. + + - In non-stop if we insert a breakpoint (e.g., a step-resume) + in one thread after another thread that was stepping had been + momentarily paused for a step-over. When we re-resume the + stepping thread, it may be resumed from that address with a + breakpoint that hasn't trapped yet. Seen with + gdb.threads/non-stop-fair-events.exp, on targets that don't + do displaced stepping. */ + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: resume: [%s] stepped breakpoint\n", + target_pid_to_str (tp->ptid)); tp->stepped_breakpoint = 1; @@ -2390,8 +2726,8 @@ resume (enum gdb_signal sig) } if (debug_displaced - && use_displaced_stepping (gdbarch) && tp->control.trap_expected + && use_displaced_stepping (tp) && !step_over_info_valid_p ()) { struct regcache *resume_regcache = get_thread_regcache (tp->ptid); @@ -2416,15 +2752,43 @@ resume (enum gdb_signal sig) } do_target_resume (resume_ptid, step, sig); + tp->resumed = 1; discard_cleanups (old_cleanups); } /* Proceeding. */ -/* Clear out all variables saying what to do when inferior is continued. - First do this, then set the ones you want, then call `proceed'. */ +/* See infrun.h. */ -static void +/* Counter that tracks number of user visible stops. This can be used + to tell whether a command has proceeded the inferior past the + current location. This allows e.g., inferior function calls in + breakpoint commands to not interrupt the command list. When the + call finishes successfully, the inferior is standing at the same + breakpoint as if nothing happened (and so we don't call + normal_stop). */ +static ULONGEST current_stop_id; + +/* See infrun.h. */ + +ULONGEST +get_stop_id (void) +{ + return current_stop_id; +} + +/* Called when we report a user visible stop. */ + +static void +new_stop_id (void) +{ + current_stop_id++; +} + +/* Clear out all variables saying what to do when inferior is continued. + First do this, then set the ones you want, then call `proceed'. */ + +static void clear_proceed_status_thread (struct thread_info *tp) { if (debug_infrun) @@ -2432,11 +2796,45 @@ clear_proceed_status_thread (struct thread_info *tp) "infrun: clear_proceed_status_thread (%s)\n", target_pid_to_str (tp->ptid)); + /* If we're starting a new sequence, then the previous finished + single-step is no longer relevant. */ + if (tp->suspend.waitstatus_pending_p) + { + if (tp->suspend.stop_reason == TARGET_STOPPED_BY_SINGLE_STEP) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: clear_proceed_status: pending " + "event of %s was a finished step. " + "Discarding.\n", + target_pid_to_str (tp->ptid)); + + tp->suspend.waitstatus_pending_p = 0; + tp->suspend.stop_reason = TARGET_STOPPED_BY_NO_REASON; + } + else if (debug_infrun) + { + char *statstr; + + statstr = target_waitstatus_to_string (&tp->suspend.waitstatus); + fprintf_unfiltered (gdb_stdlog, + "infrun: clear_proceed_status_thread: thread %s " + "has pending wait status %s " + "(currently_stepping=%d).\n", + target_pid_to_str (tp->ptid), statstr, + currently_stepping (tp)); + xfree (statstr); + } + } + /* If this signal should not be seen by program, give it zero. Used for debugging signals. */ if (!signal_pass_state (tp->suspend.stop_signal)) tp->suspend.stop_signal = GDB_SIGNAL_0; + thread_fsm_delete (tp->thread_fsm); + tp->thread_fsm = NULL; + tp->control.trap_expected = 0; tp->control.step_range_start = 0; tp->control.step_range_end = 0; @@ -2451,7 +2849,6 @@ clear_proceed_status_thread (struct thread_info *tp) tp->control.proceed_to_finish = 0; - tp->control.command_interp = NULL; tp->control.stepping_command = 0; /* Discard any remaining commands or status from previous stop. */ @@ -2461,6 +2858,18 @@ clear_proceed_status_thread (struct thread_info *tp) void clear_proceed_status (int step) { + /* With scheduler-locking replay, stop replaying other threads if we're + not replaying the user-visible resume ptid. + + This is a convenience feature to not require the user to explicitly + stop replaying the other threads. We're assuming that the user's + intent is to resume tracing the recorded process. */ + if (!non_stop && scheduler_mode == schedlock_replay + && target_record_is_replaying (minus_one_ptid) + && !target_record_will_replay (user_visible_resume_ptid (step), + execution_direction)) + target_record_stop_replaying (); + if (!non_stop) { struct thread_info *tp; @@ -2493,10 +2902,6 @@ clear_proceed_status (int step) inferior->control.stop_soon = NO_STOP_QUIETLY; } - stop_after_trap = 0; - - clear_step_over_info (); - observer_notify_about_to_proceed (); } @@ -2505,7 +2910,7 @@ clear_proceed_status (int step) meanwhile, we can skip the whole step-over dance. */ static int -thread_still_needs_step_over (struct thread_info *tp) +thread_still_needs_step_over_bp (struct thread_info *tp) { if (tp->stepping_over_breakpoint) { @@ -2522,6 +2927,25 @@ thread_still_needs_step_over (struct thread_info *tp) return 0; } +/* Check whether thread TP still needs to start a step-over in order + to make progress when resumed. Returns an bitwise or of enum + step_over_what bits, indicating what needs to be stepped over. */ + +static step_over_what +thread_still_needs_step_over (struct thread_info *tp) +{ + step_over_what what = 0; + + if (thread_still_needs_step_over_bp (tp)) + what |= STEP_OVER_BREAKPOINT; + + if (tp->stepping_over_watchpoint + && !target_have_steppable_watchpoint) + what |= STEP_OVER_WATCHPOINT; + + return what; +} + /* Returns true if scheduler locking applies. STEP indicates whether we're about to do a step/next-like command to a thread. */ @@ -2530,49 +2954,10 @@ schedlock_applies (struct thread_info *tp) { return (scheduler_mode == schedlock_on || (scheduler_mode == schedlock_step - && tp->control.stepping_command)); -} - -/* Look a thread other than EXCEPT that has previously reported a - breakpoint event, and thus needs a step-over in order to make - progress. Returns NULL is none is found. */ - -static struct thread_info * -find_thread_needs_step_over (struct thread_info *except) -{ - struct thread_info *tp, *current; - - /* With non-stop mode on, threads are always handled individually. */ - gdb_assert (! non_stop); - - current = inferior_thread (); - - /* If scheduler locking applies, we can avoid iterating over all - threads. */ - if (schedlock_applies (except)) - { - if (except != current - && thread_still_needs_step_over (current)) - return current; - - return NULL; - } - - ALL_NON_EXITED_THREADS (tp) - { - /* Ignore the EXCEPT thread. */ - if (tp == except) - continue; - /* Ignore threads of processes we're not resuming. */ - if (!sched_multi - && ptid_get_pid (tp->ptid) != ptid_get_pid (inferior_ptid)) - continue; - - if (thread_still_needs_step_over (tp)) - return tp; - } - - return NULL; + && tp->control.stepping_command) + || (scheduler_mode == schedlock_replay + && target_record_will_replay (minus_one_ptid, + execution_direction))); } /* Basic routine for continuing the program in various fashions. @@ -2595,6 +2980,11 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) struct thread_info *tp; CORE_ADDR pc; struct address_space *aspace; + ptid_t resume_ptid; + struct execution_control_state ecss; + struct execution_control_state *ecs = &ecss; + struct cleanup *old_chain; + int started; /* If we're stopped at a fork/vfork, follow the branch set by the "set follow-fork-mode" command; otherwise, we'll just proceed @@ -2620,6 +3010,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) /* Fill in with reasonable starting values. */ init_thread_stepping_state (tp); + gdb_assert (!thread_is_in_step_over_chain (tp)); + if (addr == (CORE_ADDR) -1) { if (pc == stop_pc @@ -2649,13 +3041,21 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) if (siggnal != GDB_SIGNAL_DEFAULT) tp->suspend.stop_signal = siggnal; - /* Record the interpreter that issued the execution command that - caused this thread to resume. If the top level interpreter is - MI/async, and the execution command was a CLI command - (next/step/etc.), we'll want to print stop event output to the MI - console channel (the stepped-to line, etc.), as if the user - entered the execution command on a real GDB console. */ - inferior_thread ()->control.command_interp = command_interp (); + resume_ptid = user_visible_resume_ptid (tp->control.stepping_command); + + /* If an exception is thrown from this point on, make sure to + propagate GDB's knowledge of the executing state to the + frontend/user running state. */ + old_chain = make_cleanup (finish_thread_state_cleanup, &resume_ptid); + + /* Even if RESUME_PTID is a wildcard, and we end up resuming fewer + threads (e.g., we might need to set threads stepping over + breakpoints first), from the user/frontend's point of view, all + threads in RESUME_PTID are now running. Unless we're calling an + inferior function, as in that case we pretend the inferior + doesn't run at all. */ + if (!tp->control.in_infcall) + set_running (resume_ptid, 1); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, @@ -2663,101 +3063,139 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) paddress (gdbarch, addr), gdb_signal_to_symbol_string (siggnal)); - if (non_stop) - /* In non-stop, each thread is handled individually. The context - must already be set to the right thread here. */ - ; - else + annotate_starting (); + + /* Make sure that output from GDB appears before output from the + inferior. */ + gdb_flush (gdb_stdout); + + /* In a multi-threaded task we may select another thread and + then continue or step. + + But if a thread that we're resuming had stopped at a breakpoint, + it will immediately cause another breakpoint stop without any + execution (i.e. it will report a breakpoint hit incorrectly). So + we must step over it first. + + Look for threads other than the current (TP) that reported a + breakpoint hit and haven't been resumed yet since. */ + + /* If scheduler locking applies, we can avoid iterating over all + threads. */ + if (!non_stop && !schedlock_applies (tp)) { - struct thread_info *step_over; + struct thread_info *current = tp; - /* In a multi-threaded task we may select another thread and - then continue or step. + ALL_NON_EXITED_THREADS (tp) + { + /* Ignore the current thread here. It's handled + afterwards. */ + if (tp == current) + continue; - But if the old thread was stopped at a breakpoint, it will - immediately cause another breakpoint stop without any - execution (i.e. it will report a breakpoint hit incorrectly). - So we must step over it first. + /* Ignore threads of processes we're not resuming. */ + if (!ptid_match (tp->ptid, resume_ptid)) + continue; + + if (!thread_still_needs_step_over (tp)) + continue; + + gdb_assert (!thread_is_in_step_over_chain (tp)); - Look for a thread other than the current (TP) that reported a - breakpoint hit and hasn't been resumed yet since. */ - step_over = find_thread_needs_step_over (tp); - if (step_over != NULL) - { if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: need to step-over [%s] first\n", - target_pid_to_str (step_over->ptid)); + target_pid_to_str (tp->ptid)); - /* Store the prev_pc for the stepping thread too, needed by - switch_back_to_stepped_thread. */ - tp->prev_pc = regcache_read_pc (get_current_regcache ()); - switch_to_thread (step_over->ptid); - tp = step_over; + thread_step_over_chain_enqueue (tp); } + + tp = current; } - /* If we need to step over a breakpoint, and we're not using - displaced stepping to do so, insert all breakpoints (watchpoints, - etc.) but the one we're stepping over, step one instruction, and - then re-insert the breakpoint when that step is finished. */ - if (tp->stepping_over_breakpoint && !use_displaced_stepping (gdbarch)) - { - struct regcache *regcache = get_current_regcache (); + /* Enqueue the current thread last, so that we move all other + threads over their breakpoints first. */ + if (tp->stepping_over_breakpoint) + thread_step_over_chain_enqueue (tp); - set_step_over_info (get_regcache_aspace (regcache), - regcache_read_pc (regcache), 0); - } - else - clear_step_over_info (); + /* If the thread isn't started, we'll still need to set its prev_pc, + so that switch_back_to_stepped_thread knows the thread hasn't + advanced. Must do this before resuming any thread, as in + all-stop/remote, once we resume we can't send any other packet + until the target stops again. */ + tp->prev_pc = regcache_read_pc (regcache); - insert_breakpoints (); + started = start_step_over (); - tp->control.trap_expected = tp->stepping_over_breakpoint; + if (step_over_info_valid_p ()) + { + /* Either this thread started a new in-line step over, or some + other thread was already doing one. In either case, don't + resume anything else until the step-over is finished. */ + } + else if (started && !target_is_non_stop_p ()) + { + /* A new displaced stepping sequence was started. In all-stop, + we can't talk to the target anymore until it next stops. */ + } + else if (!non_stop && target_is_non_stop_p ()) + { + /* In all-stop, but the target is always in non-stop mode. + Start all other threads that are implicitly resumed too. */ + ALL_NON_EXITED_THREADS (tp) + { + /* Ignore threads of processes we're not resuming. */ + if (!ptid_match (tp->ptid, resume_ptid)) + continue; - annotate_starting (); + if (tp->resumed) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: proceed: [%s] resumed\n", + target_pid_to_str (tp->ptid)); + gdb_assert (tp->executing || tp->suspend.waitstatus_pending_p); + continue; + } - /* Make sure that output from GDB appears before output from the - inferior. */ - gdb_flush (gdb_stdout); + if (thread_is_in_step_over_chain (tp)) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: proceed: [%s] needs step-over\n", + target_pid_to_str (tp->ptid)); + continue; + } - /* Refresh prev_pc value just prior to resuming. This used to be - done in stop_waiting, however, setting prev_pc there did not handle - scenarios such as inferior function calls or returning from - a function via the return command. In those cases, the prev_pc - value was not set properly for subsequent commands. The prev_pc value - is used to initialize the starting line number in the ecs. With an - invalid value, the gdb next command ends up stopping at the position - represented by the next line table entry past our start position. - On platforms that generate one line table entry per line, this - is not a problem. However, on the ia64, the compiler generates - extraneous line table entries that do not increase the line number. - When we issue the gdb next command on the ia64 after an inferior call - or a return command, we often end up a few instructions forward, still - within the original line we started. - - An attempt was made to refresh the prev_pc at the same time the - execution_control_state is initialized (for instance, just before - waiting for an inferior event). But this approach did not work - because of platforms that use ptrace, where the pc register cannot - be read unless the inferior is stopped. At that point, we are not - guaranteed the inferior is stopped and so the regcache_read_pc() call - can fail. Setting the prev_pc value here ensures the value is updated - correctly when the inferior is stopped. */ - tp->prev_pc = regcache_read_pc (get_current_regcache ()); - - /* Resume inferior. */ - resume (tp->suspend.stop_signal); - - /* Wait for it to stop (if not standalone) - and in any case decode why it stopped, and act accordingly. */ - /* Do this only if we are not using the event loop, or if the target - does not support asynchronous execution. */ - if (!target_can_async_p ()) + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: proceed: resuming %s\n", + target_pid_to_str (tp->ptid)); + + reset_ecs (ecs, tp); + switch_to_thread (tp->ptid); + keep_going_pass_signal (ecs); + if (!ecs->wait_some_more) + error (_("Command aborted.")); + } + } + else if (!tp->resumed && !thread_is_in_step_over_chain (tp)) { - wait_for_inferior (); - normal_stop (); + /* The thread wasn't started, and isn't queued, run it now. */ + reset_ecs (ecs, tp); + switch_to_thread (tp->ptid); + keep_going_pass_signal (ecs); + if (!ecs->wait_some_more) + error (_("Command aborted.")); } + + discard_cleanups (old_chain); + + /* Tell the event loop to wait for it to stop. If the target + supports asynchronous execution, it'll do this from within + target_resume. */ + if (!target_can_async_p ()) + mark_async_event_handler (infrun_async_inferior_event_token); } @@ -2815,28 +3253,6 @@ init_wait_for_inferior (void) } -/* Data to be passed around while handling an event. This data is - discarded between events. */ -struct execution_control_state -{ - ptid_t ptid; - /* The thread that got the event, if this was a thread event; NULL - otherwise. */ - struct thread_info *event_thread; - - struct target_waitstatus ws; - int stop_func_filled_in; - CORE_ADDR stop_func_start; - CORE_ADDR stop_func_end; - const char *stop_func_name; - int wait_some_more; - - /* True if the event thread hit the single-step breakpoint of - another thread. Thus the event doesn't cause a stop, the thread - needs to be single-stepped past the single-step breakpoint before - we can switch back to the original stepping thread. */ - int hit_singlestep_breakpoint; -}; static void handle_inferior_event (struct execution_control_state *ecs); @@ -2850,7 +3266,6 @@ static void check_exception_resume (struct execution_control_state *, static void end_stepping_range (struct execution_control_state *ecs); static void stop_waiting (struct execution_control_state *ecs); -static void prepare_to_wait (struct execution_control_state *ecs); 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); @@ -2894,7 +3309,7 @@ infrun_thread_stop_requested_callback (struct thread_info *info, void *arg) have consistent output as if the stop event had been reported. */ ecs->ptid = info->ptid; - ecs->event_thread = find_thread_ptid (info->ptid); + ecs->event_thread = info; ecs->ws.kind = TARGET_WAITKIND_STOPPED; ecs->ws.value.sig = GDB_SIGNAL_0; @@ -2902,14 +3317,10 @@ infrun_thread_stop_requested_callback (struct thread_info *info, void *arg) if (!ecs->wait_some_more) { - struct thread_info *tp; + /* Cancel any running execution command. */ + thread_cancel_execution_command (info); normal_stop (); - - /* Finish off the continuations. */ - tp = inferior_thread (); - do_all_intermediate_continuations_thread (tp, 1); - do_all_continuations_thread (tp, 1); } do_cleanups (old_chain); @@ -2925,35 +3336,17 @@ infrun_thread_stop_requested_callback (struct thread_info *info, void *arg) static void infrun_thread_stop_requested (ptid_t ptid) { - struct displaced_step_inferior_state *displaced; - - /* PTID was requested to stop. Remove it from the displaced - stepping queue, so we don't try to resume it automatically. */ - - for (displaced = displaced_step_inferior_states; - displaced; - displaced = displaced->next) - { - struct displaced_step_request *it, **prev_next_p; - - it = displaced->step_request_queue; - prev_next_p = &displaced->step_request_queue; - while (it) - { - if (ptid_match (it->ptid, ptid)) - { - *prev_next_p = it->next; - it->next = NULL; - xfree (it); - } - else - { - prev_next_p = &it->next; - } + struct thread_info *tp; - it = *prev_next_p; - } - } + /* PTID was requested to stop. Remove matching threads from the + step-over queue, so we don't try to resume them + automatically. */ + ALL_NON_EXITED_THREADS (tp) + if (ptid_match (tp->ptid, ptid)) + { + if (thread_is_in_step_over_chain (tp)) + thread_step_over_chain_remove (tp); + } iterate_over_threads (infrun_thread_stop_requested_callback, &ptid); } @@ -2989,7 +3382,7 @@ for_each_just_stopped_thread (for_each_just_stopped_thread_callback_func func) if (!target_has_execution || ptid_equal (inferior_ptid, null_ptid)) return; - if (non_stop) + if (target_is_non_stop_p ()) { /* If in non-stop mode, only the current thread stopped. */ func (inferior_thread ()); @@ -3032,9 +3425,9 @@ delete_just_stopped_threads_infrun_breakpoints_cleanup (void *arg) delete_just_stopped_threads_infrun_breakpoints (); } -/* Pretty print the results of target_wait, for debugging purposes. */ +/* See infrun.h. */ -static void +void print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid, const struct target_waitstatus *ws) { @@ -3077,75 +3470,245 @@ print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid, ui_file_delete (tmp_stream); } -/* Prepare and stabilize the inferior for detaching it. E.g., - detaching while a thread is displaced stepping is a recipe for - crashing it, as nothing would readjust the PC out of the scratch - pad. */ +/* Select a thread at random, out of those which are resumed and have + had events. */ -void -prepare_for_detach (void) +static struct thread_info * +random_pending_event_thread (ptid_t waiton_ptid) { - struct inferior *inf = current_inferior (); - ptid_t pid_ptid = pid_to_ptid (inf->pid); - struct cleanup *old_chain_1; - struct displaced_step_inferior_state *displaced; - - displaced = get_displaced_stepping_state (inf->pid); + struct thread_info *event_tp; + int num_events = 0; + int random_selector; - /* Is any thread of this process displaced stepping? If not, - there's nothing else to do. */ - if (displaced == NULL || ptid_equal (displaced->step_ptid, null_ptid)) - return; + /* First see how many events we have. Count only resumed threads + that have an event pending. */ + ALL_NON_EXITED_THREADS (event_tp) + if (ptid_match (event_tp->ptid, waiton_ptid) + && event_tp->resumed + && event_tp->suspend.waitstatus_pending_p) + num_events++; - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "displaced-stepping in-process while detaching"); + if (num_events == 0) + return NULL; - old_chain_1 = make_cleanup_restore_integer (&inf->detaching); - inf->detaching = 1; + /* Now randomly pick a thread out of those that have had events. */ + random_selector = (int) + ((num_events * (double) rand ()) / (RAND_MAX + 1.0)); - while (!ptid_equal (displaced->step_ptid, null_ptid)) - { - struct cleanup *old_chain_2; - struct execution_control_state ecss; - struct execution_control_state *ecs; + if (debug_infrun && num_events > 1) + fprintf_unfiltered (gdb_stdlog, + "infrun: Found %d events, selecting #%d\n", + num_events, random_selector); + + /* Select the Nth thread that has had an event. */ + ALL_NON_EXITED_THREADS (event_tp) + if (ptid_match (event_tp->ptid, waiton_ptid) + && event_tp->resumed + && event_tp->suspend.waitstatus_pending_p) + if (random_selector-- == 0) + break; - ecs = &ecss; - memset (ecs, 0, sizeof (*ecs)); + return event_tp; +} - 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 (); +/* Wrapper for target_wait that first checks whether threads have + pending statuses to report before actually asking the target for + more events. */ - if (deprecated_target_wait_hook) - ecs->ptid = deprecated_target_wait_hook (pid_ptid, &ecs->ws, 0); - else - ecs->ptid = target_wait (pid_ptid, &ecs->ws, 0); +static ptid_t +do_target_wait (ptid_t ptid, struct target_waitstatus *status, int options) +{ + ptid_t event_ptid; + struct thread_info *tp; + /* First check if there is a resumed thread with a wait status + pending. */ + if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid)) + { + tp = random_pending_event_thread (ptid); + } + else + { if (debug_infrun) - print_target_wait_results (pid_ptid, ecs->ptid, &ecs->ws); + fprintf_unfiltered (gdb_stdlog, + "infrun: Waiting for specific thread %s.\n", + target_pid_to_str (ptid)); - /* If an error happens while handling the event, propagate GDB's - knowledge of the executing state to the frontend/user running - state. */ - old_chain_2 = make_cleanup (finish_thread_state_cleanup, - &minus_one_ptid); + /* We have a specific thread to check. */ + tp = find_thread_ptid (ptid); + gdb_assert (tp != NULL); + if (!tp->suspend.waitstatus_pending_p) + tp = NULL; + } - /* Now figure out what to do with the result of the result. */ - handle_inferior_event (ecs); + if (tp != NULL + && (tp->suspend.stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT + || tp->suspend.stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT)) + { + struct regcache *regcache = get_thread_regcache (tp->ptid); + struct gdbarch *gdbarch = get_regcache_arch (regcache); + CORE_ADDR pc; + int discard = 0; - /* No error, don't finish the state yet. */ - discard_cleanups (old_chain_2); + pc = regcache_read_pc (regcache); - /* Breakpoints and watchpoints are not installed on the target - at this point, and signals are passed directly to the - inferior, so this must mean the process is gone. */ - if (!ecs->wait_some_more) + if (pc != tp->suspend.stop_pc) { - discard_cleanups (old_chain_1); + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: PC of %s changed. was=%s, now=%s\n", + target_pid_to_str (tp->ptid), + paddress (gdbarch, tp->prev_pc), + paddress (gdbarch, pc)); + discard = 1; + } + else if (!breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc)) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: previous breakpoint of %s, at %s gone\n", + target_pid_to_str (tp->ptid), + paddress (gdbarch, pc)); + + discard = 1; + } + + if (discard) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: pending event of %s cancelled.\n", + target_pid_to_str (tp->ptid)); + + tp->suspend.waitstatus.kind = TARGET_WAITKIND_SPURIOUS; + tp->suspend.stop_reason = TARGET_STOPPED_BY_NO_REASON; + } + } + + if (tp != NULL) + { + if (debug_infrun) + { + char *statstr; + + statstr = target_waitstatus_to_string (&tp->suspend.waitstatus); + fprintf_unfiltered (gdb_stdlog, + "infrun: Using pending wait status %s for %s.\n", + statstr, + target_pid_to_str (tp->ptid)); + xfree (statstr); + } + + /* Now that we've selected our final event LWP, un-adjust its PC + if it was a software breakpoint (and the target doesn't + always adjust the PC itself). */ + if (tp->suspend.stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT + && !target_supports_stopped_by_sw_breakpoint ()) + { + struct regcache *regcache; + struct gdbarch *gdbarch; + int decr_pc; + + regcache = get_thread_regcache (tp->ptid); + gdbarch = get_regcache_arch (regcache); + + decr_pc = gdbarch_decr_pc_after_break (gdbarch); + if (decr_pc != 0) + { + CORE_ADDR pc; + + pc = regcache_read_pc (regcache); + regcache_write_pc (regcache, pc + decr_pc); + } + } + + tp->suspend.stop_reason = TARGET_STOPPED_BY_NO_REASON; + *status = tp->suspend.waitstatus; + tp->suspend.waitstatus_pending_p = 0; + + /* Wake up the event loop again, until all pending events are + processed. */ + if (target_is_async_p ()) + mark_async_event_handler (infrun_async_inferior_event_token); + return tp->ptid; + } + + /* But if we don't find one, we'll have to wait. */ + + if (deprecated_target_wait_hook) + event_ptid = deprecated_target_wait_hook (ptid, status, options); + else + event_ptid = target_wait (ptid, status, options); + + return event_ptid; +} + +/* Prepare and stabilize the inferior for detaching it. E.g., + detaching while a thread is displaced stepping is a recipe for + crashing it, as nothing would readjust the PC out of the scratch + pad. */ + +void +prepare_for_detach (void) +{ + struct inferior *inf = current_inferior (); + ptid_t pid_ptid = pid_to_ptid (inf->pid); + struct cleanup *old_chain_1; + struct displaced_step_inferior_state *displaced; + + displaced = get_displaced_stepping_state (inf->pid); + + /* Is any thread of this process displaced stepping? If not, + there's nothing else to do. */ + if (displaced == NULL || ptid_equal (displaced->step_ptid, null_ptid)) + return; + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "displaced-stepping in-process while detaching"); + + old_chain_1 = make_cleanup_restore_integer (&inf->detaching); + inf->detaching = 1; + + while (!ptid_equal (displaced->step_ptid, null_ptid)) + { + struct cleanup *old_chain_2; + struct execution_control_state ecss; + struct execution_control_state *ecs; + + ecs = &ecss; + memset (ecs, 0, sizeof (*ecs)); + + 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 (); + + ecs->ptid = do_target_wait (pid_ptid, &ecs->ws, 0); + + if (debug_infrun) + print_target_wait_results (pid_ptid, ecs->ptid, &ecs->ws); + + /* If an error happens while handling the event, propagate GDB's + knowledge of the executing state to the frontend/user running + state. */ + old_chain_2 = make_cleanup (finish_thread_state_cleanup, + &minus_one_ptid); + + /* Now figure out what to do with the result of the result. */ + handle_inferior_event (ecs); + + /* No error, don't finish the state yet. */ + discard_cleanups (old_chain_2); + + /* Breakpoints and watchpoints are not installed on the target + at this point, and signals are passed directly to the + inferior, so this must mean the process is gone. */ + if (!ecs->wait_some_more) + { + discard_cleanups (old_chain_1); error (_("Program exited while detaching")); } } @@ -3195,10 +3758,7 @@ wait_for_inferior (void) don't get any event. */ target_dcache_invalidate (); - if (deprecated_target_wait_hook) - ecs->ptid = deprecated_target_wait_hook (waiton_ptid, &ecs->ws, 0); - else - ecs->ptid = target_wait (waiton_ptid, &ecs->ws, 0); + ecs->ptid = do_target_wait (waiton_ptid, &ecs->ws, 0); if (debug_infrun) print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws); @@ -3229,7 +3789,9 @@ wait_for_inferior (void) static void reinstall_readline_callback_handler_cleanup (void *arg) { - if (!interpreter_async) + struct ui *ui = current_ui; + + if (!ui->async) { /* We're not going back to the top level event loop yet. Don't install the readline callback, as it'd prep the terminal, @@ -3239,10 +3801,94 @@ reinstall_readline_callback_handler_cleanup (void *arg) return; } - if (async_command_editing_p && !sync_execution) + if (ui->command_editing && ui->prompt_state != PROMPT_BLOCKED) gdb_rl_callback_handler_reinstall (); } +/* Clean up the FSMs of threads that are now stopped. In non-stop, + that's just the event thread. In all-stop, that's all threads. */ + +static void +clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs) +{ + struct thread_info *thr = ecs->event_thread; + + if (thr != NULL && thr->thread_fsm != NULL) + thread_fsm_clean_up (thr->thread_fsm, thr); + + if (!non_stop) + { + ALL_NON_EXITED_THREADS (thr) + { + if (thr->thread_fsm == NULL) + continue; + if (thr == ecs->event_thread) + continue; + + switch_to_thread (thr->ptid); + thread_fsm_clean_up (thr->thread_fsm, thr); + } + + if (ecs->event_thread != NULL) + switch_to_thread (ecs->event_thread->ptid); + } +} + +/* Helper for all_uis_check_sync_execution_done that works on the + current UI. */ + +static void +check_curr_ui_sync_execution_done (void) +{ + struct ui *ui = current_ui; + + if (ui->prompt_state == PROMPT_NEEDED + && ui->async + && !gdb_in_secondary_prompt_p (ui)) + { + target_terminal_ours (); + observer_notify_sync_execution_done (); + } +} + +/* See infrun.h. */ + +void +all_uis_check_sync_execution_done (void) +{ + struct switch_thru_all_uis state; + + SWITCH_THRU_ALL_UIS (state) + { + check_curr_ui_sync_execution_done (); + } +} + +/* See infrun.h. */ + +void +all_uis_on_sync_execution_starting (void) +{ + struct switch_thru_all_uis state; + + SWITCH_THRU_ALL_UIS (state) + { + if (current_ui->prompt_state == PROMPT_NEEDED) + async_disable_stdin (); + } +} + +/* A cleanup that restores the execution direction to the value saved + in *ARG. */ + +static void +restore_execution_direction (void *arg) +{ + enum exec_direction_kind *save_exec_dir = (enum exec_direction_kind *) arg; + + execution_direction = *save_exec_dir; +} + /* Asynchronous version of wait_for_inferior. It is called by the event loop whenever a change of state is detected on the file descriptor corresponding to the target. It can be called more than @@ -3259,12 +3905,18 @@ fetch_inferior_event (void *client_data) struct execution_control_state *ecs = &ecss; struct cleanup *old_chain = make_cleanup (null_cleanup, NULL); struct cleanup *ts_old_chain; - int was_sync = sync_execution; + enum exec_direction_kind save_exec_dir = execution_direction; int cmd_done = 0; ptid_t waiton_ptid = minus_one_ptid; memset (ecs, 0, sizeof (*ecs)); + /* Events are always processed with the main UI as current UI. This + way, warnings, debug output, etc. are always consistently sent to + the main console. */ + make_cleanup (restore_ui_cleanup, current_ui); + current_ui = main_ui; + /* End up with readline processing input, if necessary. */ make_cleanup (reinstall_readline_callback_handler_cleanup, NULL); @@ -3292,14 +3944,11 @@ fetch_inferior_event (void *client_data) event. */ target_dcache_invalidate (); - make_cleanup_restore_integer (&execution_direction); + make_cleanup (restore_execution_direction, &save_exec_dir); execution_direction = target_execution_direction (); - if (deprecated_target_wait_hook) - ecs->ptid = - deprecated_target_wait_hook (waiton_ptid, &ecs->ws, TARGET_WNOHANG); - else - ecs->ptid = target_wait (waiton_ptid, &ecs->ws, TARGET_WNOHANG); + ecs->ptid = do_target_wait (waiton_ptid, &ecs->ws, + target_can_async_p () ? TARGET_WNOHANG : 0); if (debug_infrun) print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws); @@ -3307,7 +3956,7 @@ fetch_inferior_event (void *client_data) /* If an error happens while handling the event, propagate GDB's knowledge of the executing state to the frontend/user running state. */ - if (!non_stop) + if (!target_is_non_stop_p ()) ts_old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid); else ts_old_chain = make_cleanup (finish_thread_state_cleanup, &ecs->ptid); @@ -3324,24 +3973,48 @@ fetch_inferior_event (void *client_data) if (!ecs->wait_some_more) { struct inferior *inf = find_inferior_ptid (ecs->ptid); + int should_stop = 1; + struct thread_info *thr = ecs->event_thread; + int should_notify_stop = 1; delete_just_stopped_threads_infrun_breakpoints (); - /* We may not find an inferior if this was a process exit. */ - if (inf == NULL || inf->control.stop_soon == NO_STOP_QUIETLY) - normal_stop (); - - if (target_has_execution - && ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED - && ecs->ws.kind != TARGET_WAITKIND_EXITED - && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED - && ecs->event_thread->step_multi - && ecs->event_thread->control.stop_step) - inferior_event_handler (INF_EXEC_CONTINUE, NULL); + if (thr != NULL) + { + struct thread_fsm *thread_fsm = thr->thread_fsm; + + if (thread_fsm != NULL) + should_stop = thread_fsm_should_stop (thread_fsm, thr); + } + + if (!should_stop) + { + keep_going (ecs); + } else { - inferior_event_handler (INF_EXEC_COMPLETE, NULL); - cmd_done = 1; + clean_up_just_stopped_threads_fsms (ecs); + + if (thr != NULL && thr->thread_fsm != NULL) + { + should_notify_stop + = thread_fsm_should_notify_stop (thr->thread_fsm); + } + + if (should_notify_stop) + { + int proceeded = 0; + + /* We may not find an inferior if this was a process exit. */ + if (inf == NULL || inf->control.stop_soon == NO_STOP_QUIETLY) + proceeded = normal_stop (); + + if (!proceeded) + { + inferior_event_handler (INF_EXEC_COMPLETE, NULL); + cmd_done = 1; + } + } } } @@ -3351,14 +4024,12 @@ fetch_inferior_event (void *client_data) /* Revert thread and frame. */ do_cleanups (old_chain); - /* If the inferior was in sync execution mode, and now isn't, - restore the prompt (a synchronous execution command has finished, - and we're ready for input). */ - if (interpreter_async && was_sync && !sync_execution) - observer_notify_sync_execution_done (); + /* If a UI was in sync execution mode, and now isn't, restore its + prompt (a synchronous execution command has finished, and we're + ready for input). */ + all_uis_check_sync_execution_done (); if (cmd_done - && !was_sync && exec_done_display_p && (ptid_equal (inferior_ptid, null_ptid) || !is_running (inferior_ptid))) @@ -3391,7 +4062,7 @@ init_thread_stepping_state (struct thread_info *tss) /* Set the cached copy of the last ptid/waitstatus. */ -static void +void set_last_target_status (ptid_t ptid, struct target_waitstatus status) { target_last_wait_ptid = ptid; @@ -3432,8 +4103,14 @@ context_switch (ptid_t ptid) switch_to_thread (ptid); } +/* If the target can't tell whether we've hit breakpoints + (target_supports_stopped_by_sw_breakpoint), and we got a SIGTRAP, + check whether that could have been caused by a breakpoint. If so, + adjust the PC, per gdbarch_decr_pc_after_break. */ + static void -adjust_pc_after_break (struct execution_control_state *ecs) +adjust_pc_after_break (struct thread_info *thread, + struct target_waitstatus *ws) { struct regcache *regcache; struct gdbarch *gdbarch; @@ -3461,10 +4138,10 @@ adjust_pc_after_break (struct execution_control_state *ecs) target with both of these set in GDB history, and it seems unlikely to be correct, so gdbarch_have_nonsteppable_watchpoint is not checked here. */ - if (ecs->ws.kind != TARGET_WAITKIND_STOPPED) + if (ws->kind != TARGET_WAITKIND_STOPPED) return; - if (ecs->ws.value.sig != GDB_SIGNAL_TRAP) + if (ws->value.sig != GDB_SIGNAL_TRAP) return; /* In reverse execution, when a breakpoint is hit, the instruction @@ -3510,7 +4187,7 @@ adjust_pc_after_break (struct execution_control_state *ecs) /* If this target does not decrement the PC after breakpoints, then we have nothing to do. */ - regcache = get_thread_regcache (ecs->ptid); + regcache = get_thread_regcache (thread->ptid); gdbarch = get_regcache_arch (regcache); decr_pc = gdbarch_decr_pc_after_break (gdbarch); @@ -3540,7 +4217,8 @@ adjust_pc_after_break (struct execution_control_state *ecs) to get the "stopped by SW BP and needs adjustment" info out of the target/kernel (and thus never reach here; see above). */ if (software_breakpoint_inserted_here_p (aspace, breakpoint_pc) - || (non_stop && moribund_breakpoint_here_p (aspace, breakpoint_pc))) + || (target_is_non_stop_p () + && moribund_breakpoint_here_p (aspace, breakpoint_pc))) { struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL); @@ -3564,10 +4242,10 @@ adjust_pc_after_break (struct execution_control_state *ecs) software breakpoint. In this case (prev_pc == breakpoint_pc), we also need to back up to the breakpoint address. */ - if (thread_has_single_step_breakpoints_set (ecs->event_thread) - || !currently_stepping (ecs->event_thread) - || (ecs->event_thread->stepped_breakpoint - && ecs->event_thread->prev_pc == breakpoint_pc)) + if (thread_has_single_step_breakpoints_set (thread) + || !currently_stepping (thread) + || (thread->stepped_breakpoint + && thread->prev_pc == breakpoint_pc)) regcache_write_pc (regcache, breakpoint_pc); do_cleanups (old_cleanups); @@ -3666,6 +4344,480 @@ get_inferior_stop_soon (ptid_t ptid) return inf->control.stop_soon; } +/* Wait for one event. Store the resulting waitstatus in WS, and + return the event ptid. */ + +static ptid_t +wait_one (struct target_waitstatus *ws) +{ + ptid_t event_ptid; + ptid_t wait_ptid = minus_one_ptid; + + 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 (); + + if (deprecated_target_wait_hook) + event_ptid = deprecated_target_wait_hook (wait_ptid, ws, 0); + else + event_ptid = target_wait (wait_ptid, ws, 0); + + if (debug_infrun) + print_target_wait_results (wait_ptid, event_ptid, ws); + + return event_ptid; +} + +/* Generate a wrapper for target_stopped_by_REASON that works on PTID + instead of the current thread. */ +#define THREAD_STOPPED_BY(REASON) \ +static int \ +thread_stopped_by_ ## REASON (ptid_t ptid) \ +{ \ + struct cleanup *old_chain; \ + int res; \ + \ + old_chain = save_inferior_ptid (); \ + inferior_ptid = ptid; \ + \ + res = target_stopped_by_ ## REASON (); \ + \ + do_cleanups (old_chain); \ + \ + return res; \ +} + +/* Generate thread_stopped_by_watchpoint. */ +THREAD_STOPPED_BY (watchpoint) +/* Generate thread_stopped_by_sw_breakpoint. */ +THREAD_STOPPED_BY (sw_breakpoint) +/* Generate thread_stopped_by_hw_breakpoint. */ +THREAD_STOPPED_BY (hw_breakpoint) + +/* Cleanups that switches to the PTID pointed at by PTID_P. */ + +static void +switch_to_thread_cleanup (void *ptid_p) +{ + ptid_t ptid = *(ptid_t *) ptid_p; + + switch_to_thread (ptid); +} + +/* Save the thread's event and stop reason to process it later. */ + +static void +save_waitstatus (struct thread_info *tp, struct target_waitstatus *ws) +{ + struct regcache *regcache; + struct address_space *aspace; + + if (debug_infrun) + { + char *statstr; + + statstr = target_waitstatus_to_string (ws); + fprintf_unfiltered (gdb_stdlog, + "infrun: saving status %s for %d.%ld.%ld\n", + statstr, + ptid_get_pid (tp->ptid), + ptid_get_lwp (tp->ptid), + ptid_get_tid (tp->ptid)); + xfree (statstr); + } + + /* Record for later. */ + tp->suspend.waitstatus = *ws; + tp->suspend.waitstatus_pending_p = 1; + + regcache = get_thread_regcache (tp->ptid); + aspace = get_regcache_aspace (regcache); + + if (ws->kind == TARGET_WAITKIND_STOPPED + && ws->value.sig == GDB_SIGNAL_TRAP) + { + CORE_ADDR pc = regcache_read_pc (regcache); + + adjust_pc_after_break (tp, &tp->suspend.waitstatus); + + if (thread_stopped_by_watchpoint (tp->ptid)) + { + tp->suspend.stop_reason + = TARGET_STOPPED_BY_WATCHPOINT; + } + else if (target_supports_stopped_by_sw_breakpoint () + && thread_stopped_by_sw_breakpoint (tp->ptid)) + { + tp->suspend.stop_reason + = TARGET_STOPPED_BY_SW_BREAKPOINT; + } + else if (target_supports_stopped_by_hw_breakpoint () + && thread_stopped_by_hw_breakpoint (tp->ptid)) + { + tp->suspend.stop_reason + = TARGET_STOPPED_BY_HW_BREAKPOINT; + } + else if (!target_supports_stopped_by_hw_breakpoint () + && hardware_breakpoint_inserted_here_p (aspace, + pc)) + { + tp->suspend.stop_reason + = TARGET_STOPPED_BY_HW_BREAKPOINT; + } + else if (!target_supports_stopped_by_sw_breakpoint () + && software_breakpoint_inserted_here_p (aspace, + pc)) + { + tp->suspend.stop_reason + = TARGET_STOPPED_BY_SW_BREAKPOINT; + } + else if (!thread_has_single_step_breakpoints_set (tp) + && currently_stepping (tp)) + { + tp->suspend.stop_reason + = TARGET_STOPPED_BY_SINGLE_STEP; + } + } +} + +/* A cleanup that disables thread create/exit events. */ + +static void +disable_thread_events (void *arg) +{ + target_thread_events (0); +} + +/* See infrun.h. */ + +void +stop_all_threads (void) +{ + /* We may need multiple passes to discover all threads. */ + int pass; + int iterations = 0; + ptid_t entry_ptid; + struct cleanup *old_chain; + + gdb_assert (target_is_non_stop_p ()); + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "infrun: stop_all_threads\n"); + + entry_ptid = inferior_ptid; + old_chain = make_cleanup (switch_to_thread_cleanup, &entry_ptid); + + target_thread_events (1); + make_cleanup (disable_thread_events, NULL); + + /* Request threads to stop, and then wait for the stops. Because + threads we already know about can spawn more threads while we're + trying to stop them, and we only learn about new threads when we + update the thread list, do this in a loop, and keep iterating + until two passes find no threads that need to be stopped. */ + for (pass = 0; pass < 2; pass++, iterations++) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: stop_all_threads, pass=%d, " + "iterations=%d\n", pass, iterations); + while (1) + { + ptid_t event_ptid; + struct target_waitstatus ws; + int need_wait = 0; + struct thread_info *t; + + update_thread_list (); + + /* Go through all threads looking for threads that we need + to tell the target to stop. */ + ALL_NON_EXITED_THREADS (t) + { + if (t->executing) + { + /* If already stopping, don't request a stop again. + We just haven't seen the notification yet. */ + if (!t->stop_requested) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: %s executing, " + "need stop\n", + target_pid_to_str (t->ptid)); + target_stop (t->ptid); + t->stop_requested = 1; + } + else + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: %s executing, " + "already stopping\n", + target_pid_to_str (t->ptid)); + } + + if (t->stop_requested) + need_wait = 1; + } + else + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: %s not executing\n", + target_pid_to_str (t->ptid)); + + /* The thread may be not executing, but still be + resumed with a pending status to process. */ + t->resumed = 0; + } + } + + if (!need_wait) + break; + + /* If we find new threads on the second iteration, restart + over. We want to see two iterations in a row with all + threads stopped. */ + if (pass > 0) + pass = -1; + + event_ptid = wait_one (&ws); + if (ws.kind == TARGET_WAITKIND_NO_RESUMED) + { + /* All resumed threads exited. */ + } + else if (ws.kind == TARGET_WAITKIND_THREAD_EXITED + || ws.kind == TARGET_WAITKIND_EXITED + || ws.kind == TARGET_WAITKIND_SIGNALLED) + { + if (debug_infrun) + { + ptid_t ptid = pid_to_ptid (ws.value.integer); + + fprintf_unfiltered (gdb_stdlog, + "infrun: %s exited while " + "stopping threads\n", + target_pid_to_str (ptid)); + } + } + else + { + struct inferior *inf; + + t = find_thread_ptid (event_ptid); + if (t == NULL) + t = add_thread (event_ptid); + + t->stop_requested = 0; + t->executing = 0; + t->resumed = 0; + t->control.may_range_step = 0; + + /* This may be the first time we see the inferior report + a stop. */ + inf = find_inferior_ptid (event_ptid); + if (inf->needs_setup) + { + switch_to_thread_no_regs (t); + setup_inferior (0); + } + + if (ws.kind == TARGET_WAITKIND_STOPPED + && ws.value.sig == GDB_SIGNAL_0) + { + /* We caught the event that we intended to catch, so + there's no event pending. */ + t->suspend.waitstatus.kind = TARGET_WAITKIND_IGNORE; + t->suspend.waitstatus_pending_p = 0; + + if (displaced_step_fixup (t->ptid, GDB_SIGNAL_0) < 0) + { + /* Add it back to the step-over queue. */ + if (debug_infrun) + { + fprintf_unfiltered (gdb_stdlog, + "infrun: displaced-step of %s " + "canceled: adding back to the " + "step-over queue\n", + target_pid_to_str (t->ptid)); + } + t->control.trap_expected = 0; + thread_step_over_chain_enqueue (t); + } + } + else + { + enum gdb_signal sig; + struct regcache *regcache; + + if (debug_infrun) + { + char *statstr; + + statstr = target_waitstatus_to_string (&ws); + fprintf_unfiltered (gdb_stdlog, + "infrun: target_wait %s, saving " + "status for %d.%ld.%ld\n", + statstr, + ptid_get_pid (t->ptid), + ptid_get_lwp (t->ptid), + ptid_get_tid (t->ptid)); + xfree (statstr); + } + + /* Record for later. */ + save_waitstatus (t, &ws); + + sig = (ws.kind == TARGET_WAITKIND_STOPPED + ? ws.value.sig : GDB_SIGNAL_0); + + if (displaced_step_fixup (t->ptid, sig) < 0) + { + /* Add it back to the step-over queue. */ + t->control.trap_expected = 0; + thread_step_over_chain_enqueue (t); + } + + regcache = get_thread_regcache (t->ptid); + t->suspend.stop_pc = regcache_read_pc (regcache); + + if (debug_infrun) + { + fprintf_unfiltered (gdb_stdlog, + "infrun: saved stop_pc=%s for %s " + "(currently_stepping=%d)\n", + paddress (target_gdbarch (), + t->suspend.stop_pc), + target_pid_to_str (t->ptid), + currently_stepping (t)); + } + } + } + } + } + + do_cleanups (old_chain); + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "infrun: stop_all_threads done\n"); +} + +/* Handle a TARGET_WAITKIND_NO_RESUMED event. */ + +static int +handle_no_resumed (struct execution_control_state *ecs) +{ + struct inferior *inf; + struct thread_info *thread; + + if (target_can_async_p ()) + { + struct ui *ui; + int any_sync = 0; + + ALL_UIS (ui) + { + if (ui->prompt_state == PROMPT_BLOCKED) + { + any_sync = 1; + break; + } + } + if (!any_sync) + { + /* There were no unwaited-for children left in the target, but, + we're not synchronously waiting for events either. Just + ignore. */ + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: TARGET_WAITKIND_NO_RESUMED " + "(ignoring: bg)\n"); + prepare_to_wait (ecs); + return 1; + } + } + + /* Otherwise, if we were running a synchronous execution command, we + may need to cancel it and give the user back the terminal. + + In non-stop mode, the target can't tell whether we've already + consumed previous stop events, so it can end up sending us a + no-resumed event like so: + + #0 - thread 1 is left stopped + + #1 - thread 2 is resumed and hits breakpoint + -> TARGET_WAITKIND_STOPPED + + #2 - thread 3 is resumed and exits + this is the last resumed thread, so + -> TARGET_WAITKIND_NO_RESUMED + + #3 - gdb processes stop for thread 2 and decides to re-resume + it. + + #4 - gdb processes the TARGET_WAITKIND_NO_RESUMED event. + thread 2 is now resumed, so the event should be ignored. + + IOW, if the stop for thread 2 doesn't end a foreground command, + then we need to ignore the following TARGET_WAITKIND_NO_RESUMED + event. But it could be that the event meant that thread 2 itself + (or whatever other thread was the last resumed thread) exited. + + To address this we refresh the thread list and check whether we + have resumed threads _now_. In the example above, this removes + thread 3 from the thread list. If thread 2 was re-resumed, we + ignore this event. If we find no thread resumed, then we cancel + the synchronous command show "no unwaited-for " to the user. */ + update_thread_list (); + + ALL_NON_EXITED_THREADS (thread) + { + if (thread->executing + || thread->suspend.waitstatus_pending_p) + { + /* There were no unwaited-for children left in the target at + some point, but there are now. Just ignore. */ + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: TARGET_WAITKIND_NO_RESUMED " + "(ignoring: found resumed)\n"); + prepare_to_wait (ecs); + return 1; + } + } + + /* Note however that we may find no resumed thread because the whole + process exited meanwhile (thus updating the thread list results + in an empty thread list). In this case we know we'll be getting + a process exit event shortly. */ + ALL_INFERIORS (inf) + { + if (inf->pid == 0) + continue; + + thread = any_live_thread_of_process (inf->pid); + if (thread == NULL) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: TARGET_WAITKIND_NO_RESUMED " + "(expect process exit)\n"); + prepare_to_wait (ecs); + return 1; + } + } + + /* Go ahead and report the event. */ + return 0; +} + /* Given an execution control state that has been freshly filled in by an event from the inferior, figure out what it means and take appropriate action. @@ -3680,7 +4832,7 @@ get_inferior_stop_soon (ptid_t ptid) once). */ static void -handle_inferior_event (struct execution_control_state *ecs) +handle_inferior_event_1 (struct execution_control_state *ecs) { enum stop_kind stop_soon; @@ -3701,21 +4853,18 @@ handle_inferior_event (struct execution_control_state *ecs) return; } - if (ecs->ws.kind == TARGET_WAITKIND_NO_RESUMED - && target_can_async_p () && !sync_execution) + if (ecs->ws.kind == TARGET_WAITKIND_THREAD_EXITED) { - /* There were no unwaited-for children left in the target, but, - we're not synchronously waiting for events either. Just - ignore. Otherwise, if we were running a synchronous - execution command, we need to cancel it and give the user - back the terminal. */ if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: TARGET_WAITKIND_NO_RESUMED (ignoring)\n"); + fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_THREAD_EXITED\n"); prepare_to_wait (ecs); return; } + if (ecs->ws.kind == TARGET_WAITKIND_NO_RESUMED + && handle_no_resumed (ecs)) + return; + /* Cache the last pid/waitstatus. */ set_last_target_status (ecs->ptid, ecs->ws); @@ -3748,7 +4897,7 @@ handle_inferior_event (struct execution_control_state *ecs) } /* Dependent on valid ECS->EVENT_THREAD. */ - adjust_pc_after_break (ecs); + adjust_pc_after_break (ecs->event_thread, &ecs->ws); /* Dependent on the current PC value modified by adjust_pc_after_break. */ reinit_frame_cache (); @@ -3784,15 +4933,39 @@ handle_inferior_event (struct execution_control_state *ecs) /* Mark the non-executing threads accordingly. In all-stop, all threads of all processes are stopped when we get any event - reported. In non-stop mode, only the event thread stops. If - we're handling a process exit in non-stop mode, there's nothing - to do, as threads of the dead process are gone, and threads of - any other process were left running. */ - if (!non_stop) - set_executing (minus_one_ptid, 0); - else if (ecs->ws.kind != TARGET_WAITKIND_SIGNALLED - && ecs->ws.kind != TARGET_WAITKIND_EXITED) - set_executing (ecs->ptid, 0); + reported. In non-stop mode, only the event thread stops. */ + { + ptid_t mark_ptid; + + if (!target_is_non_stop_p ()) + mark_ptid = minus_one_ptid; + else if (ecs->ws.kind == TARGET_WAITKIND_SIGNALLED + || ecs->ws.kind == TARGET_WAITKIND_EXITED) + { + /* If we're handling a process exit in non-stop mode, even + though threads haven't been deleted yet, one would think + that there is nothing to do, as threads of the dead process + will be soon deleted, and threads of any other process were + left running. However, on some targets, threads survive a + process exit event. E.g., for the "checkpoint" command, + when the current checkpoint/fork exits, linux-fork.c + automatically switches to another fork from within + target_mourn_inferior, by associating the same + inferior/thread to another fork. We haven't mourned yet at + this point, but we must mark any threads left in the + process as not-executing so that finish_thread_state marks + them stopped (in the user's perspective) if/when we present + the stop to the user. */ + mark_ptid = pid_to_ptid (ptid_get_pid (ecs->ptid)); + } + else + mark_ptid = ecs->ptid; + + set_executing (mark_ptid, 0); + + /* Likewise the resumed flag. */ + set_resumed (mark_ptid, 0); + } switch (ecs->ws.kind) { @@ -3881,6 +5054,15 @@ handle_inferior_event (struct execution_control_state *ecs) prepare_to_wait (ecs); return; + case TARGET_WAITKIND_THREAD_CREATED: + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_THREAD_CREATED\n"); + if (!ptid_equal (ecs->ptid, inferior_ptid)) + context_switch (ecs->ptid); + if (!switch_back_to_stepped_thread (ecs)) + keep_going (ecs); + return; + case TARGET_WAITKIND_EXITED: case TARGET_WAITKIND_SIGNALLED: if (debug_infrun) @@ -3970,12 +5152,10 @@ Cannot fill $_exitsignal with the correct signal number.\n")); { struct regcache *regcache = get_thread_regcache (ecs->ptid); struct gdbarch *gdbarch = get_regcache_arch (regcache); - struct displaced_step_inferior_state *displaced - = get_displaced_stepping_state (ptid_get_pid (ecs->ptid)); /* If checking displaced stepping is supported, and thread ecs->ptid is displaced stepping. */ - if (displaced && ptid_equal (displaced->step_ptid, ecs->ptid)) + if (displaced_step_in_progress_thread (ecs->ptid)) { struct inferior *parent_inf = find_inferior_ptid (ecs->ptid); @@ -3988,9 +5168,15 @@ Cannot fill $_exitsignal with the correct signal number.\n")); that this operation also cleans up the child process for vfork, because their pages are shared. */ displaced_step_fixup (ecs->ptid, GDB_SIGNAL_TRAP); + /* Start a new step-over in another thread if there's one + that needs it. */ + start_step_over (); if (ecs->ws.kind == TARGET_WAITKIND_FORKED) { + struct displaced_step_inferior_state *displaced + = get_displaced_stepping_state (ptid_get_pid (ecs->ptid)); + /* Restore scratch pad for child process. */ displaced_step_restore (displaced, ecs->ws.value.related_pid); } @@ -4074,8 +5260,20 @@ Cannot fill $_exitsignal with the correct signal number.\n")); parent = ecs->ptid; child = ecs->ws.value.related_pid; + /* At this point, the parent is marked running, and the + child is marked stopped. */ + + /* If not resuming the parent, mark it stopped. */ + if (follow_child && !detach_fork && !non_stop && !sched_multi) + set_running (parent, 0); + + /* If resuming the child, mark it running. */ + if (follow_child || (!detach_fork && (non_stop || sched_multi))) + set_running (child, 1); + /* In non-stop mode, also resume the other branch. */ - if (non_stop && !detach_fork) + if (!detach_fork && (non_stop + || (sched_multi && target_is_non_stop_p ()))) { if (follow_child) switch_to_thread (parent); @@ -4139,6 +5337,11 @@ Cannot fill $_exitsignal with the correct signal number.\n")); stop. */ follow_exec (inferior_ptid, ecs->ws.value.execd_pathname); + /* In follow_exec we may have deleted the original thread and + created a new one. Make sure that the event thread is the + execd thread for that case (this is a nop otherwise). */ + ecs->event_thread = inferior_thread (); + ecs->event_thread->control.stop_bpstat = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()), stop_pc, ecs->ptid, &ecs->ws); @@ -4194,14 +5397,272 @@ Cannot fill $_exitsignal with the correct signal number.\n")); fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_NO_HISTORY\n"); /* Reverse execution: target ran out of history info. */ + /* Switch to the stopped thread. */ + if (!ptid_equal (ecs->ptid, inferior_ptid)) + context_switch (ecs->ptid); + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n"); + delete_just_stopped_threads_single_step_breakpoints (); - stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); + stop_pc = regcache_read_pc (get_thread_regcache (inferior_ptid)); observer_notify_no_history (); stop_waiting (ecs); return; } } +/* A wrapper around handle_inferior_event_1, which also makes sure + that all temporary struct value objects that were created during + the handling of the event get deleted at the end. */ + +static void +handle_inferior_event (struct execution_control_state *ecs) +{ + struct value *mark = value_mark (); + + handle_inferior_event_1 (ecs); + /* Purge all temporary values created during the event handling, + as it could be a long time before we return to the command level + where such values would otherwise be purged. */ + value_free_to_mark (mark); +} + +/* Restart threads back to what they were trying to do back when we + paused them for an in-line step-over. The EVENT_THREAD thread is + ignored. */ + +static void +restart_threads (struct thread_info *event_thread) +{ + struct thread_info *tp; + + /* In case the instruction just stepped spawned a new thread. */ + update_thread_list (); + + ALL_NON_EXITED_THREADS (tp) + { + if (tp == event_thread) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: restart threads: " + "[%s] is event thread\n", + target_pid_to_str (tp->ptid)); + continue; + } + + if (!(tp->state == THREAD_RUNNING || tp->control.in_infcall)) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: restart threads: " + "[%s] not meant to be running\n", + target_pid_to_str (tp->ptid)); + continue; + } + + if (tp->resumed) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: restart threads: [%s] resumed\n", + target_pid_to_str (tp->ptid)); + gdb_assert (tp->executing || tp->suspend.waitstatus_pending_p); + continue; + } + + if (thread_is_in_step_over_chain (tp)) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: restart threads: " + "[%s] needs step-over\n", + target_pid_to_str (tp->ptid)); + gdb_assert (!tp->resumed); + continue; + } + + + if (tp->suspend.waitstatus_pending_p) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: restart threads: " + "[%s] has pending status\n", + target_pid_to_str (tp->ptid)); + tp->resumed = 1; + continue; + } + + /* 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. */ + if (thread_still_needs_step_over (tp)) + { + internal_error (__FILE__, __LINE__, + "thread [%s] needs a step-over, but not in " + "step-over queue\n", + target_pid_to_str (tp->ptid)); + } + + if (currently_stepping (tp)) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: restart threads: [%s] was stepping\n", + target_pid_to_str (tp->ptid)); + keep_going_stepped_thread (tp); + } + else + { + struct execution_control_state ecss; + struct execution_control_state *ecs = &ecss; + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: restart threads: [%s] continuing\n", + target_pid_to_str (tp->ptid)); + reset_ecs (ecs, tp); + switch_to_thread (tp->ptid); + keep_going_pass_signal (ecs); + } + } +} + +/* Callback for iterate_over_threads. Find a resumed thread that has + a pending waitstatus. */ + +static int +resumed_thread_with_pending_status (struct thread_info *tp, + void *arg) +{ + return (tp->resumed + && tp->suspend.waitstatus_pending_p); +} + +/* Called when we get an event that may finish an in-line or + out-of-line (displaced stepping) step-over started previously. + Return true if the event is processed and we should go back to the + event loop; false if the caller should continue processing the + event. */ + +static int +finish_step_over (struct execution_control_state *ecs) +{ + int had_step_over_info; + + displaced_step_fixup (ecs->ptid, + ecs->event_thread->suspend.stop_signal); + + had_step_over_info = step_over_info_valid_p (); + + if (had_step_over_info) + { + /* If we're stepping over a breakpoint with all threads locked, + then only the thread that was stepped should be reporting + 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 (); + } + + if (!target_is_non_stop_p ()) + return 0; + + /* Start a new step-over in another thread if there's one that + needs it. */ + start_step_over (); + + /* If we were stepping over a breakpoint before, and haven't started + a new in-line step-over sequence, then restart all other threads + (except the event thread). We can't do this in all-stop, as then + e.g., we wouldn't be able to issue any other remote packet until + these other threads stop. */ + if (had_step_over_info && !step_over_info_valid_p ()) + { + struct thread_info *pending; + + /* If we only have threads with pending statuses, the restart + below won't restart any thread and so nothing re-inserts the + breakpoint we just stepped over. But we need it inserted + when we later process the pending events, otherwise if + another thread has a pending event for this breakpoint too, + we'd discard its event (because the breakpoint that + originally caused the event was no longer inserted). */ + context_switch (ecs->ptid); + insert_breakpoints (); + + restart_threads (ecs->event_thread); + + /* If we have events pending, go through handle_inferior_event + again, picking up a pending event at random. This avoids + thread starvation. */ + + /* But not if we just stepped over a watchpoint in order to let + the instruction execute so we can evaluate its expression. + The set of watchpoints that triggered is recorded in the + breakpoint objects themselves (see bp->watchpoint_triggered). + If we processed another event first, that other event could + clobber this info. */ + if (ecs->event_thread->stepping_over_watchpoint) + return 0; + + pending = iterate_over_threads (resumed_thread_with_pending_status, + NULL); + if (pending != NULL) + { + struct thread_info *tp = ecs->event_thread; + struct regcache *regcache; + + if (debug_infrun) + { + fprintf_unfiltered (gdb_stdlog, + "infrun: found resumed threads with " + "pending events, saving status\n"); + } + + gdb_assert (pending != tp); + + /* Record the event thread's event for later. */ + save_waitstatus (tp, &ecs->ws); + /* This was cleared early, by handle_inferior_event. Set it + so this pending event is considered by + do_target_wait. */ + tp->resumed = 1; + + gdb_assert (!tp->executing); + + regcache = get_thread_regcache (tp->ptid); + tp->suspend.stop_pc = regcache_read_pc (regcache); + + if (debug_infrun) + { + fprintf_unfiltered (gdb_stdlog, + "infrun: saved stop_pc=%s for %s " + "(currently_stepping=%d)\n", + paddress (target_gdbarch (), + tp->suspend.stop_pc), + target_pid_to_str (tp->ptid), + currently_stepping (tp)); + } + + /* This in-line step-over finished; clear this so we won't + start a new one. This is what handle_signal_stop would + do, if we returned false. */ + tp->stepping_over_breakpoint = 0; + + /* Wake up the event loop again. */ + mark_async_event_handler (infrun_async_inferior_event_token); + + prepare_to_wait (ecs); + return 1; + } + } + + return 0; +} + /* Come here when the program has stopped with a signal. */ static void @@ -4218,8 +5679,8 @@ handle_signal_stop (struct execution_control_state *ecs) /* Do we need to clean up the state of a thread that has completed a displaced single-step? (Doing so usually affects the PC, so do it here, before we set stop_pc.) */ - displaced_step_fixup (ecs->ptid, - ecs->event_thread->suspend.stop_signal); + if (finish_step_over (ecs)) + return; /* If we either finished a single-step or hit a breakpoint, but the user wanted this thread to be stopped, pretend we got a @@ -4272,18 +5733,6 @@ handle_signal_stop (struct execution_control_state *ecs) return; } - if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP - && stop_after_trap) - { - if (!ptid_equal (ecs->ptid, inferior_ptid)) - context_switch (ecs->ptid); - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n"); - stop_print_frame = 0; - stop_waiting (ecs); - return; - } - /* This originates from attach_command(). We need to overwrite the stop_signal here, because some kernels don't ignore a SIGSTOP in a subsequent ptrace(PTRACE_CONT,SIGSTOP) call. @@ -4325,7 +5774,7 @@ handle_signal_stop (struct execution_control_state *ecs) context_switch (ecs->ptid); if (deprecated_context_hook) - deprecated_context_hook (pid_to_thread_id (ecs->ptid)); + deprecated_context_hook (ptid_to_global_thread_id (ecs->ptid)); } /* At this point, get hold of the now-current thread's frame. */ @@ -4662,6 +6111,8 @@ 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 @@ -4677,11 +6128,34 @@ 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)) @@ -4710,6 +6184,7 @@ handle_signal_stop (struct execution_control_state *ecs) "infrun: signal may take us out of " "single-step range\n"); + 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. */ @@ -4766,6 +6241,10 @@ process_event_stop_test (struct execution_control_state *ecs) stop_stack_dummy = what.call_dummy; } + /* A few breakpoint types have callbacks associated (e.g., + bp_jit_event). Run them now. */ + bpstat_run_callbacks (ecs->event_thread->control.stop_bpstat); + /* If we hit an internal event that triggers symbol changes, the current frame will be invalidated within bpstat_what (e.g., if we hit an internal solib event). Re-fetch it. */ @@ -5565,11 +7044,10 @@ process_event_stop_test (struct execution_control_state *ecs) static int switch_back_to_stepped_thread (struct execution_control_state *ecs) { - if (!non_stop) + if (!target_is_non_stop_p ()) { struct thread_info *tp; struct thread_info *stepping_thread; - struct thread_info *step_over; /* If any thread is blocked on some internal breakpoint, and we simply need to step over that breakpoint to get it going @@ -5612,14 +7090,20 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) return 1; } - /* Otherwise, we no longer expect a trap in the current thread. - Clear the trap_expected flag before switching back -- this is - what keep_going does as well, if we call it. */ - ecs->event_thread->control.trap_expected = 0; - - /* Likewise, clear the signal if it should not be passed. */ - if (!signal_program[ecs->event_thread->suspend.stop_signal]) - ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0; + /* If this thread needs yet another step-over (e.g., stepping + through a delay slot), do it first before moving on to + another thread. */ + if (thread_still_needs_step_over (ecs->event_thread)) + { + if (debug_infrun) + { + fprintf_unfiltered (gdb_stdlog, + "infrun: thread [%s] still needs step-over\n", + target_pid_to_str (ecs->event_thread->ptid)); + } + keep_going (ecs); + return 1; + } /* If scheduler locking applies even if not stepping, there's no need to walk over threads. Above we've checked whether the @@ -5629,24 +7113,46 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) if (schedlock_applies (ecs->event_thread)) return 0; - /* Look for the stepping/nexting thread, and check if any other - thread other than the stepping thread needs to start a - step-over. Do all step-overs before actually proceeding with + /* Otherwise, we no longer expect a trap in the current thread. + Clear the trap_expected flag before switching back -- this is + what keep_going does as well, if we call it. */ + ecs->event_thread->control.trap_expected = 0; + + /* Likewise, clear the signal if it should not be passed. */ + if (!signal_program[ecs->event_thread->suspend.stop_signal]) + ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0; + + /* Do all pending step-overs before actually proceeding with step/next/etc. */ + if (start_step_over ()) + { + prepare_to_wait (ecs); + return 1; + } + + /* Look for the stepping/nexting thread. */ stepping_thread = NULL; - step_over = NULL; + ALL_NON_EXITED_THREADS (tp) { - /* Ignore threads of processes we're not resuming. */ + /* Ignore threads of processes the caller is not + resuming. */ if (!sched_multi - && ptid_get_pid (tp->ptid) != ptid_get_pid (inferior_ptid)) + && ptid_get_pid (tp->ptid) != ptid_get_pid (ecs->ptid)) continue; /* When stepping over a breakpoint, we lock all threads except the one that needs to move past the breakpoint. If a non-event thread has this set, the "incomplete step-over" check above should have caught it earlier. */ - gdb_assert (!tp->control.trap_expected); + if (tp->control.trap_expected) + { + internal_error (__FILE__, __LINE__, + "[%s] has inconsistent state: " + "trap_expected=%d\n", + target_pid_to_str (tp->ptid), + tp->control.trap_expected); + } /* Did we find the stepping thread? */ if (tp->control.step_range_end) @@ -5666,145 +7172,131 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) stepping_thread = tp; } - else if (thread_still_needs_step_over (tp)) - { - step_over = tp; - - /* At the top we've returned early if the event thread - is stepping. If some other thread not the event - thread is stepping, then scheduler locking can't be - in effect, and we can resume this thread. No need to - keep looking for the stepping thread then. */ - break; - } } - if (step_over != NULL) + if (stepping_thread != NULL) { - tp = step_over; if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: switching back to stepped thread\n"); + + if (keep_going_stepped_thread (stepping_thread)) { - fprintf_unfiltered (gdb_stdlog, - "infrun: need to step-over [%s]\n", - target_pid_to_str (tp->ptid)); + prepare_to_wait (ecs); + return 1; } + } + } - /* Only the stepping thread should have this set. */ - gdb_assert (tp->control.step_range_end == 0); + return 0; +} - ecs->ptid = tp->ptid; - ecs->event_thread = tp; - switch_to_thread (ecs->ptid); - keep_going (ecs); - return 1; - } +/* Set a previously stepped thread back to stepping. Returns true on + success, false if the resume is not possible (e.g., the thread + vanished). */ - if (stepping_thread != NULL) - { - struct frame_info *frame; - struct gdbarch *gdbarch; +static int +keep_going_stepped_thread (struct thread_info *tp) +{ + struct frame_info *frame; + struct execution_control_state ecss; + struct execution_control_state *ecs = &ecss; - tp = stepping_thread; - - /* If the stepping thread exited, then don't try to switch - back and resume it, which could fail in several different - ways depending on the target. Instead, just keep going. - - We can find a stepping dead thread in the thread list in - two cases: - - - The target supports thread exit events, and when the - target tries to delete the thread from the thread list, - inferior_ptid pointed at the exiting thread. In such - case, calling delete_thread does not really remove the - thread from the list; instead, the thread is left listed, - with 'exited' state. - - - The target's debug interface does not support thread - exit events, and so we have no idea whatsoever if the - previously stepping thread is still alive. For that - reason, we need to synchronously query the target - now. */ - if (is_exited (tp->ptid) - || !target_thread_alive (tp->ptid)) - { - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: not switching back to " - "stepped thread, it has vanished\n"); + /* If the stepping thread exited, then don't try to switch back and + resume it, which could fail in several different ways depending + on the target. Instead, just keep going. + + We can find a stepping dead thread in the thread list in two + cases: + + - The target supports thread exit events, and when the target + tries to delete the thread from the thread list, inferior_ptid + pointed at the exiting thread. In such case, calling + delete_thread does not really remove the thread from the list; + instead, the thread is left listed, with 'exited' state. + + - The target's debug interface does not support thread exit + events, and so we have no idea whatsoever if the previously + stepping thread is still alive. For that reason, we need to + synchronously query the target now. */ + + if (is_exited (tp->ptid) + || !target_thread_alive (tp->ptid)) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: not resuming previously " + "stepped thread, it has vanished\n"); + + delete_thread (tp->ptid); + return 0; + } + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: resuming previously stepped thread\n"); - delete_thread (tp->ptid); - keep_going (ecs); - return 1; - } + reset_ecs (ecs, tp); + switch_to_thread (tp->ptid); - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: switching back to stepped thread\n"); + stop_pc = regcache_read_pc (get_thread_regcache (tp->ptid)); + frame = get_current_frame (); - ecs->event_thread = tp; - ecs->ptid = tp->ptid; - context_switch (ecs->ptid); + /* If the PC of the thread we were trying to single-step has + changed, then that thread has trapped or been signaled, but the + event has not been reported to GDB yet. Re-poll the target + looking for this particular thread's event (i.e. temporarily + enable schedlock) by: - stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); - frame = get_current_frame (); - gdbarch = get_frame_arch (frame); + - setting a break at the current PC + - resuming that particular thread, only (by setting trap + expected) - /* If the PC of the thread we were trying to single-step has - changed, then that thread has trapped or been signaled, - but the event has not been reported to GDB yet. Re-poll - the target looking for this particular thread's event - (i.e. temporarily enable schedlock) by: + This prevents us continuously moving the single-step breakpoint + forward, one instruction at a time, overstepping. */ - - setting a break at the current PC - - resuming that particular thread, only (by setting - trap expected) + if (stop_pc != tp->prev_pc) + { + ptid_t resume_ptid; - This prevents us continuously moving the single-step - breakpoint forward, one instruction at a time, - overstepping. */ + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: expected thread advanced also (%s -> %s)\n", + paddress (target_gdbarch (), tp->prev_pc), + paddress (target_gdbarch (), stop_pc)); + + /* Clear the info of the previous step-over, as it's no longer + valid (if the thread was trying to step over a breakpoint, it + has already succeeded). It's what keep_going would do too, + if we called it. Do this before trying to insert the sss + breakpoint, otherwise if we were previously trying to step + over this exact address in another thread, the breakpoint is + skipped. */ + clear_step_over_info (); + tp->control.trap_expected = 0; - if (stop_pc != tp->prev_pc) - { - ptid_t resume_ptid; + insert_single_step_breakpoint (get_frame_arch (frame), + get_frame_address_space (frame), + stop_pc); - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: expected thread advanced also\n"); - - /* Clear the info of the previous step-over, as it's no - longer valid. It's what keep_going would do too, if - we called it. Must do this before trying to insert - the sss breakpoint, otherwise if we were previously - trying to step over this exact address in another - thread, the breakpoint ends up not installed. */ - clear_step_over_info (); - - insert_single_step_breakpoint (get_frame_arch (frame), - get_frame_address_space (frame), - stop_pc); - - resume_ptid = user_visible_resume_ptid (tp->control.stepping_command); - do_target_resume (resume_ptid, - currently_stepping (tp), GDB_SIGNAL_0); - prepare_to_wait (ecs); - } - else - { - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: expected thread still " - "hasn't advanced\n"); - keep_going (ecs); - } + tp->resumed = 1; + resume_ptid = internal_resume_ptid (tp->control.stepping_command); + do_target_resume (resume_ptid, 0, GDB_SIGNAL_0); + } + else + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: expected thread still hasn't advanced\n"); - return 1; - } + keep_going_pass_signal (ecs); } - return 0; + return 1; } -/* Is thread TP in the middle of single-stepping? */ +/* Is thread TP in the middle of (software or hardware) + single-stepping? (Note the result of this function must never be + passed directly as target_resume's STEP parameter.) */ static int currently_stepping (struct thread_info *tp) @@ -6065,13 +7557,13 @@ insert_exception_resume_breakpoint (struct thread_info *tp, { TRY { - struct symbol *vsym; + struct block_symbol vsym; struct value *value; CORE_ADDR handler; struct breakpoint *bp; vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN, NULL); - value = read_var_value (vsym, frame); + value = read_var_value (vsym.symbol, vsym.block, frame); /* If the value was optimized out, revert to the old behavior. */ if (! value_optimized_out (value)) { @@ -6088,7 +7580,7 @@ insert_exception_resume_breakpoint (struct thread_info *tp, /* set_momentary_breakpoint_at_pc invalidates FRAME. */ frame = NULL; - bp->thread = tp->num; + bp->thread = tp->global_num; inferior_thread ()->control.exception_resume_breakpoint = bp; } } @@ -6125,7 +7617,7 @@ insert_exception_resume_from_probe (struct thread_info *tp, bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame), handler, bp_exception_resume); - bp->thread = tp->num; + bp->thread = tp->global_num; inferior_thread ()->control.exception_resume_breakpoint = bp; } @@ -6208,26 +7700,40 @@ stop_waiting (struct execution_control_state *ecs) /* Let callers know we don't want to wait for the inferior anymore. */ ecs->wait_some_more = 0; + + /* If all-stop, but the target is always in non-stop mode, stop all + threads now that we're presenting the stop to the user. */ + if (!non_stop && target_is_non_stop_p ()) + stop_all_threads (); } -/* Called when we should continue running the inferior, because the - current event doesn't cause a user visible stop. This does the - resuming part; waiting for the next event is done elsewhere. */ +/* Like keep_going, but passes the signal to the inferior, even if the + signal is set to nopass. */ static void -keep_going (struct execution_control_state *ecs) +keep_going_pass_signal (struct execution_control_state *ecs) { /* Make sure normal_stop is called if we get a QUIT handled before reaching resume. */ struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0); + gdb_assert (ptid_equal (ecs->event_thread->ptid, inferior_ptid)); + gdb_assert (!ecs->event_thread->resumed); + /* Save the pc before execution, to compare with pc after stop. */ ecs->event_thread->prev_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); - if (ecs->event_thread->control.trap_expected - && ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_TRAP) + if (ecs->event_thread->control.trap_expected) { + struct thread_info *tp = ecs->event_thread; + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: %s has trap_expected set, " + "resuming to collect trap\n", + target_pid_to_str (tp->ptid)); + /* We haven't yet gotten our trap, and either: intercepted a non-signal event (e.g., a fork); or took a signal which we are supposed to pass through to the inferior. Simply @@ -6235,11 +7741,40 @@ keep_going (struct execution_control_state *ecs) discard_cleanups (old_cleanups); resume (ecs->event_thread->suspend.stop_signal); } + else if (step_over_info_valid_p ()) + { + /* Another thread is stepping over a breakpoint in-line. If + this thread needs a step-over too, queue the request. In + either case, this resume must be deferred for later. */ + struct thread_info *tp = ecs->event_thread; + + if (ecs->hit_singlestep_breakpoint + || thread_still_needs_step_over (tp)) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: step-over already in progress: " + "step-over for %s deferred\n", + target_pid_to_str (tp->ptid)); + thread_step_over_chain_enqueue (tp); + } + else + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: step-over in progress: " + "resume of %s deferred\n", + target_pid_to_str (tp->ptid)); + } + + discard_cleanups (old_cleanups); + } else { struct regcache *regcache = get_current_regcache (); int remove_bp; int remove_wps; + step_over_what step_what; /* Either the trap was not expected, but we are continuing anyway (if we got a signal, the user asked it be passed to @@ -6260,25 +7795,32 @@ keep_going (struct execution_control_state *ecs) instruction, and then re-insert the breakpoint when that step is finished. */ + step_what = thread_still_needs_step_over (ecs->event_thread); + remove_bp = (ecs->hit_singlestep_breakpoint - || thread_still_needs_step_over (ecs->event_thread)); - remove_wps = (ecs->event_thread->stepping_over_watchpoint - && !target_have_steppable_watchpoint); + || (step_what & STEP_OVER_BREAKPOINT)); + remove_wps = (step_what & STEP_OVER_WATCHPOINT); /* We can't use displaced stepping if we need to step past a watchpoint. The instruction copied to the scratch pad would still trigger the watchpoint. */ if (remove_bp - && (remove_wps - || !use_displaced_stepping (get_regcache_arch (regcache)))) + && (remove_wps || !use_displaced_stepping (ecs->event_thread))) { set_step_over_info (get_regcache_aspace (regcache), - regcache_read_pc (regcache), remove_wps); + regcache_read_pc (regcache), remove_wps, + ecs->event_thread->global_num); } else if (remove_wps) - set_step_over_info (NULL, 0, remove_wps); - else - clear_step_over_info (); + set_step_over_info (NULL, 0, remove_wps, -1); + + /* If we now need to do an in-line step-over, we need to stop + all other threads. Note this must be done before + insert_breakpoints below, because that removes the breakpoint + we're about to step over, otherwise other threads could miss + it. */ + if (step_over_info_valid_p () && target_is_non_stop_p ()) + stop_all_threads (); /* Stop stepping if inserting breakpoints fails. */ TRY @@ -6296,20 +7838,6 @@ keep_going (struct execution_control_state *ecs) ecs->event_thread->control.trap_expected = (remove_bp || remove_wps); - /* Do not deliver GDB_SIGNAL_TRAP (except when the user - explicitly specifies that such a signal should be delivered - to the target program). Typically, that would occur when a - user is debugging a target monitor on a simulator: the target - monitor sets a breakpoint; the simulator encounters this - breakpoint and halts the simulation handing control to GDB; - GDB, noting that the stop address doesn't map to any known - breakpoint, returns control back to the simulator; the - simulator then delivers the hardware equivalent of a - GDB_SIGNAL_TRAP to the program being debugged. */ - if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP - && !signal_program[ecs->event_thread->suspend.stop_signal]) - ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0; - discard_cleanups (old_cleanups); resume (ecs->event_thread->suspend.stop_signal); } @@ -6317,6 +7845,22 @@ keep_going (struct execution_control_state *ecs) prepare_to_wait (ecs); } +/* Called when we should continue running the inferior, because the + current event doesn't cause a user visible stop. This does the + resuming part; waiting for the next event is done elsewhere. */ + +static void +keep_going (struct execution_control_state *ecs) +{ + if (ecs->event_thread->control.trap_expected + && ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP) + ecs->event_thread->control.trap_expected = 0; + + if (!signal_program[ecs->event_thread->suspend.stop_signal]) + ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0; + keep_going_pass_signal (ecs); +} + /* This function normally comes after a resume, before handle_inferior_event exits. It takes care of any last bits of housekeeping, and sets the all-important wait_some_more flag. */ @@ -6327,10 +7871,10 @@ prepare_to_wait (struct execution_control_state *ecs) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: prepare_to_wait\n"); - /* This is the old end of the while loop. Let everybody know we - want to wait for the inferior some more and get called again - soon. */ ecs->wait_some_more = 1; + + if (!target_is_async_p ()) + mark_infrun_async_event_handler (); } /* We are done with the step range of a step/next/si/ni command. @@ -6420,24 +7964,52 @@ print_exited_reason (struct ui_out *uiout, int exitstatus) } } +/* Some targets/architectures can do extra processing/display of + segmentation faults. E.g., Intel MPX boundary faults. + Call the architecture dependent function to handle the fault. */ + +static void +handle_segmentation_fault (struct ui_out *uiout) +{ + struct regcache *regcache = get_current_regcache (); + struct gdbarch *gdbarch = get_regcache_arch (regcache); + + if (gdbarch_handle_segmentation_fault_p (gdbarch)) + gdbarch_handle_segmentation_fault (gdbarch, uiout); +} + void print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal) { + struct thread_info *thr = inferior_thread (); + annotate_signal (); - if (siggnal == GDB_SIGNAL_0 && !ui_out_is_mi_like_p (uiout)) + if (ui_out_is_mi_like_p (uiout)) + ; + else if (show_thread_that_caused_stop ()) { - struct thread_info *t = inferior_thread (); + const char *name; + + ui_out_text (uiout, "\nThread "); + ui_out_field_fmt (uiout, "thread-id", "%s", print_thread_id (thr)); - ui_out_text (uiout, "\n["); - ui_out_field_string (uiout, "thread-name", - target_pid_to_str (t->ptid)); - ui_out_field_fmt (uiout, "thread-id", "] #%d", t->num); - ui_out_text (uiout, " stopped"); + name = thr->name != NULL ? thr->name : target_thread_name (thr); + if (name != NULL) + { + ui_out_text (uiout, " \""); + ui_out_field_fmt (uiout, "name", "%s", name); + ui_out_text (uiout, "\""); + } } + else + ui_out_text (uiout, "\nProgram"); + + if (siggnal == GDB_SIGNAL_0 && !ui_out_is_mi_like_p (uiout)) + ui_out_text (uiout, " stopped"); else { - ui_out_text (uiout, "\nProgram received signal "); + ui_out_text (uiout, " received signal "); annotate_signal_name (); if (ui_out_is_mi_like_p (uiout)) ui_out_field_string @@ -6449,6 +8021,10 @@ print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal) annotate_signal_string (); ui_out_field_string (uiout, "signal-meaning", gdb_signal_to_string (siggnal)); + + if (siggnal == GDB_SIGNAL_SEGV) + handle_segmentation_fault (uiout); + annotate_signal_string_end (); } ui_out_text (uiout, ".\n"); @@ -6465,11 +8041,11 @@ print_no_history_reason (struct ui_out *uiout) bpstat_print contains the logic deciding in detail what to print, based on the event(s) that just occurred. */ -void -print_stop_event (struct target_waitstatus *ws) +static void +print_stop_location (struct target_waitstatus *ws) { int bpstat_ret; - int source_flag; + enum print_what source_flag; int do_frame_printing = 1; struct thread_info *tp = inferior_thread (); @@ -6517,37 +8093,179 @@ print_stop_event (struct target_waitstatus *ws) SRC_AND_LOC: Print location and source line. */ if (do_frame_printing) print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1); +} + +/* Cleanup that restores a previous current uiout. */ + +static void +restore_current_uiout_cleanup (void *arg) +{ + struct ui_out *saved_uiout = (struct ui_out *) arg; + + current_uiout = saved_uiout; +} + +/* See infrun.h. */ + +void +print_stop_event (struct ui_out *uiout) +{ + struct cleanup *old_chain; + struct target_waitstatus last; + ptid_t last_ptid; + struct thread_info *tp; + + get_last_target_status (&last_ptid, &last); + + old_chain = make_cleanup (restore_current_uiout_cleanup, current_uiout); + current_uiout = uiout; + + print_stop_location (&last); /* Display the auto-display expressions. */ do_displays (); -} -/* Here to return control to GDB when the inferior stops for real. - Print appropriate messages, remove breakpoints, give terminal our modes. + do_cleanups (old_chain); + + tp = inferior_thread (); + if (tp->thread_fsm != NULL + && thread_fsm_finished_p (tp->thread_fsm)) + { + struct return_value_info *rv; + + rv = thread_fsm_return_value (tp->thread_fsm); + if (rv != NULL) + print_return_value (uiout, rv); + } +} - STOP_PRINT_FRAME nonzero means print the executing frame - (pc, function, args, file, line number and line text). - BREAKPOINTS_FAILED nonzero means stop was due to error - attempting to insert breakpoints. */ +/* See infrun.h. */ void +maybe_remove_breakpoints (void) +{ + if (!breakpoints_should_be_inserted_now () && target_has_execution) + { + if (remove_breakpoints ()) + { + target_terminal_ours_for_output (); + printf_filtered (_("Cannot remove breakpoints because " + "program is no longer writable.\nFurther " + "execution is probably impossible.\n")); + } + } +} + +/* The execution context that just caused a normal stop. */ + +struct stop_context +{ + /* The stop ID. */ + ULONGEST stop_id; + + /* The event PTID. */ + + ptid_t ptid; + + /* If stopp for a thread event, this is the thread that caused the + stop. */ + struct thread_info *thread; + + /* The inferior that caused the stop. */ + int inf_num; +}; + +/* Returns a new stop context. If stopped for a thread event, this + takes a strong reference to the thread. */ + +static struct stop_context * +save_stop_context (void) +{ + struct stop_context *sc = XNEW (struct stop_context); + + sc->stop_id = get_stop_id (); + sc->ptid = inferior_ptid; + sc->inf_num = current_inferior ()->num; + + if (!ptid_equal (inferior_ptid, null_ptid)) + { + /* Take a strong reference so that the thread can't be deleted + yet. */ + sc->thread = inferior_thread (); + sc->thread->refcount++; + } + else + sc->thread = NULL; + + return sc; +} + +/* Release a stop context previously created with save_stop_context. + Releases the strong reference to the thread as well. */ + +static void +release_stop_context_cleanup (void *arg) +{ + struct stop_context *sc = (struct stop_context *) arg; + + if (sc->thread != NULL) + sc->thread->refcount--; + xfree (sc); +} + +/* Return true if the current context no longer matches the saved stop + context. */ + +static int +stop_context_changed (struct stop_context *prev) +{ + if (!ptid_equal (prev->ptid, inferior_ptid)) + return 1; + if (prev->inf_num != current_inferior ()->num) + return 1; + if (prev->thread != NULL && prev->thread->state != THREAD_STOPPED) + return 1; + if (get_stop_id () != prev->stop_id) + return 1; + return 0; +} + +/* See infrun.h. */ + +int normal_stop (void) { struct target_waitstatus last; ptid_t last_ptid; struct cleanup *old_chain = make_cleanup (null_cleanup, NULL); + ptid_t pid_ptid; + struct switch_thru_all_uis state; get_last_target_status (&last_ptid, &last); + new_stop_id (); + /* If an exception is thrown from this point on, make sure to propagate GDB's knowledge of the executing state to the frontend/user running state. A QUIT is an easy exception to see here, so do this before any filtered output. */ if (!non_stop) make_cleanup (finish_thread_state_cleanup, &minus_one_ptid); - else if (last.kind != TARGET_WAITKIND_SIGNALLED - && last.kind != TARGET_WAITKIND_EXITED - && last.kind != TARGET_WAITKIND_NO_RESUMED) + else if (last.kind == TARGET_WAITKIND_SIGNALLED + || last.kind == TARGET_WAITKIND_EXITED) + { + /* On some targets, we may still have live threads in the + inferior when we get a process exit event. E.g., for + "checkpoint", when the current checkpoint/fork exits, + linux-fork.c automatically switches to another fork from + within target_mourn_inferior. */ + if (!ptid_equal (inferior_ptid, null_ptid)) + { + pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid)); + make_cleanup (finish_thread_state_cleanup, &pid_ptid); + } + } + else if (last.kind != TARGET_WAITKIND_NO_RESUMED) make_cleanup (finish_thread_state_cleanup, &inferior_ptid); /* As we're presenting a stop, and potentially removing breakpoints, @@ -6586,32 +8304,28 @@ normal_stop (void) && last.kind != TARGET_WAITKIND_EXITED && last.kind != TARGET_WAITKIND_NO_RESUMED) { - target_terminal_ours_for_output (); - printf_filtered (_("[Switching to %s]\n"), - target_pid_to_str (inferior_ptid)); - annotate_thread_changed (); + SWITCH_THRU_ALL_UIS (state) + { + target_terminal_ours_for_output (); + printf_filtered (_("[Switching to %s]\n"), + target_pid_to_str (inferior_ptid)); + annotate_thread_changed (); + } previous_inferior_ptid = inferior_ptid; } if (last.kind == TARGET_WAITKIND_NO_RESUMED) { - gdb_assert (sync_execution || !target_can_async_p ()); - - target_terminal_ours_for_output (); - printf_filtered (_("No unwaited-for children left.\n")); + SWITCH_THRU_ALL_UIS (state) + if (current_ui->prompt_state == PROMPT_BLOCKED) + { + target_terminal_ours_for_output (); + printf_filtered (_("No unwaited-for children left.\n")); + } } /* Note: this depends on the update_thread_list call above. */ - if (!breakpoints_should_be_inserted_now () && target_has_execution) - { - if (remove_breakpoints ()) - { - target_terminal_ours_for_output (); - printf_filtered (_("Cannot remove breakpoints because " - "program is no longer writable.\nFurther " - "execution is probably impossible.\n")); - } - } + maybe_remove_breakpoints (); /* If an auto-display called a function and that got a signal, delete that auto-display to avoid an infinite recursion. */ @@ -6619,123 +8333,75 @@ normal_stop (void) if (stopped_by_random_signal) disable_current_display (); - /* Notify observers if we finished a "step"-like command, etc. */ - if (target_has_execution - && last.kind != TARGET_WAITKIND_SIGNALLED - && last.kind != TARGET_WAITKIND_EXITED - && inferior_thread ()->control.stop_step) - { - /* But not if in the middle of doing a "step n" operation for - n > 1 */ - if (inferior_thread ()->step_multi) - goto done; - - observer_notify_end_stepping_range (); - } - - target_terminal_ours (); - async_enable_stdin (); - - /* Set the current source location. This will also happen if we - display the frame below, but the current SAL will be incorrect - during a user hook-stop function. */ - if (has_stack_frames () && !stop_stack_dummy) - set_current_sal_from_frame (get_current_frame ()); - - /* Let the user/frontend see the threads as stopped, but do nothing - if the thread was running an infcall. We may be e.g., evaluating - a breakpoint condition. In that case, the thread had state - THREAD_RUNNING before the infcall, and shall remain set to - running, all without informing the user/frontend about state - transition changes. If this is actually a call command, then the - thread was originally already stopped, so there's no state to - finish either. */ - if (target_has_execution && inferior_thread ()->control.in_infcall) - discard_cleanups (old_chain); - else - do_cleanups (old_chain); - - /* Look up the hook_stop and run it (CLI internally handles problem - of stop_command's pre-hook not existing). */ - if (stop_command) - catch_errors (hook_stop_stub, stop_command, - "Error while running hook_stop:\n", RETURN_MASK_ALL); - - if (!has_stack_frames ()) - goto done; + SWITCH_THRU_ALL_UIS (state) + { + async_enable_stdin (); + } - if (last.kind == TARGET_WAITKIND_SIGNALLED - || last.kind == TARGET_WAITKIND_EXITED) - goto done; + /* Let the user/frontend see the threads as stopped. */ + do_cleanups (old_chain); /* Select innermost stack frame - i.e., current frame is frame 0, - and current location is based on that. - Don't do this on return from a stack dummy routine, - or if the program has exited. */ + and current location is based on that. Handle the case where the + dummy call is returning after being stopped. E.g. the dummy call + previously hit a breakpoint. (If the dummy call returns + normally, we won't reach here.) Do this before the stop hook is + run, so that it doesn't get to see the temporary dummy frame, + which is not where we'll present the stop. */ + if (has_stack_frames ()) + { + if (stop_stack_dummy == STOP_STACK_DUMMY) + { + /* Pop the empty frame that contains the stack dummy. This + also restores inferior state prior to the call (struct + infcall_suspend_state). */ + struct frame_info *frame = get_current_frame (); + + gdb_assert (get_frame_type (frame) == DUMMY_FRAME); + frame_pop (frame); + /* frame_pop calls reinit_frame_cache as the last thing it + does which means there's now no selected frame. */ + } - if (!stop_stack_dummy) - { select_frame (get_current_frame ()); - /* If --batch-silent is enabled then there's no need to print the current - source location, and to try risks causing an error message about - missing source files. */ - if (stop_print_frame && !batch_silent) - print_stop_event (&last); - } - - if (stop_stack_dummy == STOP_STACK_DUMMY) - { - /* Pop the empty frame that contains the stack dummy. - This also restores inferior state prior to the call - (struct infcall_suspend_state). */ - struct frame_info *frame = get_current_frame (); - - gdb_assert (get_frame_type (frame) == DUMMY_FRAME); - frame_pop (frame); - /* frame_pop() calls reinit_frame_cache as the last thing it - does which means there's currently no selected frame. We - don't need to re-establish a selected frame if the dummy call - returns normally, that will be done by - restore_infcall_control_state. However, we do have to handle - the case where the dummy call is returning after being - stopped (e.g. the dummy call previously hit a breakpoint). - We can't know which case we have so just always re-establish - a selected frame here. */ - select_frame (get_current_frame ()); + /* Set the current source location. */ + set_current_sal_from_frame (get_current_frame ()); } -done: - annotate_stopped (); - - /* Suppress the stop observer if we're in the middle of: + /* Look up the hook_stop and run it (CLI internally handles problem + of stop_command's pre-hook not existing). */ + if (stop_command != NULL) + { + struct stop_context *saved_context = save_stop_context (); + struct cleanup *old_chain + = make_cleanup (release_stop_context_cleanup, saved_context); - - a step n (n > 1), as there still more steps to be done. + catch_errors (hook_stop_stub, stop_command, + "Error while running hook_stop:\n", RETURN_MASK_ALL); - - a "finish" command, as the observer will be called in - finish_command_continuation, so it can include the inferior - function's return value. + /* If the stop hook resumes the target, then there's no point in + trying to notify about the previous stop; its context is + gone. Likewise if the command switches thread or inferior -- + the observers would print a stop for the wrong + thread/inferior. */ + if (stop_context_changed (saved_context)) + { + do_cleanups (old_chain); + return 1; + } + do_cleanups (old_chain); + } - - calling an inferior function, as we pretend we inferior didn't - run at all. The return value of the call is handled by the - expression evaluator, through call_function_by_hand. */ + /* Notify observers about the stop. This is where the interpreters + print the stop event. */ + if (!ptid_equal (inferior_ptid, null_ptid)) + observer_notify_normal_stop (inferior_thread ()->control.stop_bpstat, + stop_print_frame); + else + observer_notify_normal_stop (NULL, stop_print_frame); - if (!target_has_execution - || last.kind == TARGET_WAITKIND_SIGNALLED - || last.kind == TARGET_WAITKIND_EXITED - || last.kind == TARGET_WAITKIND_NO_RESUMED - || (!(inferior_thread ()->step_multi - && inferior_thread ()->control.stop_step) - && !(inferior_thread ()->control.stop_bpstat - && inferior_thread ()->control.proceed_to_finish) - && !inferior_thread ()->control.in_infcall)) - { - if (!ptid_equal (inferior_ptid, null_ptid)) - observer_notify_normal_stop (inferior_thread ()->control.stop_bpstat, - stop_print_frame); - else - observer_notify_normal_stop (NULL, stop_print_frame); - } + annotate_stopped (); if (target_has_execution) { @@ -6750,6 +8416,8 @@ done: longer needed. Keeping those around slows down things linearly. Note that this never removes the current inferior. */ prune_inferiors (); + + return 0; } static int @@ -7036,7 +8704,7 @@ Are you sure you want to change it? "), sig_print_header (); for (; signum < nsigs; signum++) if (sigs[signum]) - sig_print_info (signum); + sig_print_info ((enum gdb_signal) signum); } break; @@ -7127,25 +8795,6 @@ signals_info (char *signum_exp, int from_tty) "to change these tables.\n")); } -/* Check if it makes sense to read $_siginfo from the current thread - at this point. If not, throw an error. */ - -static void -validate_siginfo_access (void) -{ - /* No current inferior, no siginfo. */ - if (ptid_equal (inferior_ptid, null_ptid)) - error (_("No thread selected.")); - - /* Don't try to read from a dead thread. */ - if (is_exited (inferior_ptid)) - error (_("The current thread has terminated")); - - /* ... or from a spinning thread. */ - if (is_running (inferior_ptid)) - error (_("Selected thread is running.")); -} - /* The $_siginfo convenience variable is a bit special. We don't know for sure the type of the value until we actually have a chance to fetch the data. The type can change depending on gdbarch, so it is @@ -7164,7 +8813,9 @@ siginfo_value_read (struct value *v) { LONGEST transferred; - validate_siginfo_access (); + /* If we can access registers, so can we access $_siginfo. Likewise + vice versa. */ + validate_registers_access (); transferred = target_read (¤t_target, TARGET_OBJECT_SIGNAL_INFO, @@ -7185,7 +8836,9 @@ siginfo_value_write (struct value *v, struct value *fromval) { LONGEST transferred; - validate_siginfo_access (); + /* If we can access registers, so can we access $_siginfo. Likewise + vice versa. */ + validate_registers_access (); transferred = target_write (¤t_target, TARGET_OBJECT_SIGNAL_INFO, @@ -7234,9 +8887,6 @@ siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var, struct infcall_suspend_state { struct thread_suspend_state thread_suspend; -#if 0 /* Currently unused and empty structures are not valid C. */ - struct inferior_suspend_state inferior_suspend; -#endif /* Other fields: */ CORE_ADDR stop_pc; @@ -7256,9 +8906,6 @@ save_infcall_suspend_state (void) { struct infcall_suspend_state *inf_state; struct thread_info *tp = inferior_thread (); -#if 0 - struct inferior *inf = current_inferior (); -#endif struct regcache *regcache = get_current_regcache (); struct gdbarch *gdbarch = get_regcache_arch (regcache); gdb_byte *siginfo_data = NULL; @@ -7269,7 +8916,7 @@ save_infcall_suspend_state (void) size_t len = TYPE_LENGTH (type); struct cleanup *back_to; - siginfo_data = xmalloc (len); + siginfo_data = (gdb_byte *) xmalloc (len); back_to = make_cleanup (xfree, siginfo_data); if (target_read (¤t_target, TARGET_OBJECT_SIGNAL_INFO, NULL, @@ -7292,9 +8939,6 @@ save_infcall_suspend_state (void) } inf_state->thread_suspend = tp->suspend; -#if 0 /* Currently unused and empty structures are not valid C. */ - inf_state->inferior_suspend = inf->suspend; -#endif /* run_inferior_call will not use the signal due to its `proceed' call with GDB_SIGNAL_0 anyway. */ @@ -7313,16 +8957,10 @@ void restore_infcall_suspend_state (struct infcall_suspend_state *inf_state) { struct thread_info *tp = inferior_thread (); -#if 0 - struct inferior *inf = current_inferior (); -#endif struct regcache *regcache = get_current_regcache (); struct gdbarch *gdbarch = get_regcache_arch (regcache); tp->suspend = inf_state->thread_suspend; -#if 0 /* Currently unused and empty structures are not valid C. */ - inf->suspend = inf_state->inferior_suspend; -#endif stop_pc = inf_state->stop_pc; @@ -7347,7 +8985,7 @@ restore_infcall_suspend_state (struct infcall_suspend_state *inf_state) static void do_restore_infcall_suspend_state_cleanup (void *state) { - restore_infcall_suspend_state (state); + restore_infcall_suspend_state ((struct infcall_suspend_state *) state); } struct cleanup * @@ -7383,7 +9021,6 @@ struct infcall_control_state /* Other fields: */ enum stop_stack_kind stop_stack_dummy; int stopped_by_random_signal; - int stop_after_trap; /* ID if the selected frame when the inferior function call was made. */ struct frame_id selected_frame_id; @@ -7395,7 +9032,8 @@ struct infcall_control_state struct infcall_control_state * save_infcall_control_state (void) { - struct infcall_control_state *inf_status = xmalloc (sizeof (*inf_status)); + struct infcall_control_state *inf_status = + XNEW (struct infcall_control_state); struct thread_info *tp = inferior_thread (); struct inferior *inf = current_inferior (); @@ -7414,7 +9052,6 @@ save_infcall_control_state (void) /* Other fields: */ inf_status->stop_stack_dummy = stop_stack_dummy; inf_status->stopped_by_random_signal = stopped_by_random_signal; - inf_status->stop_after_trap = stop_after_trap; inf_status->selected_frame_id = get_frame_id (get_selected_frame (NULL)); @@ -7466,7 +9103,6 @@ restore_infcall_control_state (struct infcall_control_state *inf_status) /* Other fields: */ stop_stack_dummy = inf_status->stop_stack_dummy; stopped_by_random_signal = inf_status->stopped_by_random_signal; - stop_after_trap = inf_status->stop_after_trap; if (target_has_stack) { @@ -7488,7 +9124,7 @@ restore_infcall_control_state (struct infcall_control_state *inf_status) static void do_restore_infcall_control_state_cleanup (void *sts) { - restore_infcall_control_state (sts); + restore_infcall_control_state ((struct infcall_control_state *) sts); } struct cleanup * @@ -7522,7 +9158,7 @@ discard_infcall_control_state (struct infcall_control_state *inf_status) static void restore_inferior_ptid (void *arg) { - ptid_t *saved_ptid_ptr = arg; + ptid_t *saved_ptid_ptr = (ptid_t *) arg; inferior_ptid = *saved_ptid_ptr; xfree (arg); @@ -7535,9 +9171,8 @@ restore_inferior_ptid (void *arg) struct cleanup * save_inferior_ptid (void) { - ptid_t *saved_ptid_ptr; + ptid_t *saved_ptid_ptr = XNEW (ptid_t); - saved_ptid_ptr = xmalloc (sizeof (ptid_t)); *saved_ptid_ptr = inferior_ptid; return make_cleanup (restore_inferior_ptid, saved_ptid_ptr); } @@ -7556,7 +9191,7 @@ clear_exit_convenience_vars (void) Set exec-direction / show exec-direction commands (returns error unless target implements to_set_exec_direction method). */ -int execution_direction = EXEC_FORWARD; +enum exec_direction_kind execution_direction = EXEC_FORWARD; static const char exec_forward[] = "forward"; static const char exec_reverse[] = "reverse"; static const char *exec_direction = exec_forward; @@ -7619,6 +9254,15 @@ static const struct internalvar_funcs siginfo_funcs = NULL }; +/* Callback for infrun's target events source. This is marked when a + thread has a pending status to process. */ + +static void +infrun_async_inferior_event_handler (gdb_client_data data) +{ + inferior_event_handler (INF_REG_EVENT, NULL); +} + void _initialize_infrun (void) { @@ -7626,6 +9270,10 @@ _initialize_infrun (void) int numsigs; struct cmd_list_element *c; + /* Register extra event sources in the event loop. */ + infrun_async_inferior_event_token + = create_async_event_handler (infrun_async_inferior_event_handler, NULL); + add_info ("signals", signals_info, _("\ What debugger does when program gets various signals.\n\ Specify a signal as argument to print info on that signal only.")); @@ -7702,15 +9350,11 @@ leave it stopped or free to run as needed."), &showlist); numsigs = (int) GDB_SIGNAL_LAST; - signal_stop = (unsigned char *) xmalloc (sizeof (signal_stop[0]) * numsigs); - signal_print = (unsigned char *) - xmalloc (sizeof (signal_print[0]) * numsigs); - signal_program = (unsigned char *) - xmalloc (sizeof (signal_program[0]) * numsigs); - signal_catch = (unsigned char *) - xmalloc (sizeof (signal_catch[0]) * numsigs); - signal_pass = (unsigned char *) - xmalloc (sizeof (signal_pass[0]) * numsigs); + signal_stop = XNEWVEC (unsigned char, numsigs); + signal_print = XNEWVEC (unsigned char, numsigs); + signal_program = XNEWVEC (unsigned char, numsigs); + signal_catch = XNEWVEC (unsigned char, numsigs); + signal_pass = XNEWVEC (unsigned char, numsigs); for (i = 0; i < numsigs; i++) { signal_stop[i] = 1; @@ -7719,8 +9363,19 @@ leave it stopped or free to run as needed."), signal_catch[i] = 0; } - /* Signals caused by debugger's own actions - should not be given to the program afterwards. */ + /* Signals caused by debugger's own actions should not be given to + the program afterwards. + + Do not deliver GDB_SIGNAL_TRAP by default, except when the user + explicitly specifies that it should be delivered to the target + program. Typically, that would occur when a user is debugging a + target monitor on a simulator: the target monitor sets a + breakpoint; the simulator encounters this breakpoint and halts + the simulation handing control to GDB; GDB, noting that the stop + address doesn't map to any known breakpoint, returns control back + to the simulator; the simulator then delivers the hardware + equivalent of a GDB_SIGNAL_TRAP to the program being + debugged. */ signal_program[GDB_SIGNAL_TRAP] = 0; signal_program[GDB_SIGNAL_INT] = 0; @@ -7811,10 +9466,13 @@ By default, the debugger will use the same inferior."), scheduler_enums, &scheduler_mode, _("\ Set mode for locking scheduler during execution."), _("\ Show mode for locking scheduler during execution."), _("\ -off == no locking (threads may preempt at any time)\n\ -on == full locking (no thread except the current thread may run)\n\ -step == scheduler locked during stepping commands (step, next, stepi, nexti).\n\ - In this mode, other threads may run during other commands."), +off == no locking (threads may preempt at any time)\n\ +on == full locking (no thread except the current thread may run)\n\ + This applies to both normal execution and replay mode.\n\ +step == scheduler locked during stepping commands (step, next, stepi, nexti).\n\ + In this mode, other threads may run during other commands.\n\ + This applies to both normal execution and replay mode.\n\ +replay == scheduler locked in replay mode and unlocked during normal execution."), set_schedlock_func, /* traps on target vector */ show_scheduler_mode, &setlist, &showlist);