X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Finfrun.c;h=7870f703e6c76041d0c831b28545f3a5536e1513;hb=8550d3b32f4ac17bdb9e4768bb905da181b77ded;hp=51540b33425b276ac880abfe0849f17d53bd7aa7;hpb=ecd75fc8eed3bde86036141228074a20e55dcfc9;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/infrun.c b/gdb/infrun.c index 51540b3342..7870f703e6 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-2014 Free Software Foundation, Inc. + Copyright (C) 1986-2015 Free Software Foundation, Inc. This file is part of GDB. @@ -19,12 +19,11 @@ along with this program. If not, see . */ #include "defs.h" -#include +#include "infrun.h" #include #include "symtab.h" #include "frame.h" #include "inferior.h" -#include "exceptions.h" #include "breakpoint.h" #include "gdb_wait.h" #include "gdbcore.h" @@ -45,7 +44,6 @@ #include "main.h" #include "dictionary.h" #include "block.h" -#include "gdb_assert.h" #include "mi/mi-common.h" #include "event-top.h" #include "record.h" @@ -61,6 +59,7 @@ #include "completer.h" #include "target-descriptions.h" #include "target-dcache.h" +#include "terminal.h" /* Prototypes for local functions */ @@ -80,28 +79,15 @@ static int restore_selected_frame (void *); static int follow_fork (void); +static int follow_fork_inferior (int follow_child, int detach_fork); + +static void follow_inferior_reset_breakpoints (void); + static void set_schedlock_func (char *args, int from_tty, struct cmd_list_element *c); static int currently_stepping (struct thread_info *tp); -static int currently_stepping_or_nexting_callback (struct thread_info *tp, - void *data); - -static void xdb_handle_command (char *args, int from_tty); - -static int prepare_to_proceed (int); - -static void print_exited_reason (int exitstatus); - -static void print_signal_exited_reason (enum gdb_signal siggnal); - -static void print_no_history_reason (void); - -static void print_signal_received_reason (enum gdb_signal siggnal); - -static void print_end_stepping_range_reason (void); - void _initialize_infrun (void); void nullify_last_target_wait_ptid (void); @@ -112,6 +98,8 @@ static void insert_step_resume_breakpoint_at_caller (struct frame_info *); static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR); +static int maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc); + /* 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. */ @@ -127,9 +115,9 @@ show_step_stop_if_no_debug (struct ui_file *file, int from_tty, int sync_execution = 0; -/* wait_for_inferior and normal_stop use this to notify the user - when the inferior stopped in a different thread than it had been - running in. */ +/* proceed and normal_stop use this to notify the user when the + inferior stopped in a different thread than it had been running + in. */ static ptid_t previous_inferior_ptid; @@ -247,7 +235,6 @@ set_observer_mode (char *args, int from_tty, going out we leave it that way. */ if (observer_mode) { - target_async_permitted = 1; pagination_enabled = 0; non_stop = non_stop_1 = 1; } @@ -339,10 +326,6 @@ update_signals_program_target (void) static struct cmd_list_element *stop_command; -/* Function inferior was in as of last step command. */ - -static struct symbol *step_start_function; - /* Nonzero if we want to give control to the user when we're notified of shared library events by the dynamic linker. */ int stop_on_solib_events; @@ -390,8 +373,6 @@ static void context_switch (ptid_t ptid); void init_thread_stepping_state (struct thread_info *tss); -static void init_infwait_state (void); - static const char follow_fork_mode_child[] = "child"; static const char follow_fork_mode_parent[] = "parent"; @@ -413,6 +394,244 @@ show_follow_fork_mode_string (struct ui_file *file, int from_tty, } +/* Handle changes to the inferior list based on the type of fork, + which process is being followed, and whether the other process + should be detached. On entry inferior_ptid must be the ptid of + the fork parent. At return inferior_ptid is the ptid of the + followed inferior. */ + +static int +follow_fork_inferior (int follow_child, int detach_fork) +{ + int has_vforked; + ptid_t parent_ptid, child_ptid; + + has_vforked = (inferior_thread ()->pending_follow.kind + == TARGET_WAITKIND_VFORKED); + parent_ptid = inferior_ptid; + child_ptid = inferior_thread ()->pending_follow.value.related_pid; + + if (has_vforked + && !non_stop /* Non-stop always resumes both branches. */ + && (!target_is_async_p () || sync_execution) + && !(follow_child || detach_fork || sched_multi)) + { + /* The parent stays blocked inside the vfork syscall until the + child execs or exits. If we don't let the child run, then + the parent stays blocked. If we're telling the parent to run + in the foreground, the user will not be able to ctrl-c to get + back the terminal, effectively hanging the debug session. */ + fprintf_filtered (gdb_stderr, _("\ +Can not resume the parent process over vfork in the foreground while\n\ +holding the child stopped. Try \"set detach-on-fork\" or \ +\"set schedule-multiple\".\n")); + /* FIXME output string > 80 columns. */ + return 1; + } + + if (!follow_child) + { + /* 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 + breakpoint inserted in the parent is visible in the + child, even those added while stopped in a vfork + catchpoint. This will remove the breakpoints from the + parent also, but they'll be reinserted below. */ + if (has_vforked) + { + /* Keep breakpoints list in sync. */ + remove_breakpoints_pid (ptid_get_pid (inferior_ptid)); + } + + if (info_verbose || debug_infrun) + { + 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)); + } + } + else + { + struct inferior *parent_inf, *child_inf; + struct cleanup *old_chain; + + /* Add process to GDB's tables. */ + child_inf = add_inferior (ptid_get_pid (child_ptid)); + + parent_inf = current_inferior (); + child_inf->attach_flag = parent_inf->attach_flag; + copy_terminal_info (child_inf, parent_inf); + child_inf->gdbarch = parent_inf->gdbarch; + copy_inferior_target_desc_info (child_inf, parent_inf); + + old_chain = save_inferior_ptid (); + save_current_program_space (); + + inferior_ptid = child_ptid; + add_thread (inferior_ptid); + child_inf->symfile_flags = SYMFILE_NO_READ; + + /* If this is a vfork child, then the address-space is + shared with the parent. */ + if (has_vforked) + { + child_inf->pspace = parent_inf->pspace; + child_inf->aspace = parent_inf->aspace; + + /* The parent will be frozen until the child is done + with the shared region. Keep track of the + parent. */ + child_inf->vfork_parent = parent_inf; + child_inf->pending_detach = 0; + parent_inf->vfork_child = child_inf; + parent_inf->pending_detach = 0; + } + else + { + child_inf->aspace = new_address_space (); + child_inf->pspace = add_program_space (child_inf->aspace); + child_inf->removable = 1; + set_current_program_space (child_inf->pspace); + clone_program_space (child_inf->pspace, parent_inf->pspace); + + /* Let the shared library layer (e.g., solib-svr4) learn + about this new process, relocate the cloned exec, pull + in shared libraries, and install the solib event + breakpoint. If a "cloned-VM" event was propagated + better throughout the core, this wouldn't be + required. */ + solib_create_inferior_hook (0); + } + + do_cleanups (old_chain); + } + + if (has_vforked) + { + struct inferior *parent_inf; + + parent_inf = current_inferior (); + + /* If we detached from the child, then we have to be careful + to not insert breakpoints in the parent until the child + is done with the shared memory region. However, if we're + staying attached to the child, then we can and should + insert breakpoints, so that we can debug it. A + subsequent child exec or exit is enough to know when does + the child stops using the parent's address space. */ + parent_inf->waiting_for_vfork_done = detach_fork; + parent_inf->pspace->breakpoints_not_allowed = detach_fork; + } + } + else + { + /* Follow the child. */ + struct inferior *parent_inf, *child_inf; + struct program_space *parent_pspace; + + if (info_verbose || debug_infrun) + { + target_terminal_ours_for_output (); + fprintf_filtered (gdb_stdlog, + _("Attaching after %s %s to child %s.\n"), + target_pid_to_str (parent_ptid), + has_vforked ? "vfork" : "fork", + target_pid_to_str (child_ptid)); + } + + /* Add the new inferior first, so that the target_detach below + doesn't unpush the target. */ + + child_inf = add_inferior (ptid_get_pid (child_ptid)); + + parent_inf = current_inferior (); + child_inf->attach_flag = parent_inf->attach_flag; + copy_terminal_info (child_inf, parent_inf); + child_inf->gdbarch = parent_inf->gdbarch; + copy_inferior_target_desc_info (child_inf, parent_inf); + + parent_pspace = parent_inf->pspace; + + /* If we're vforking, we want to hold on to the parent until the + child exits or execs. At child exec or exit time we can + remove the old breakpoints from the parent and detach or + resume debugging it. Otherwise, detach the parent now; we'll + want to reuse it's program/address spaces, but we can't set + them to the child before removing breakpoints from the + parent, otherwise, the breakpoints module could decide to + remove breakpoints from the wrong process (since they'd be + assigned to the same address space). */ + + if (has_vforked) + { + gdb_assert (child_inf->vfork_parent == NULL); + gdb_assert (parent_inf->vfork_child == NULL); + child_inf->vfork_parent = parent_inf; + child_inf->pending_detach = 0; + parent_inf->vfork_child = child_inf; + parent_inf->pending_detach = detach_fork; + parent_inf->waiting_for_vfork_done = 0; + } + else if (detach_fork) + { + if (info_verbose || debug_infrun) + { + target_terminal_ours_for_output (); + fprintf_filtered (gdb_stdlog, + _("Detaching after fork from " + "child %s.\n"), + target_pid_to_str (child_ptid)); + } + + target_detach (NULL, 0); + } + + /* Note that the detach above makes PARENT_INF dangling. */ + + /* Add the child thread to the appropriate lists, and switch to + this new thread, before cloning the program space, and + informing the solib layer about this new process. */ + + inferior_ptid = child_ptid; + add_thread (inferior_ptid); + + /* If this is a vfork child, then the address-space is shared + with the parent. If we detached from the parent, then we can + reuse the parent's program/address spaces. */ + if (has_vforked || detach_fork) + { + child_inf->pspace = parent_pspace; + child_inf->aspace = child_inf->pspace->aspace; + } + else + { + child_inf->aspace = new_address_space (); + child_inf->pspace = add_program_space (child_inf->aspace); + child_inf->removable = 1; + child_inf->symfile_flags = SYMFILE_NO_READ; + set_current_program_space (child_inf->pspace); + clone_program_space (child_inf->pspace, parent_pspace); + + /* Let the shared library layer (e.g., solib-svr4) learn + about this new process, relocate the cloned exec, pull in + shared libraries, and install the solib event breakpoint. + If a "cloned-VM" event was propagated better throughout + the core, this wouldn't be required. */ + solib_create_inferior_hook (0); + } + } + + return target_follow_fork (follow_child, detach_fork); +} + /* Tell the target to follow the fork we're stopped at. Returns true if the inferior should be resumed; false, if the target for some reason decided it's best not to resume. */ @@ -433,6 +652,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; if (!non_stop) { @@ -484,6 +704,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; /* For now, delete the parent's sr breakpoint, otherwise, parent/child sr breakpoints are considered duplicates, @@ -495,14 +716,16 @@ 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; } parent = inferior_ptid; child = tp->pending_follow.value.related_pid; - /* Tell the target to do whatever is necessary to follow - either parent or child. */ - if (target_follow_fork (follow_child, detach_fork)) + /* Set up inferior(s) as specified by the caller, and tell the + target to do whatever is necessary to follow either parent + or child. */ + if (follow_fork_inferior (follow_child, detach_fork)) { /* Target refused to follow, or there's some other reason we shouldn't resume. */ @@ -539,6 +762,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; } else { @@ -573,14 +797,16 @@ follow_fork (void) return should_resume; } -void +static void follow_inferior_reset_breakpoints (void) { struct thread_info *tp = inferior_thread (); /* Was there a step_resume breakpoint? (There was if the user did a "next" at the fork() call.) If so, explicitly reset its - thread number. + thread number. Cloned step_resume breakpoints are disabled on + creation, so enable it here now that it is associated with the + correct thread. step_resumes are a form of bp that are made to be per-thread. Since we created the step_resume bp when the parent process @@ -590,10 +816,17 @@ follow_inferior_reset_breakpoints (void) it is for, or it'll be ignored when it triggers. */ if (tp->control.step_resume_breakpoint) - breakpoint_re_set_thread (tp->control.step_resume_breakpoint); + { + breakpoint_re_set_thread (tp->control.step_resume_breakpoint); + tp->control.step_resume_breakpoint->loc->enabled = 1; + } + /* Treat exception_resume breakpoints like step_resume breakpoints. */ if (tp->control.exception_resume_breakpoint) - breakpoint_re_set_thread (tp->control.exception_resume_breakpoint); + { + breakpoint_re_set_thread (tp->control.exception_resume_breakpoint); + tp->control.exception_resume_breakpoint->loc->enabled = 1; + } /* Reinsert all breakpoints in the child. The user may have set breakpoints after catching the fork, in which case those @@ -625,8 +858,8 @@ proceed_after_vfork_done (struct thread_info *thread, target_pid_to_str (thread->ptid)); switch_to_thread (thread->ptid); - clear_proceed_status (); - proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT, 0); + clear_proceed_status (0); + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT); } return 0; @@ -693,18 +926,22 @@ handle_vfork_child_exec_or_exit (int exec) if (debug_infrun || info_verbose) { - target_terminal_ours (); + target_terminal_ours_for_output (); if (exec) - fprintf_filtered (gdb_stdlog, - "Detaching vfork parent process " - "%d after child exec.\n", - inf->vfork_parent->pid); + { + fprintf_filtered (gdb_stdlog, + _("Detaching vfork parent process " + "%d after child exec.\n"), + inf->vfork_parent->pid); + } else - fprintf_filtered (gdb_stdlog, - "Detaching vfork parent process " - "%d after child exit.\n", - inf->vfork_parent->pid); + { + fprintf_filtered (gdb_stdlog, + _("Detaching vfork parent process " + "%d after child exit.\n"), + inf->vfork_parent->pid); + } } target_detach (NULL, 0); @@ -814,10 +1051,11 @@ show_follow_exec_mode_string (struct ui_file *file, int from_tty, /* EXECD_PATHNAME is assumed to be non-NULL. */ static void -follow_exec (ptid_t pid, char *execd_pathname) +follow_exec (ptid_t ptid, char *execd_pathname) { - struct thread_info *th = inferior_thread (); + struct thread_info *th, *tmp; struct inferior *inf = current_inferior (); + int pid = ptid_get_pid (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 @@ -842,23 +1080,47 @@ follow_exec (ptid_t pid, char *execd_pathname) mark_breakpoints_out (); - update_breakpoints_after_exec (); - - /* If there was one, it's gone now. We cannot truly step-to-next - statement through an exec(). */ + /* The target reports the exec event to the main thread, even if + some other thread does the exec, and even if the main thread was + stopped or already gone. We may still have non-leader threads of + the process on our list. E.g., on targets that don't have thread + exit events (like remote); or on native Linux in non-stop mode if + there were only two threads in the inferior and the non-leader + one is the one that execs (and nothing forces an update of the + thread list up to here). When debugging remotely, it's best to + avoid extra traffic, when possible, so avoid syncing the thread + list with the target, and instead go ahead and delete all threads + of the process but one that reported the event. Note this must + be done before calling update_breakpoints_after_exec, as + otherwise clearing the threads' resources would reference stale + thread breakpoints -- it may have been one of these threads that + stepped across the exec. We could just clear their stepping + states, but as long as we're iterating, might as well delete + them. Deleting them now rather than at the next user-visible + stop provides a nicer sequence of events for user and MI + notifications. */ + ALL_THREADS_SAFE (th, tmp) + if (ptid_get_pid (th->ptid) == pid && !ptid_equal (th->ptid, ptid)) + delete_thread (th->ptid); + + /* We also need to clear any left over stale state for the + leader/event thread. E.g., if there was any step-resume + breakpoint or similar, it's gone now. We cannot truly + step-to-next statement through an exec(). */ + th = inferior_thread (); th->control.step_resume_breakpoint = NULL; th->control.exception_resume_breakpoint = NULL; + th->control.single_step_breakpoints = NULL; th->control.step_range_start = 0; th->control.step_range_end = 0; - /* The target reports the exec event to the main thread, even if - some other thread does the exec, and even if the main thread was - already stopped --- if debugging in non-stop mode, it's possible - the user had the main thread held stopped in the previous image - --- release it now. This is the same behavior as step-over-exec - with scheduler-locking on in all-stop mode. */ + /* The user may have had the main thread held stopped in the + previous image (e.g., schedlock on, or non-stop). Release + it now. */ th->stop_requested = 0; + update_breakpoints_after_exec (); + /* What is this a.out's name? */ printf_unfiltered (_("%s is executing new program: %s\n"), target_pid_to_str (inferior_ptid), @@ -961,30 +1223,100 @@ follow_exec (ptid_t pid, char *execd_pathname) matically get reset there in the new process.). */ } -/* Non-zero if we just simulating a single-step. This is needed - because we cannot remove the breakpoints in the inferior process - until after the `wait' in `wait_for_inferior'. */ -static int singlestep_breakpoints_inserted_p = 0; +/* Info about an instruction that is being stepped over. */ + +struct step_over_info +{ + /* If we're stepping past a breakpoint, this is the address space + and address of the instruction the breakpoint is set at. We'll + skip inserting all breakpoints here. Valid iff ASPACE is + non-NULL. */ + struct address_space *aspace; + CORE_ADDR address; + + /* The instruction being stepped over triggers a nonsteppable + watchpoint. If true, we'll skip inserting watchpoints. */ + int nonsteppable_watchpoint_p; +}; + +/* The step-over info of the location that is being stepped over. + + Note that with async/breakpoint always-inserted mode, a user might + set a new breakpoint/watchpoint/etc. exactly while a breakpoint is + being stepped over. As setting a new breakpoint inserts all + breakpoints, we need to make sure the breakpoint being stepped over + isn't inserted then. We do that by only clearing the step-over + info when the step-over is actually finished (or aborted). + + Presently GDB can only step over one breakpoint at any given time. + Given threads that can't run code in the same address space as the + breakpoint's can't really miss the breakpoint, GDB could be taught + to step-over at most one breakpoint per address space (so this info + could move to the address space object if/when GDB is extended). + The set of breakpoints being stepped over will normally be much + smaller than the set of all breakpoints, so a flag in the + breakpoint location structure would be wasteful. A separate list + also saves complexity and run-time, as otherwise we'd have to go + through all breakpoint locations clearing their flag whenever we + start a new sequence. Similar considerations weigh against storing + this info in the thread object. Plus, not all step overs actually + have breakpoint locations -- e.g., stepping past a single-step + breakpoint, or stepping to complete a non-continuable + watchpoint. */ +static struct step_over_info step_over_info; + +/* Record the address of the breakpoint/instruction we're currently + stepping over. */ + +static void +set_step_over_info (struct address_space *aspace, CORE_ADDR address, + int nonsteppable_watchpoint_p) +{ + step_over_info.aspace = aspace; + step_over_info.address = address; + step_over_info.nonsteppable_watchpoint_p = nonsteppable_watchpoint_p; +} + +/* Called when we're not longer stepping over a breakpoint / an + instruction, so all breakpoints are free to be (re)inserted. */ + +static void +clear_step_over_info (void) +{ + step_over_info.aspace = NULL; + step_over_info.address = 0; + step_over_info.nonsteppable_watchpoint_p = 0; +} + +/* See infrun.h. */ + +int +stepping_past_instruction_at (struct address_space *aspace, + CORE_ADDR address) +{ + return (step_over_info.aspace != NULL + && breakpoint_address_match (aspace, address, + step_over_info.aspace, + step_over_info.address)); +} -/* The thread we inserted single-step breakpoints for. */ -static ptid_t singlestep_ptid; +/* See infrun.h. */ -/* PC when we started this single-step. */ -static CORE_ADDR singlestep_pc; +int +stepping_past_nonsteppable_watchpoint (void) +{ + return step_over_info.nonsteppable_watchpoint_p; +} -/* If another thread hit the singlestep breakpoint, we save the original - thread here so that we can resume single-stepping it later. */ -static ptid_t saved_singlestep_ptid; -static int stepping_past_singlestep_breakpoint; +/* Returns true if step-over info is valid. */ -/* If not equal to null_ptid, this means that after stepping over breakpoint - is finished, we need to switch to deferred_step_ptid, and step it. +static int +step_over_info_valid_p (void) +{ + return (step_over_info.aspace != NULL + || stepping_past_nonsteppable_watchpoint ()); +} - The use case is when one thread has hit a breakpoint, and then the user - has switched to another thread and issued 'step'. We need to step over - breakpoint in the thread which hit the breakpoint, but then continue - stepping the thread user has selected. */ -static ptid_t deferred_step_ptid; /* Displaced stepping. */ @@ -1133,6 +1465,20 @@ get_displaced_stepping_state (int pid) return NULL; } +/* Return true if process PID has a thread doing a displaced step. */ + +static int +displaced_step_in_progress (int pid) +{ + struct displaced_step_inferior_state *displaced; + + displaced = get_displaced_stepping_state (pid); + if (displaced != NULL && !ptid_equal (displaced->step_ptid, null_ptid)) + return 1; + + return 0; +} + /* Add a new displaced stepping state for process PID to the displaced stepping state list, or return a pointer to an already existing entry, if it already exists. Never returns NULL. */ @@ -1240,7 +1586,7 @@ use_displaced_stepping (struct gdbarch *gdbarch) return (((can_use_displaced_stepping == AUTO_BOOLEAN_AUTO && non_stop) || can_use_displaced_stepping == AUTO_BOOLEAN_TRUE) && gdbarch_displaced_step_copy_insn_p (gdbarch) - && !RECORD_IS_USED); + && find_record_target () == NULL); } /* Clean out any stray displaced stepping state. */ @@ -1464,8 +1810,16 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal) displaced_step_restore (displaced, displaced->step_ptid); + /* Fixup may need to read memory/registers. Switch to the thread + that we're fixing up. Also, target_stopped_by_watchpoint checks + the current thread. */ + switch_to_thread (event_ptid); + /* Did the instruction complete successfully? */ - if (signal == GDB_SIGNAL_TRAP) + if (signal == GDB_SIGNAL_TRAP + && !(target_stopped_by_watchpoint () + && (gdbarch_have_nonsteppable_watchpoint (displaced->step_gdbarch) + || target_have_steppable_watchpoint))) { /* Fix up the resulting state. */ gdbarch_displaced_step_fixup (displaced->step_gdbarch, @@ -1511,6 +1865,7 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal) regcache = get_thread_regcache (ptid); actual_pc = regcache_read_pc (regcache); aspace = get_regcache_aspace (regcache); + gdbarch = get_regcache_arch (regcache); if (breakpoint_here_p (aspace, actual_pc)) { @@ -1521,8 +1876,6 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal) displaced_step_prepare (ptid); - gdbarch = get_regcache_arch (regcache); - if (debug_displaced) { CORE_ADDR actual_pc = regcache_read_pc (regcache); @@ -1555,6 +1908,9 @@ displaced_step_fixup (ptid_t event_ptid, enum gdb_signal signal) /* Go back to what we were trying to do. */ step = currently_stepping (tp); + if (step) + step = maybe_software_singlestep (gdbarch, actual_pc); + if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: breakpoint is gone: %s, step(%d)\n", @@ -1580,12 +1936,6 @@ infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid) if (ptid_equal (inferior_ptid, old_ptid)) inferior_ptid = new_ptid; - if (ptid_equal (singlestep_ptid, old_ptid)) - singlestep_ptid = new_ptid; - - if (ptid_equal (deferred_step_ptid, old_ptid)) - deferred_step_ptid = new_ptid; - for (displaced = displaced_step_inferior_states; displaced; displaced = displaced->next) @@ -1606,6 +1956,9 @@ infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid) static void resume_cleanups (void *ignore) { + if (!ptid_equal (inferior_ptid, null_ptid)) + delete_single_step_breakpoints (inferior_thread ()); + normal_stop (); } @@ -1660,37 +2013,17 @@ maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc) && gdbarch_software_single_step (gdbarch, get_current_frame ())) { hw_step = 0; - /* Do not pull these breakpoints until after a `wait' in - `wait_for_inferior'. */ - singlestep_breakpoints_inserted_p = 1; - singlestep_ptid = inferior_ptid; - singlestep_pc = pc; } return hw_step; } -/* Return a ptid representing the set of threads that we will proceed, - in the perspective of the user/frontend. We may actually resume - fewer threads at first, e.g., if a thread is stopped at a - breakpoint that needs stepping-off, but that should not be visible - to the user/frontend, and neither should the frontend/user be - allowed to proceed any of the threads that happen to be stopped for - internal run control handling, if a previous command wanted them - resumed. */ +/* See infrun.h. */ ptid_t user_visible_resume_ptid (int step) { - /* By default, resume all threads of all processes. */ - ptid_t resume_ptid = RESUME_ALL; - - /* Maybe resume only all threads of the current process. */ - if (!sched_multi && target_supports_multi_process ()) - { - resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid)); - } + ptid_t resume_ptid; - /* Maybe resume a single thread after all. */ if (non_stop) { /* With non-stop mode on, threads are always handled @@ -1698,37 +2031,104 @@ user_visible_resume_ptid (int step) resume_ptid = inferior_ptid; } else if ((scheduler_mode == schedlock_on) - || (scheduler_mode == schedlock_step - && (step || singlestep_breakpoints_inserted_p))) + || (scheduler_mode == schedlock_step && step)) { - /* User-settable 'scheduler' mode requires solo thread resume. */ + /* User-settable 'scheduler' mode requires solo thread + resume. */ resume_ptid = inferior_ptid; } + else if (!sched_multi && target_supports_multi_process ()) + { + /* Resume all threads of the current process (and none of other + processes). */ + resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid)); + } + else + { + /* Resume all threads of all processes. */ + resume_ptid = RESUME_ALL; + } return resume_ptid; } +/* Wrapper for target_resume, that handles infrun-specific + bookkeeping. */ + +static void +do_target_resume (ptid_t resume_ptid, int step, enum gdb_signal sig) +{ + struct thread_info *tp = inferior_thread (); + + /* Install inferior's terminal modes. */ + target_terminal_inferior (); + + /* Avoid confusing the next resume, if the next stop/resume + happens to apply to another thread. */ + tp->suspend.stop_signal = GDB_SIGNAL_0; + + /* Advise target which signals may be handled silently. + + If we have removed breakpoints because we are stepping over one + in-line (in any thread), we need to receive all signals to avoid + accidentally skipping a breakpoint during execution of a signal + handler. + + Likewise if we're displaced stepping, otherwise a trap for a + breakpoint in a signal handler might be confused with the + displaced step finishing. We don't make the displaced_step_fixup + step distinguish the cases instead, because: + + - a backtrace while stopped in the signal handler would show the + scratch pad as frame older than the signal handler, instead of + the real mainline code. + + - when the thread is later resumed, the signal handler would + return to the scratch pad area, which would no longer be + valid. */ + if (step_over_info_valid_p () + || displaced_step_in_progress (ptid_get_pid (tp->ptid))) + target_pass_signals (0, NULL); + else + target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass); + + target_resume (resume_ptid, step, sig); +} + /* Resume the inferior, but allow a QUIT. This is useful if the user wants to interrupt some lengthy single-stepping operation (for child processes, the SIGINT goes to the inferior, and so we get a SIGINT random_signal, but for remote debugging and perhaps other targets, that's not true). - STEP nonzero if we should step (zero to continue instead). SIG is the signal to give the inferior (zero for none). */ void -resume (int step, enum gdb_signal sig) +resume (enum gdb_signal sig) { - int should_resume = 1; struct cleanup *old_cleanups = make_cleanup (resume_cleanups, 0); struct regcache *regcache = get_current_regcache (); struct gdbarch *gdbarch = get_regcache_arch (regcache); struct thread_info *tp = inferior_thread (); CORE_ADDR pc = regcache_read_pc (regcache); struct address_space *aspace = get_regcache_aspace (regcache); + ptid_t resume_ptid; + /* This represents the user's step vs continue request. When + deciding whether "set scheduler-locking step" applies, it's the + user's intention that counts. */ + const int user_step = tp->control.stepping_command; + /* This represents what we'll actually request the target to do. + This can decay from a step to a continue, if e.g., we need to + implement single-stepping with breakpoints (software + single-step). */ + int step; + + tp->stepped_breakpoint = 0; QUIT; + /* Depends on stepped_breakpoint. */ + step = currently_stepping (tp); + if (current_inferior ()->waiting_for_vfork_done) { /* Don't try to single-step a vfork parent that is waiting for @@ -1763,13 +2163,76 @@ resume (int step, enum gdb_signal sig) breakpoints can't be removed. So we have to test for it here. */ if (breakpoint_here_p (aspace, pc) == permanent_breakpoint_here) { - if (gdbarch_skip_permanent_breakpoint_p (gdbarch)) - gdbarch_skip_permanent_breakpoint (gdbarch, regcache); + if (sig != GDB_SIGNAL_0) + { + /* We have a signal to pass to the inferior. The resume + may, or may not take us to the signal handler. If this + is a step, we'll need to stop in the signal handler, if + there's one, (if the target supports stepping into + handlers), or in the next mainline instruction, if + there's no handler. If this is a continue, we need to be + sure to run the handler with all breakpoints inserted. + In all cases, set a breakpoint at the current address + (where the handler returns to), and once that breakpoint + is hit, resume skipping the permanent breakpoint. If + that breakpoint isn't hit, then we've stepped into the + signal handler (or hit some other event). We'll delete + the step-resume breakpoint then. */ + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: resume: skipping permanent breakpoint, " + "deliver signal first\n"); + + clear_step_over_info (); + tp->control.trap_expected = 0; + + if (tp->control.step_resume_breakpoint == NULL) + { + /* Set a "high-priority" step-resume, as we don't want + user breakpoints at PC to trigger (again) when this + hits. */ + insert_hp_step_resume_breakpoint_at_frame (get_current_frame ()); + gdb_assert (tp->control.step_resume_breakpoint->loc->permanent); + + tp->step_after_step_resume_breakpoint = step; + } + + insert_breakpoints (); + } else - error (_("\ -The program is stopped at a permanent breakpoint, but GDB does not know\n\ -how to step past a permanent breakpoint on this architecture. Try using\n\ -a command like `return' or `jump' to continue execution.")); + { + /* There's no signal to pass, we can go ahead and skip the + permanent breakpoint manually. */ + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: resume: skipping permanent breakpoint\n"); + gdbarch_skip_permanent_breakpoint (gdbarch, regcache); + /* Update pc to reflect the new address from which we will + execute instructions. */ + pc = regcache_read_pc (regcache); + + if (step) + { + /* We've already advanced the PC, so the stepping part + is done. Now we need to arrange for a trap to be + reported to handle_inferior_event. Set a breakpoint + at the current PC, and run to it. Don't update + prev_pc, because if we end in + switch_back_to_stepped_thread, we want the "expected + thread advanced also" branch to be taken. IOW, we + don't want this thread to step further from PC + (overstep). */ + gdb_assert (!step_over_info_valid_p ()); + insert_single_step_breakpoint (gdbarch, aspace, pc); + insert_breakpoints (); + + resume_ptid = user_visible_resume_ptid (user_step); + do_target_resume (resume_ptid, 0, GDB_SIGNAL_0); + discard_cleanups (old_cleanups); + return; + } + } } /* If we have a breakpoint to step over, make sure to do a single @@ -1789,8 +2252,8 @@ a command like `return' or `jump' to continue execution.")); event, displaced stepping breaks the vfork child similarly as single step software breakpoint. */ if (use_displaced_stepping (gdbarch) - && (tp->control.trap_expected - || (step && gdbarch_software_single_step_p (gdbarch))) + && tp->control.trap_expected + && !step_over_info_valid_p () && sig == GDB_SIGNAL_0 && !current_inferior ()->waiting_for_vfork_done) { @@ -1800,11 +2263,14 @@ a command like `return' or `jump' to continue execution.")); { /* 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 frontend point of view, - the thread is running. */ - set_running (inferior_ptid, 1); + 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); discard_cleanups (old_cleanups); return; } @@ -1846,8 +2312,9 @@ a command like `return' or `jump' to continue execution.")); at the current address, deliver the signal without stepping, and once we arrive back at the step-resume breakpoint, actually step over the breakpoint we originally wanted to step over. */ - if (singlestep_breakpoints_inserted_p - && tp->control.trap_expected && sig != GDB_SIGNAL_0) + if (thread_has_single_step_breakpoints_set (tp) + && sig != GDB_SIGNAL_0 + && step_over_info_valid_p ()) { /* If we have nested signals or a pending signal is delivered immediately after a handler returns, might might already have @@ -1860,116 +2327,103 @@ a command like `return' or `jump' to continue execution.")); tp->step_after_step_resume_breakpoint = 1; } - remove_single_step_breakpoints (); - singlestep_breakpoints_inserted_p = 0; + delete_single_step_breakpoints (tp); - insert_breakpoints (); + clear_step_over_info (); tp->control.trap_expected = 0; + + insert_breakpoints (); } - if (should_resume) - { - ptid_t resume_ptid; + /* If STEP is set, it's a request to use hardware stepping + facilities. But in that case, we should never + use singlestep breakpoint. */ + gdb_assert (!(thread_has_single_step_breakpoints_set (tp) && step)); - /* If STEP is set, it's a request to use hardware stepping - facilities. But in that case, we should never - use singlestep breakpoint. */ - gdb_assert (!(singlestep_breakpoints_inserted_p && step)); + /* 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); - /* 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 (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 (singlestep_breakpoints_inserted_p - && stepping_past_singlestep_breakpoint) - { - /* The situation here is as follows. In thread T1 we wanted to - single-step. Lacking hardware single-stepping we've - set breakpoint at the PC of the next instruction -- call it - P. After resuming, we've hit that breakpoint in thread T2. - Now we've removed original breakpoint, inserted breakpoint - at P+1, and try to step to advance T2 past breakpoint. - We need to step only T2, as if T1 is allowed to freely run, - it can run past P, and if other threads are allowed to run, - they can hit breakpoint at P+1, and nested hits of single-step - breakpoints is not something we'd want -- that's complicated - to support, and has no value. */ - resume_ptid = inferior_ptid; - } - else if ((step || singlestep_breakpoints_inserted_p) - && 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. - - The current code actually removes all breakpoints when - doing this, not just the one being stepped over, so if we - let other threads run, we can actually miss any - breakpoint, not just the one at PC. */ - resume_ptid = inferior_ptid; - } + /* Maybe resume a single thread after all. */ + if ((step || thread_has_single_step_breakpoints_set (tp)) + && 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. */ + resume_ptid = inferior_ptid; + } + 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 + 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 + set. Assuming single-stepping and delivering a signal at the + same time would takes us to the signal handler, then we could + have removed the breakpoint at PC to step over it. However, + some hardware step targets (like e.g., Mac OS) can't step + into signal handlers, and for those, we need to leave the + breakpoint at PC inserted, as otherwise if the handler + 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); + + tp->stepped_breakpoint = 1; + + /* Most targets can step a breakpoint instruction, thus + executing it normally. But if this one cannot, just + continue and we will hit it anyway. */ if (gdbarch_cannot_step_breakpoint (gdbarch)) - { - /* Most targets can step a breakpoint instruction, thus - executing it normally. But if this one cannot, just - continue and we will hit it anyway. */ - if (step && breakpoint_inserted_here_p (aspace, pc)) - step = 0; - } + step = 0; + } - if (debug_displaced - && use_displaced_stepping (gdbarch) - && tp->control.trap_expected) - { - struct regcache *resume_regcache = get_thread_regcache (resume_ptid); - struct gdbarch *resume_gdbarch = get_regcache_arch (resume_regcache); - CORE_ADDR actual_pc = regcache_read_pc (resume_regcache); - gdb_byte buf[4]; - - fprintf_unfiltered (gdb_stdlog, "displaced: run %s: ", - paddress (resume_gdbarch, actual_pc)); - read_memory (actual_pc, buf, sizeof (buf)); - displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf)); - } - - if (tp->control.may_range_step) - { - /* If we're resuming a thread with the PC out of the step - range, then we're doing some nested/finer run control - operation, like stepping the thread out of the dynamic - linker or the displaced stepping scratch pad. We - shouldn't have allowed a range step then. */ - gdb_assert (pc_in_thread_step_range (pc, tp)); - } + if (debug_displaced + && use_displaced_stepping (gdbarch) + && tp->control.trap_expected + && !step_over_info_valid_p ()) + { + struct regcache *resume_regcache = get_thread_regcache (tp->ptid); + struct gdbarch *resume_gdbarch = get_regcache_arch (resume_regcache); + CORE_ADDR actual_pc = regcache_read_pc (resume_regcache); + gdb_byte buf[4]; - /* Install inferior's terminal modes. */ - target_terminal_inferior (); - - /* Avoid confusing the next resume, if the next stop/resume - happens to apply to another thread. */ - tp->suspend.stop_signal = GDB_SIGNAL_0; - - /* Advise target which signals may be handled silently. If we have - removed breakpoints because we are stepping over one (which can - happen only if we are not using displaced stepping), we need to - receive all signals to avoid accidentally skipping a breakpoint - during execution of a signal handler. */ - if ((step || singlestep_breakpoints_inserted_p) - && tp->control.trap_expected - && !use_displaced_stepping (gdbarch)) - target_pass_signals (0, NULL); - else - target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass); + fprintf_unfiltered (gdb_stdlog, "displaced: run %s: ", + paddress (resume_gdbarch, actual_pc)); + read_memory (actual_pc, buf, sizeof (buf)); + displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf)); + } - target_resume (resume_ptid, step, sig); + if (tp->control.may_range_step) + { + /* If we're resuming a thread with the PC out of the step + range, then we're doing some nested/finer run control + operation, like stepping the thread out of the dynamic + linker or the displaced stepping scratch pad. We + shouldn't have allowed a range step then. */ + gdb_assert (pc_in_thread_step_range (pc, tp)); } + do_target_resume (resume_ptid, step, sig); discard_cleanups (old_cleanups); } @@ -1986,6 +2440,11 @@ clear_proceed_status_thread (struct thread_info *tp) "infrun: clear_proceed_status_thread (%s)\n", target_pid_to_str (tp->ptid)); + /* 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; + tp->control.trap_expected = 0; tp->control.step_range_start = 0; tp->control.step_range_end = 0; @@ -1993,36 +2452,38 @@ clear_proceed_status_thread (struct thread_info *tp) tp->control.step_frame_id = null_frame_id; tp->control.step_stack_frame_id = null_frame_id; tp->control.step_over_calls = STEP_OVER_UNDEBUGGABLE; + tp->control.step_start_function = NULL; tp->stop_requested = 0; tp->control.stop_step = 0; 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. */ bpstat_clear (&tp->control.stop_bpstat); } -static int -clear_proceed_status_callback (struct thread_info *tp, void *data) -{ - if (is_exited (tp->ptid)) - return 0; - - clear_proceed_status_thread (tp); - return 0; -} - void -clear_proceed_status (void) +clear_proceed_status (int step) { if (!non_stop) { - /* In all-stop mode, delete the per-thread status of all - threads, even if inferior_ptid is null_ptid, there may be - threads on the list. E.g., we may be launching a new - process, while selecting the executable. */ - iterate_over_threads (clear_proceed_status_callback, NULL); + struct thread_info *tp; + ptid_t resume_ptid; + + resume_ptid = user_visible_resume_ptid (step); + + /* In all-stop mode, delete the per-thread status of all threads + we're about to resume, implicitly and explicitly. */ + ALL_NON_EXITED_THREADS (tp) + { + if (!ptid_match (tp->ptid, resume_ptid)) + continue; + clear_proceed_status_thread (tp); + } } if (!ptid_equal (inferior_ptid, null_ptid)) @@ -2042,6 +2503,8 @@ clear_proceed_status (void) stop_after_trap = 0; + clear_step_over_info (); + observer_notify_about_to_proceed (); if (stop_registers) @@ -2051,79 +2514,79 @@ clear_proceed_status (void) } } -/* Check the current thread against the thread that reported the most recent - event. If a step-over is required return TRUE and set the current thread - to the old thread. Otherwise return FALSE. +/* Returns true if TP is still stopped at a breakpoint that needs + stepping-over in order to make progress. If the breakpoint is gone + meanwhile, we can skip the whole step-over dance. */ + +static int +thread_still_needs_step_over (struct thread_info *tp) +{ + if (tp->stepping_over_breakpoint) + { + struct regcache *regcache = get_thread_regcache (tp->ptid); + + if (breakpoint_here_p (get_regcache_aspace (regcache), + regcache_read_pc (regcache)) + == ordinary_breakpoint_here) + return 1; + + tp->stepping_over_breakpoint = 0; + } + + return 0; +} - This should be suitable for any targets that support threads. */ +/* Returns true if scheduler locking applies. STEP indicates whether + we're about to do a step/next-like command to a thread. */ static int -prepare_to_proceed (int step) +schedlock_applies (struct thread_info *tp) { - ptid_t wait_ptid; - struct target_waitstatus wait_status; - int schedlock_enabled; + 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); - /* Get the last target status returned by target_wait(). */ - get_last_target_status (&wait_ptid, &wait_status); + current = inferior_thread (); - /* Make sure we were stopped at a breakpoint. */ - if (wait_status.kind != TARGET_WAITKIND_STOPPED - || (wait_status.value.sig != GDB_SIGNAL_TRAP - && wait_status.value.sig != GDB_SIGNAL_ILL - && wait_status.value.sig != GDB_SIGNAL_SEGV - && wait_status.value.sig != GDB_SIGNAL_EMT)) + /* If scheduler locking applies, we can avoid iterating over all + threads. */ + if (schedlock_applies (except)) { - return 0; + if (except != current + && thread_still_needs_step_over (current)) + return current; + + return NULL; } - schedlock_enabled = (scheduler_mode == schedlock_on - || (scheduler_mode == schedlock_step - && step)); + 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; - /* Don't switch over to WAIT_PTID if scheduler locking is on. */ - if (schedlock_enabled) - return 0; + if (thread_still_needs_step_over (tp)) + return tp; + } - /* Don't switch over if we're about to resume some other process - other than WAIT_PTID's, and schedule-multiple is off. */ - if (!sched_multi - && ptid_get_pid (wait_ptid) != ptid_get_pid (inferior_ptid)) - return 0; - - /* Switched over from WAIT_PID. */ - if (!ptid_equal (wait_ptid, minus_one_ptid) - && !ptid_equal (inferior_ptid, wait_ptid)) - { - struct regcache *regcache = get_thread_regcache (wait_ptid); - - if (breakpoint_here_p (get_regcache_aspace (regcache), - regcache_read_pc (regcache))) - { - /* If stepping, remember current thread to switch back to. */ - if (step) - deferred_step_ptid = inferior_ptid; - - /* Switch back to WAIT_PID thread. */ - switch_to_thread (wait_ptid); - - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: prepare_to_proceed (step=%d), " - "switched to [%s]\n", - step, target_pid_to_str (inferior_ptid)); - - /* We return 1 to indicate that there is a breakpoint here, - so we need to step over it before continuing to avoid - hitting it straight away. */ - return 1; - } - } - - return 0; + return NULL; } /* Basic routine for continuing the program in various fashions. @@ -2139,15 +2602,13 @@ prepare_to_proceed (int step) You should call clear_proceed_status before calling proceed. */ void -proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step) +proceed (CORE_ADDR addr, enum gdb_signal siggnal) { struct regcache *regcache; struct gdbarch *gdbarch; struct thread_info *tp; CORE_ADDR pc; struct address_space *aspace; - /* GDB may force the inferior to step due to various reasons. */ - int force_step = 0; /* If we're stopped at a fork/vfork, follow the branch set by the "set follow-fork-mode" command; otherwise, we'll just proceed @@ -2168,15 +2629,15 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step) gdbarch = get_regcache_arch (regcache); aspace = get_regcache_aspace (regcache); pc = regcache_read_pc (regcache); + tp = inferior_thread (); - if (step > 0) - step_start_function = find_pc_function (pc); - if (step < 0) - stop_after_trap = 1; + /* Fill in with reasonable starting values. */ + init_thread_stepping_state (tp); if (addr == (CORE_ADDR) -1) { - if (pc == stop_pc && breakpoint_here_p (aspace, pc) + if (pc == stop_pc + && breakpoint_here_p (aspace, pc) == ordinary_breakpoint_here && execution_direction != EXEC_REVERSE) /* There is a breakpoint at the address we will resume at, step one instruction before inserting breakpoints so that @@ -2186,25 +2647,35 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step) Note, we don't do this in reverse, because we won't actually be executing the breakpoint insn anyway. We'll be (un-)executing the previous instruction. */ - - force_step = 1; + tp->stepping_over_breakpoint = 1; else if (gdbarch_single_step_through_delay_p (gdbarch) && gdbarch_single_step_through_delay (gdbarch, get_current_frame ())) /* We stepped onto an instruction that needs to be stepped again before re-inserting the breakpoint, do so. */ - force_step = 1; + tp->stepping_over_breakpoint = 1; } else { regcache_write_pc (regcache, addr); } + 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 (); + if (debug_infrun) fprintf_unfiltered (gdb_stdlog, - "infrun: proceed (addr=%s, signal=%s, step=%d)\n", + "infrun: proceed (addr=%s, signal=%s)\n", paddress (gdbarch, addr), - gdb_signal_to_symbol_string (siggnal), step); + gdb_signal_to_symbol_string (siggnal)); if (non_stop) /* In non-stop, each thread is handled individually. The context @@ -2212,6 +2683,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step) ; else { + struct thread_info *step_over; + /* In a multi-threaded task we may select another thread and then continue or step. @@ -2220,66 +2693,41 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step) execution (i.e. it will report a breakpoint hit incorrectly). So we must step over it first. - prepare_to_proceed checks the current thread against the - thread that reported the most recent event. If a step-over - is required it returns TRUE and sets the current thread to - the old thread. */ - if (prepare_to_proceed (step)) - force_step = 1; - } - - /* prepare_to_proceed may change the current thread. */ - tp = inferior_thread (); - - if (force_step) - { - tp->control.trap_expected = 1; - /* If displaced stepping is enabled, we can step over the - breakpoint without hitting it, so leave all breakpoints - inserted. Otherwise we need to disable all breakpoints, step - one instruction, and then re-add them when that step is - finished. */ - if (!use_displaced_stepping (gdbarch)) - remove_breakpoints (); + 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)); + + /* 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; + } } - /* We can insert breakpoints if we're not trying to step over one, - or if we are stepping over one but we're using displaced stepping - to do so. */ - if (! tp->control.trap_expected || use_displaced_stepping (gdbarch)) - insert_breakpoints (); - - if (!non_stop) + /* 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)) { - /* Pass the last stop signal to the thread we're resuming, - irrespective of whether the current thread is the thread that - got the last event or not. This was historically GDB's - behaviour before keeping a stop_signal per thread. */ + struct regcache *regcache = get_current_regcache (); - struct thread_info *last_thread; - ptid_t last_ptid; - struct target_waitstatus last_status; - - get_last_target_status (&last_ptid, &last_status); - if (!ptid_equal (inferior_ptid, last_ptid) - && !ptid_equal (last_ptid, null_ptid) - && !ptid_equal (last_ptid, minus_one_ptid)) - { - last_thread = find_thread_ptid (last_ptid); - if (last_thread) - { - tp->suspend.stop_signal = last_thread->suspend.stop_signal; - last_thread->suspend.stop_signal = GDB_SIGNAL_0; - } - } + set_step_over_info (get_regcache_aspace (regcache), + regcache_read_pc (regcache), 0); } + else + clear_step_over_info (); - if (siggnal != GDB_SIGNAL_DEFAULT) - tp->suspend.stop_signal = siggnal; - /* If this signal should not be seen by program, - give it zero. Used for debugging signals. */ - else if (!signal_program[tp->suspend.stop_signal]) - tp->suspend.stop_signal = GDB_SIGNAL_0; + insert_breakpoints (); + + tp->control.trap_expected = tp->stepping_over_breakpoint; annotate_starting (); @@ -2288,7 +2736,7 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step) gdb_flush (gdb_stdout); /* Refresh prev_pc value just prior to resuming. This used to be - done in stop_stepping, however, setting prev_pc there did not handle + 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 @@ -2312,15 +2760,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal, int step) correctly when the inferior is stopped. */ tp->prev_pc = regcache_read_pc (get_current_regcache ()); - /* Fill in with reasonable starting values. */ - init_thread_stepping_state (tp); - - /* Reset to normal state. */ - init_infwait_state (); - /* Resume inferior. */ - resume (force_step || step || bpstat_should_step (), - tp->suspend.stop_signal); + resume (tp->suspend.stop_signal); /* Wait for it to stop (if not standalone) and in any case decode why it stopped, and act accordingly. */ @@ -2377,39 +2818,17 @@ init_wait_for_inferior (void) breakpoint_init_inferior (inf_starting); - clear_proceed_status (); - - stepping_past_singlestep_breakpoint = 0; - deferred_step_ptid = null_ptid; + clear_proceed_status (0); target_last_wait_ptid = minus_one_ptid; previous_inferior_ptid = inferior_ptid; - init_infwait_state (); /* Discard any skipped inlined frames. */ clear_inline_frame_state (minus_one_ptid); } -/* This enum encodes possible reasons for doing a target_wait, so that - wfi can call target_wait in one place. (Ultimately the call will be - moved out of the infinite loop entirely.) */ - -enum infwait_states -{ - infwait_normal_state, - infwait_thread_hop_state, - infwait_step_watch_state, - infwait_nonstep_watch_state -}; - -/* The PTID we'll do a target_wait on.*/ -ptid_t waiton_ptid; - -/* Current inferior wait state. */ -static enum infwait_states infwait_state; - /* Data to be passed around while handling an event. This data is discarded between events. */ struct execution_control_state @@ -2426,10 +2845,11 @@ struct execution_control_state const char *stop_func_name; int wait_some_more; - /* We were in infwait_step_watch_state or - infwait_nonstep_watch_state state, and the thread reported an - event. */ - int stepped_after_stopped_by_watchpoint; + /* 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); @@ -2442,7 +2862,8 @@ static void handle_signal_stop (struct execution_control_state *ecs); static void check_exception_resume (struct execution_control_state *, struct frame_info *); -static void stop_stepping (struct execution_control_state *ecs); +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); @@ -2558,54 +2979,71 @@ infrun_thread_thread_exit (struct thread_info *tp, int silent) nullify_last_target_wait_ptid (); } -/* Callback for iterate_over_threads. */ +/* Delete the step resume, single-step and longjmp/exception resume + breakpoints of TP. */ -static int -delete_step_resume_breakpoint_callback (struct thread_info *info, void *data) +static void +delete_thread_infrun_breakpoints (struct thread_info *tp) { - if (is_exited (info->ptid)) - return 0; - - delete_step_resume_breakpoint (info); - delete_exception_resume_breakpoint (info); - return 0; + delete_step_resume_breakpoint (tp); + delete_exception_resume_breakpoint (tp); + delete_single_step_breakpoints (tp); } -/* In all-stop, delete the step resume breakpoint of any thread that - had one. In non-stop, delete the step resume breakpoint of the - thread that just stopped. */ +/* If the target still has execution, call FUNC for each thread that + just stopped. In all-stop, that's all the non-exited threads; in + non-stop, that's the current thread, only. */ + +typedef void (*for_each_just_stopped_thread_callback_func) + (struct thread_info *tp); static void -delete_step_thread_step_resume_breakpoint (void) +for_each_just_stopped_thread (for_each_just_stopped_thread_callback_func func) { - if (!target_has_execution - || ptid_equal (inferior_ptid, null_ptid)) - /* If the inferior has exited, we have already deleted the step - resume breakpoints out of GDB's lists. */ + if (!target_has_execution || ptid_equal (inferior_ptid, null_ptid)) return; if (non_stop) { - /* If in non-stop mode, only delete the step-resume or - longjmp-resume breakpoint of the thread that just stopped - stepping. */ - struct thread_info *tp = inferior_thread (); - - delete_step_resume_breakpoint (tp); - delete_exception_resume_breakpoint (tp); + /* If in non-stop mode, only the current thread stopped. */ + func (inferior_thread ()); } else - /* In all-stop mode, delete all step-resume and longjmp-resume - breakpoints of any thread that had them. */ - iterate_over_threads (delete_step_resume_breakpoint_callback, NULL); + { + struct thread_info *tp; + + /* In all-stop mode, all threads have stopped. */ + ALL_NON_EXITED_THREADS (tp) + { + func (tp); + } + } +} + +/* Delete the step resume and longjmp/exception resume breakpoints of + the threads that just stopped. */ + +static void +delete_just_stopped_threads_infrun_breakpoints (void) +{ + for_each_just_stopped_thread (delete_thread_infrun_breakpoints); +} + +/* Delete the single-step breakpoints of the threads that just + stopped. */ + +static void +delete_just_stopped_threads_single_step_breakpoints (void) +{ + for_each_just_stopped_thread (delete_single_step_breakpoints); } /* A cleanup wrapper. */ static void -delete_step_thread_step_resume_breakpoint_cleanup (void *arg) +delete_just_stopped_threads_infrun_breakpoints_cleanup (void *arg) { - delete_step_thread_step_resume_breakpoint (); + delete_just_stopped_threads_infrun_breakpoints (); } /* Pretty print the results of target_wait, for debugging purposes. */ @@ -2624,14 +3062,19 @@ print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid, is set. */ fprintf_unfiltered (tmp_stream, - "infrun: target_wait (%d", ptid_get_pid (waiton_ptid)); + "infrun: target_wait (%d.%ld.%ld", + ptid_get_pid (waiton_ptid), + ptid_get_lwp (waiton_ptid), + ptid_get_tid (waiton_ptid)); if (ptid_get_pid (waiton_ptid) != -1) fprintf_unfiltered (tmp_stream, " [%s]", target_pid_to_str (waiton_ptid)); fprintf_unfiltered (tmp_stream, ", status) =\n"); fprintf_unfiltered (tmp_stream, - "infrun: %d [%s],\n", + "infrun: %d.%ld.%ld [%s],\n", ptid_get_pid (result_ptid), + ptid_get_lwp (result_ptid), + ptid_get_tid (result_ptid), target_pid_to_str (result_ptid)); fprintf_unfiltered (tmp_stream, "infrun: %s\n", @@ -2735,19 +3178,26 @@ void wait_for_inferior (void) { struct cleanup *old_cleanups; + struct cleanup *thread_state_chain; if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: wait_for_inferior ()\n"); - old_cleanups = - make_cleanup (delete_step_thread_step_resume_breakpoint_cleanup, NULL); + old_cleanups + = make_cleanup (delete_just_stopped_threads_infrun_breakpoints_cleanup, + NULL); + + /* If an error happens while handling the event, propagate GDB's + knowledge of the executing state to the frontend/user running + state. */ + thread_state_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid); while (1) { struct execution_control_state ecss; struct execution_control_state *ecs = &ecss; - struct cleanup *old_chain; + ptid_t waiton_ptid = minus_one_ptid; memset (ecs, 0, sizeof (*ecs)); @@ -2767,24 +3217,46 @@ wait_for_inferior (void) if (debug_infrun) print_target_wait_results (waiton_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 = 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); - if (!ecs->wait_some_more) break; } + /* No error, don't finish the state yet. */ + discard_cleanups (thread_state_chain); + do_cleanups (old_cleanups); } +/* Cleanup that reinstalls the readline callback handler, if the + target is running in the background. If while handling the target + event something triggered a secondary prompt, like e.g., a + pagination prompt, we'll have removed the callback handler (see + gdb_readline_wrapper_line). Need to do this as we go back to the + event loop, ready to process further input. Note this has no + effect if the handler hasn't actually been removed, because calling + rl_callback_handler_install resets the line buffer, thus losing + input. */ + +static void +reinstall_readline_callback_handler_cleanup (void *arg) +{ + if (!interpreter_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, + readline-style (raw, noecho) (e.g., --batch). We'll install + it the next time the prompt is displayed, when we're ready + for input. */ + return; + } + + if (async_command_editing_p && !sync_execution) + gdb_rl_callback_handler_reinstall (); +} + /* 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 @@ -2803,9 +3275,13 @@ fetch_inferior_event (void *client_data) struct cleanup *ts_old_chain; int was_sync = sync_execution; int cmd_done = 0; + ptid_t waiton_ptid = minus_one_ptid; memset (ecs, 0, sizeof (*ecs)); + /* End up with readline processing input, if necessary. */ + make_cleanup (reinstall_readline_callback_handler_cleanup, NULL); + /* We're handling a live event, so make sure we're doing live debugging. If we're looking at traceframes while the target is running, we're going to need to get back to that mode after @@ -2854,14 +3330,16 @@ fetch_inferior_event (void *client_data) still for the thread which has thrown the exception. */ make_bpstat_clear_actions_cleanup (); + make_cleanup (delete_just_stopped_threads_infrun_breakpoints_cleanup, NULL); + /* Now figure out what to do with the result of the result. */ handle_inferior_event (ecs); if (!ecs->wait_some_more) { - struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid)); + struct inferior *inf = find_inferior_ptid (ecs->ptid); - delete_step_thread_step_resume_breakpoint (); + 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) @@ -2891,7 +3369,7 @@ fetch_inferior_event (void *client_data) restore the prompt (a synchronous execution command has finished, and we're ready for input). */ if (interpreter_async && was_sync && !sync_execution) - display_gdb_prompt (0); + observer_notify_sync_execution_done (); if (cmd_done && !was_sync @@ -2919,10 +3397,21 @@ set_step_info (struct frame_info *frame, struct symtab_and_line sal) void init_thread_stepping_state (struct thread_info *tss) { + tss->stepped_breakpoint = 0; tss->stepping_over_breakpoint = 0; + tss->stepping_over_watchpoint = 0; tss->step_after_step_resume_breakpoint = 0; } +/* Set the cached copy of the last ptid/waitstatus. */ + +static void +set_last_target_status (ptid_t ptid, struct target_waitstatus status) +{ + target_last_wait_ptid = ptid; + target_last_waitstatus = status; +} + /* Return the cached copy of the last pid/waitstatus returned by target_wait()/deprecated_target_wait_hook(). The data is actually cached by handle_inferior_event(), which gets called immediately @@ -2963,7 +3452,7 @@ adjust_pc_after_break (struct execution_control_state *ecs) struct regcache *regcache; struct gdbarch *gdbarch; struct address_space *aspace; - CORE_ADDR breakpoint_pc; + CORE_ADDR breakpoint_pc, decr_pc; /* If we've hit a breakpoint, we'll normally be stopped with SIGTRAP. If we aren't, just return. @@ -3021,19 +3510,37 @@ adjust_pc_after_break (struct execution_control_state *ecs) if (execution_direction == EXEC_REVERSE) return; + /* If the target can tell whether the thread hit a SW breakpoint, + trust it. Targets that can tell also adjust the PC + themselves. */ + if (target_supports_stopped_by_sw_breakpoint ()) + return; + + /* Note that relying on whether a breakpoint is planted in memory to + determine this can fail. E.g,. the breakpoint could have been + removed since. Or the thread could have been told to step an + instruction the size of a breakpoint instruction, and only + _after_ was a breakpoint inserted at its address. */ + /* If this target does not decrement the PC after breakpoints, then we have nothing to do. */ regcache = get_thread_regcache (ecs->ptid); gdbarch = get_regcache_arch (regcache); - if (gdbarch_decr_pc_after_break (gdbarch) == 0) + + decr_pc = gdbarch_decr_pc_after_break (gdbarch); + if (decr_pc == 0) return; aspace = get_regcache_aspace (regcache); /* Find the location where (if we've hit a breakpoint) the breakpoint would be. */ - breakpoint_pc = regcache_read_pc (regcache) - - gdbarch_decr_pc_after_break (gdbarch); + breakpoint_pc = regcache_read_pc (regcache) - decr_pc; + + /* If the target can't tell whether a software breakpoint triggered, + fallback to figuring it out based on breakpoints we think were + inserted in the target, and on whether the thread was stepped or + continued. */ /* Check whether there actually is a software breakpoint inserted at that location. @@ -3042,13 +3549,16 @@ adjust_pc_after_break (struct execution_control_state *ecs) removed a breakpoint, but stop events for that breakpoint were already queued and arrive later. To suppress those spurious SIGTRAPs, we keep a list of such breakpoint locations for a bit, - and retire them after a number of stop events are reported. */ + and retire them after a number of stop events are reported. Note + this is an heuristic and can thus get confused. The real fix is + 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))) { struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL); - if (RECORD_IS_USED) + if (record_full_is_used ()) record_full_gdb_operation_disable_set (); /* When using hardware single-step, a SIGTRAP is reported for both @@ -3058,7 +3568,6 @@ adjust_pc_after_break (struct execution_control_state *ecs) The SIGTRAP can be due to a completed hardware single-step only if - we didn't insert software single-step breakpoints - - the thread to be examined is still the current thread - this thread is currently being stepped If any of these events did not occur, we must have stopped due @@ -3069,23 +3578,16 @@ 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 (singlestep_breakpoints_inserted_p - || !ptid_equal (ecs->ptid, inferior_ptid) + if (thread_has_single_step_breakpoints_set (ecs->event_thread) || !currently_stepping (ecs->event_thread) - || ecs->event_thread->prev_pc == breakpoint_pc) + || (ecs->event_thread->stepped_breakpoint + && ecs->event_thread->prev_pc == breakpoint_pc)) regcache_write_pc (regcache, breakpoint_pc); do_cleanups (old_cleanups); } } -static void -init_infwait_state (void) -{ - waiton_ptid = pid_to_ptid (-1); - infwait_state = infwait_normal_state; -} - static int stepped_in_from (struct frame_info *frame, struct frame_id step_frame_id) { @@ -3158,6 +3660,10 @@ fill_in_stop_func (struct gdbarch *gdbarch, ecs->stop_func_start += gdbarch_deprecated_function_start_offset (gdbarch); + if (gdbarch_skip_entrypoint_p (gdbarch)) + ecs->stop_func_start = gdbarch_skip_entrypoint (gdbarch, + ecs->stop_func_start); + ecs->stop_func_filled_in = 1; } } @@ -3168,7 +3674,7 @@ fill_in_stop_func (struct gdbarch *gdbarch, static enum stop_kind get_inferior_stop_soon (ptid_t ptid) { - struct inferior *inf = find_inferior_pid (ptid_get_pid (ptid)); + struct inferior *inf = find_inferior_ptid (ptid); gdb_assert (inf != NULL); return inf->control.stop_soon; @@ -3180,7 +3686,7 @@ get_inferior_stop_soon (ptid_t ptid) The alternatives are: - 1) stop_stepping and return; to really stop and return to the + 1) stop_waiting and return; to really stop and return to the debugger. 2) keep_going and return; to wait for the next event (set @@ -3225,8 +3731,7 @@ handle_inferior_event (struct execution_control_state *ecs) } /* Cache the last pid/waitstatus. */ - target_last_wait_ptid = ecs->ptid; - target_last_waitstatus = ecs->ws; + set_last_target_status (ecs->ptid, ecs->ws); /* Always clear state belonging to the previous time we stopped. */ stop_stack_dummy = STOP_NONE; @@ -3239,7 +3744,7 @@ handle_inferior_event (struct execution_control_state *ecs) fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_NO_RESUMED\n"); stop_print_frame = 0; - stop_stepping (ecs); + stop_waiting (ecs); return; } @@ -3303,45 +3808,6 @@ handle_inferior_event (struct execution_control_state *ecs) && ecs->ws.kind != TARGET_WAITKIND_EXITED) set_executing (ecs->ptid, 0); - switch (infwait_state) - { - case infwait_thread_hop_state: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: infwait_thread_hop_state\n"); - break; - - case infwait_normal_state: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: infwait_normal_state\n"); - break; - - case infwait_step_watch_state: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: infwait_step_watch_state\n"); - - ecs->stepped_after_stopped_by_watchpoint = 1; - break; - - case infwait_nonstep_watch_state: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: infwait_nonstep_watch_state\n"); - insert_breakpoints (); - - /* FIXME-maybe: is this cleaner than setting a flag? Does it - handle things like signals arriving and other things happening - in combination correctly? */ - ecs->stepped_after_stopped_by_watchpoint = 1; - break; - - default: - internal_error (__FILE__, __LINE__, _("bad switch")); - } - - infwait_state = infwait_normal_state; - waiton_ptid = pid_to_ptid (-1); - switch (ecs->ws.kind) { case TARGET_WAITKIND_LOADED: @@ -3387,7 +3853,7 @@ handle_inferior_event (struct execution_control_state *ecs) normal_stop. */ stop_print_frame = 1; - stop_stepping (ecs); + stop_waiting (ecs); return; } } @@ -3399,10 +3865,9 @@ handle_inferior_event (struct execution_control_state *ecs) { /* Loading of shared libraries might have changed breakpoint addresses. Make sure new breakpoints are inserted. */ - if (stop_soon == NO_STOP_QUIETLY - && !breakpoints_always_inserted_mode ()) + if (stop_soon == NO_STOP_QUIETLY) insert_breakpoints (); - resume (0, GDB_SIGNAL_0); + resume (GDB_SIGNAL_0); prepare_to_wait (ecs); return; } @@ -3414,7 +3879,7 @@ handle_inferior_event (struct execution_control_state *ecs) { if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n"); - stop_stepping (ecs); + stop_waiting (ecs); return; } @@ -3426,7 +3891,7 @@ handle_inferior_event (struct execution_control_state *ecs) fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SPURIOUS\n"); if (!ptid_equal (ecs->ptid, inferior_ptid)) context_switch (ecs->ptid); - resume (0, GDB_SIGNAL_0); + resume (GDB_SIGNAL_0); prepare_to_wait (ecs); return; @@ -3443,7 +3908,7 @@ handle_inferior_event (struct execution_control_state *ecs) } inferior_ptid = ecs->ptid; - set_current_inferior (find_inferior_pid (ptid_get_pid (ecs->ptid))); + set_current_inferior (find_inferior_ptid (ecs->ptid)); set_current_program_space (current_inferior ()->pspace); handle_vfork_child_exec_or_exit (0); target_terminal_ours (); /* Must do this before mourn anyway. */ @@ -3462,7 +3927,10 @@ handle_inferior_event (struct execution_control_state *ecs) current_inferior ()->has_exit_code = 1; current_inferior ()->exit_code = (LONGEST) ecs->ws.value.integer; - print_exited_reason (ecs->ws.value.integer); + /* Support the --return-child-result option. */ + return_child_result_value = ecs->ws.value.integer; + + observer_notify_exited (ecs->ws.value.integer); } else { @@ -3491,15 +3959,13 @@ handle_inferior_event (struct execution_control_state *ecs) Cannot fill $_exitsignal with the correct signal number.\n")); } - print_signal_exited_reason (ecs->ws.value.sig); + observer_notify_signal_exited (ecs->ws.value.sig); } gdb_flush (gdb_stdout); target_mourn_inferior (); - singlestep_breakpoints_inserted_p = 0; - cancel_single_step_breakpoints (); stop_print_frame = 0; - stop_stepping (ecs); + stop_waiting (ecs); return; /* The following are the only cases in which we keep going; @@ -3526,7 +3992,7 @@ Cannot fill $_exitsignal with the correct signal number.\n")); if (displaced && ptid_equal (displaced->step_ptid, ecs->ptid)) { struct inferior *parent_inf - = find_inferior_pid (ptid_get_pid (ecs->ptid)); + = find_inferior_ptid (ecs->ptid); struct regcache *child_regcache; CORE_ADDR parent_pc; @@ -3590,12 +4056,7 @@ Cannot fill $_exitsignal with the correct signal number.\n")); detach_breakpoints (ecs->ws.value.related_pid); } - if (singlestep_breakpoints_inserted_p) - { - /* Pull the single step breakpoints out of the target. */ - remove_single_step_breakpoints (); - singlestep_breakpoints_inserted_p = 0; - } + delete_just_stopped_threads_single_step_breakpoints (); /* In case the event is caught by a catchpoint, remember that the event is to be followed at the next resume of the thread, @@ -3651,7 +4112,7 @@ Cannot fill $_exitsignal with the correct signal number.\n")); if (should_resume) keep_going (ecs); else - stop_stepping (ecs); + stop_waiting (ecs); return; } process_event_stop_test (ecs); @@ -3682,9 +4143,6 @@ Cannot fill $_exitsignal with the correct signal number.\n")); if (!ptid_equal (ecs->ptid, inferior_ptid)) context_switch (ecs->ptid); - singlestep_breakpoints_inserted_p = 0; - cancel_single_step_breakpoints (); - stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); /* Do whatever is necessary to the parent branch of the vfork. */ @@ -3750,17 +4208,10 @@ 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. */ - /* Pull the single step breakpoints out of the target. */ - if (singlestep_breakpoints_inserted_p) - { - if (!ptid_equal (ecs->ptid, inferior_ptid)) - context_switch (ecs->ptid); - remove_single_step_breakpoints (); - singlestep_breakpoints_inserted_p = 0; - } + delete_just_stopped_threads_single_step_breakpoints (); stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); - print_no_history_reason (); - stop_stepping (ecs); + observer_notify_no_history (); + stop_waiting (ecs); return; } } @@ -3776,22 +4227,20 @@ handle_signal_stop (struct execution_control_state *ecs) enum stop_kind stop_soon; int random_signal; - if (ecs->ws.kind == TARGET_WAITKIND_STOPPED) - { - /* 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); + gdb_assert (ecs->ws.kind == TARGET_WAITKIND_STOPPED); - /* If we either finished a single-step or hit a breakpoint, but - the user wanted this thread to be stopped, pretend we got a - SIG0 (generic unsignaled stop). */ + /* 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 (ecs->event_thread->stop_requested - && ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP) - ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0; - } + /* If we either finished a single-step or hit a breakpoint, but + the user wanted this thread to be stopped, pretend we got a + SIG0 (generic unsignaled stop). */ + if (ecs->event_thread->stop_requested + && ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP) + ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0; stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); @@ -3833,7 +4282,7 @@ handle_signal_stop (struct execution_control_state *ecs) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n"); stop_print_frame = 1; - stop_stepping (ecs); + stop_waiting (ecs); return; } @@ -3845,7 +4294,7 @@ handle_signal_stop (struct execution_control_state *ecs) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n"); stop_print_frame = 0; - stop_stepping (ecs); + stop_waiting (ecs); return; } @@ -3875,226 +4324,11 @@ handle_signal_stop (struct execution_control_state *ecs) || ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_0)) { stop_print_frame = 1; - stop_stepping (ecs); + stop_waiting (ecs); ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0; return; } - if (stepping_past_singlestep_breakpoint) - { - gdb_assert (singlestep_breakpoints_inserted_p); - gdb_assert (ptid_equal (singlestep_ptid, ecs->ptid)); - gdb_assert (!ptid_equal (singlestep_ptid, saved_singlestep_ptid)); - - stepping_past_singlestep_breakpoint = 0; - - /* We've either finished single-stepping past the single-step - breakpoint, or stopped for some other reason. It would be nice if - we could tell, but we can't reliably. */ - if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP) - { - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: stepping_past_" - "singlestep_breakpoint\n"); - /* Pull the single step breakpoints out of the target. */ - if (!ptid_equal (ecs->ptid, inferior_ptid)) - context_switch (ecs->ptid); - remove_single_step_breakpoints (); - singlestep_breakpoints_inserted_p = 0; - - ecs->event_thread->control.trap_expected = 0; - - context_switch (saved_singlestep_ptid); - if (deprecated_context_hook) - deprecated_context_hook (pid_to_thread_id (saved_singlestep_ptid)); - - resume (1, GDB_SIGNAL_0); - prepare_to_wait (ecs); - return; - } - } - - if (!ptid_equal (deferred_step_ptid, null_ptid)) - { - /* In non-stop mode, there's never a deferred_step_ptid set. */ - gdb_assert (!non_stop); - - /* If we stopped for some other reason than single-stepping, ignore - the fact that we were supposed to switch back. */ - if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP) - { - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: handling deferred step\n"); - - /* Pull the single step breakpoints out of the target. */ - if (singlestep_breakpoints_inserted_p) - { - if (!ptid_equal (ecs->ptid, inferior_ptid)) - context_switch (ecs->ptid); - remove_single_step_breakpoints (); - singlestep_breakpoints_inserted_p = 0; - } - - ecs->event_thread->control.trap_expected = 0; - - context_switch (deferred_step_ptid); - deferred_step_ptid = null_ptid; - /* Suppress spurious "Switching to ..." message. */ - previous_inferior_ptid = inferior_ptid; - - resume (1, GDB_SIGNAL_0); - prepare_to_wait (ecs); - return; - } - - deferred_step_ptid = null_ptid; - } - - /* See if a thread hit a thread-specific breakpoint that was meant for - another thread. If so, then step that thread past the breakpoint, - and continue it. */ - - if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP) - { - int thread_hop_needed = 0; - struct address_space *aspace = - get_regcache_aspace (get_thread_regcache (ecs->ptid)); - - /* Check if a regular breakpoint has been hit before checking - for a potential single step breakpoint. Otherwise, GDB will - not see this breakpoint hit when stepping onto breakpoints. */ - if (regular_breakpoint_inserted_here_p (aspace, stop_pc)) - { - if (!breakpoint_thread_match (aspace, stop_pc, ecs->ptid)) - thread_hop_needed = 1; - } - else if (singlestep_breakpoints_inserted_p) - { - /* We have not context switched yet, so this should be true - no matter which thread hit the singlestep breakpoint. */ - gdb_assert (ptid_equal (inferior_ptid, singlestep_ptid)); - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: software single step " - "trap for %s\n", - target_pid_to_str (ecs->ptid)); - - /* The call to in_thread_list is necessary because PTIDs sometimes - change when we go from single-threaded to multi-threaded. If - the singlestep_ptid is still in the list, assume that it is - really different from ecs->ptid. */ - if (!ptid_equal (singlestep_ptid, ecs->ptid) - && in_thread_list (singlestep_ptid)) - { - /* If the PC of the thread we were trying to single-step - has changed, discard this event (which we were going - to ignore anyway), and pretend we saw that thread - trap. This prevents us continuously moving the - single-step breakpoint forward, one instruction at a - time. If the PC has changed, then the thread we were - trying to single-step has trapped or been signalled, - but the event has not been reported to GDB yet. - - There might be some cases where this loses signal - information, if a signal has arrived at exactly the - same time that the PC changed, but this is the best - we can do with the information available. Perhaps we - should arrange to report all events for all threads - when they stop, or to re-poll the remote looking for - this particular thread (i.e. temporarily enable - schedlock). */ - - CORE_ADDR new_singlestep_pc - = regcache_read_pc (get_thread_regcache (singlestep_ptid)); - - if (new_singlestep_pc != singlestep_pc) - { - enum gdb_signal stop_signal; - - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: unexpected thread," - " but expected thread advanced also\n"); - - /* The current context still belongs to - singlestep_ptid. Don't swap here, since that's - the context we want to use. Just fudge our - state and continue. */ - stop_signal = ecs->event_thread->suspend.stop_signal; - ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0; - ecs->ptid = singlestep_ptid; - ecs->event_thread = find_thread_ptid (ecs->ptid); - ecs->event_thread->suspend.stop_signal = stop_signal; - stop_pc = new_singlestep_pc; - } - else - { - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: unexpected thread\n"); - - thread_hop_needed = 1; - stepping_past_singlestep_breakpoint = 1; - saved_singlestep_ptid = singlestep_ptid; - } - } - } - - if (thread_hop_needed) - { - struct regcache *thread_regcache; - int remove_status = 0; - - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: thread_hop_needed\n"); - - /* Switch context before touching inferior memory, the - previous thread may have exited. */ - if (!ptid_equal (inferior_ptid, ecs->ptid)) - context_switch (ecs->ptid); - - /* Saw a breakpoint, but it was hit by the wrong thread. - Just continue. */ - - if (singlestep_breakpoints_inserted_p) - { - /* Pull the single step breakpoints out of the target. */ - remove_single_step_breakpoints (); - singlestep_breakpoints_inserted_p = 0; - } - - /* If the arch can displace step, don't remove the - breakpoints. */ - thread_regcache = get_thread_regcache (ecs->ptid); - if (!use_displaced_stepping (get_regcache_arch (thread_regcache))) - remove_status = remove_breakpoints (); - - /* Did we fail to remove breakpoints? If so, try - to set the PC past the bp. (There's at least - one situation in which we can fail to remove - the bp's: On HP-UX's that use ttrace, we can't - change the address space of a vforking child - process until the child exits (well, okay, not - then either :-) or execs. */ - if (remove_status != 0) - error (_("Cannot step over breakpoint hit in wrong thread")); - else - { /* Single step */ - if (!non_stop) - { - /* Only need to require the next event from this - thread in all-stop mode. */ - waiton_ptid = ecs->ptid; - infwait_state = infwait_thread_hop_state; - } - - ecs->event_thread->stepping_over_breakpoint = 1; - keep_going (ecs); - return; - } - } - } - /* See if something interesting happened to the non-current thread. If so, then switch to that thread. */ if (!ptid_equal (ecs->ptid, inferior_ptid)) @@ -4112,14 +4346,51 @@ handle_signal_stop (struct execution_control_state *ecs) frame = get_current_frame (); gdbarch = get_frame_arch (frame); - if (singlestep_breakpoints_inserted_p) + /* Pull the single step breakpoints out of the target. */ + if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP) { - /* Pull the single step breakpoints out of the target. */ - remove_single_step_breakpoints (); - singlestep_breakpoints_inserted_p = 0; + struct regcache *regcache; + struct address_space *aspace; + CORE_ADDR pc; + + regcache = get_thread_regcache (ecs->ptid); + aspace = get_regcache_aspace (regcache); + pc = regcache_read_pc (regcache); + + /* However, before doing so, if this single-step breakpoint was + actually for another thread, set this thread up for moving + past it. */ + if (!thread_has_single_step_breakpoint_here (ecs->event_thread, + aspace, pc)) + { + if (single_step_breakpoint_inserted_here_p (aspace, pc)) + { + if (debug_infrun) + { + fprintf_unfiltered (gdb_stdlog, + "infrun: [%s] hit another thread's " + "single-step breakpoint\n", + target_pid_to_str (ecs->ptid)); + } + ecs->hit_singlestep_breakpoint = 1; + } + } + else + { + if (debug_infrun) + { + fprintf_unfiltered (gdb_stdlog, + "infrun: [%s] hit its " + "single-step breakpoint\n", + target_pid_to_str (ecs->ptid)); + } + } } + delete_just_stopped_threads_single_step_breakpoints (); - if (ecs->stepped_after_stopped_by_watchpoint) + if (ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP + && ecs->event_thread->control.trap_expected + && ecs->event_thread->stepping_over_watchpoint) stopped_by_watchpoint = 0; else stopped_by_watchpoint = watchpoints_triggered (&ecs->ws); @@ -4142,36 +4413,28 @@ handle_signal_stop (struct execution_control_state *ecs) watchpoint expression. We do this by single-stepping the target. - It may not be necessary to disable the watchpoint to stop over + It may not be necessary to disable the watchpoint to step over it. For example, the PA can (with some kernel cooperation) single step over a watchpoint without disabling the watchpoint. It is far more common to need to disable a watchpoint to step the inferior over it. If we have non-steppable watchpoints, we must disable the current watchpoint; it's simplest to - disable all watchpoints and breakpoints. */ - int hw_step = 1; - - if (!target_have_steppable_watchpoint) - { - remove_breakpoints (); - /* See comment in resume why we need to stop bypassing signals - while breakpoints have been removed. */ - target_pass_signals (0, NULL); - } - /* Single step */ - hw_step = maybe_software_singlestep (gdbarch, stop_pc); - target_resume (ecs->ptid, hw_step, GDB_SIGNAL_0); - waiton_ptid = ecs->ptid; - if (target_have_steppable_watchpoint) - infwait_state = infwait_step_watch_state; - else - infwait_state = infwait_nonstep_watch_state; - prepare_to_wait (ecs); + disable all watchpoints. + + Any breakpoint at PC must also be stepped over -- if there's + one, it will have already triggered before the watchpoint + triggered, and we either already reported it to the user, or + it didn't cause a stop and we called keep_going. In either + case, if there was a breakpoint at PC, we must be trying to + step past it. */ + ecs->event_thread->stepping_over_watchpoint = 1; + keep_going (ecs); return; } ecs->event_thread->stepping_over_breakpoint = 0; + ecs->event_thread->stepping_over_watchpoint = 0; bpstat_clear (&ecs->event_thread->control.stop_bpstat); ecs->event_thread->control.stop_step = 0; stop_print_frame = 1; @@ -4304,11 +4567,65 @@ handle_signal_stop (struct execution_control_state *ecs) = !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat, ecs->event_thread->suspend.stop_signal); + /* Maybe this was a trap for a software breakpoint that has since + been removed. */ + if (random_signal && target_stopped_by_sw_breakpoint ()) + { + if (program_breakpoint_here_p (gdbarch, stop_pc)) + { + struct regcache *regcache; + int decr_pc; + + /* Re-adjust PC to what the program would see if GDB was not + debugging it. */ + regcache = get_thread_regcache (ecs->event_thread->ptid); + decr_pc = gdbarch_decr_pc_after_break (gdbarch); + if (decr_pc != 0) + { + struct cleanup *old_cleanups = make_cleanup (null_cleanup, NULL); + + if (record_full_is_used ()) + record_full_gdb_operation_disable_set (); + + regcache_write_pc (regcache, stop_pc + decr_pc); + + do_cleanups (old_cleanups); + } + } + else + { + /* A delayed software breakpoint event. Ignore the trap. */ + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: delayed software breakpoint " + "trap, ignoring\n"); + random_signal = 0; + } + } + + /* Maybe this was a trap for a hardware breakpoint/watchpoint that + has since been removed. */ + if (random_signal && target_stopped_by_hw_breakpoint ()) + { + /* A delayed hardware breakpoint event. Ignore the trap. */ + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: delayed hardware breakpoint/watchpoint " + "trap, ignoring\n"); + random_signal = 0; + } + /* If not, perhaps stepping/nexting can. */ if (random_signal) random_signal = !(ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP && currently_stepping (ecs->event_thread)); + /* Perhaps the thread hit a single-step breakpoint of _another_ + thread. Single-step breakpoints are transparent to the + breakpoints module. */ + if (random_signal) + random_signal = !ecs->hit_singlestep_breakpoint; + /* No? Perhaps we got a moribund watchpoint. */ if (random_signal) random_signal = !stopped_by_watchpoint; @@ -4319,8 +4636,7 @@ handle_signal_stop (struct execution_control_state *ecs) if (random_signal) { /* Signal not for debugging purposes. */ - int printed = 0; - struct inferior *inf = find_inferior_pid (ptid_get_pid (ecs->ptid)); + struct inferior *inf = find_inferior_ptid (ecs->ptid); enum gdb_signal stop_signal = ecs->event_thread->suspend.stop_signal; if (debug_infrun) @@ -4329,13 +4645,6 @@ handle_signal_stop (struct execution_control_state *ecs) stopped_by_random_signal = 1; - if (signal_print[ecs->event_thread->suspend.stop_signal]) - { - printed = 1; - target_terminal_ours_for_output (); - print_signal_received_reason - (ecs->event_thread->suspend.stop_signal); - } /* Always stop on signals if we're either just gaining control of the program, or the user explicitly requested this thread to remain stopped. */ @@ -4344,13 +4653,20 @@ handle_signal_stop (struct execution_control_state *ecs) || (!inf->detaching && signal_stop_state (ecs->event_thread->suspend.stop_signal))) { - stop_stepping (ecs); + stop_waiting (ecs); return; } - /* If not going to stop, give terminal back - if we took it away. */ - else if (printed) - target_terminal_inferior (); + + /* Notify observers the signal has "handle print" set. Note we + returned early above if stopping; normal_stop handles the + printing in that case. */ + if (signal_print[ecs->event_thread->suspend.stop_signal]) + { + /* The signal table tells us to print about this signal. */ + target_terminal_ours_for_output (); + observer_notify_signal_received (ecs->event_thread->suspend.stop_signal); + target_terminal_inferior (); + } /* Clear the signal if it should not be passed. */ if (signal_program[ecs->event_thread->suspend.stop_signal] == 0) @@ -4379,13 +4695,17 @@ handle_signal_stop (struct execution_control_state *ecs) 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; - keep_going (ecs); + + /* 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)) + keep_going (ecs); return; } - if (ecs->event_thread->control.step_range_end != 0 - && ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_0 - && pc_in_thread_step_range (stop_pc, ecs->event_thread) + if (ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_0 + && (pc_in_thread_step_range (stop_pc, ecs->event_thread) + || ecs->event_thread->control.step_range_end == 1) && frame_id_eq (get_stack_frame_id (frame), ecs->event_thread->control.step_stack_frame_id) && ecs->event_thread->control.step_resume_breakpoint == NULL) @@ -4405,6 +4725,7 @@ handle_signal_stop (struct execution_control_state *ecs) "single-step range\n"); 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; keep_going (ecs); @@ -4487,7 +4808,10 @@ process_event_stop_test (struct execution_control_state *ecs) is the third argument to the probe. */ arg_value = probe_safe_evaluate_at_pc (frame, 2); if (arg_value) - jmp_buf_pc = value_as_address (arg_value); + { + jmp_buf_pc = value_as_address (arg_value); + jmp_buf_pc = gdbarch_addr_bits_remove (gdbarch, jmp_buf_pc); + } else if (!gdbarch_get_longjmp_target_p (gdbarch) || !gdbarch_get_longjmp_target (gdbarch, frame, &jmp_buf_pc)) @@ -4540,7 +4864,7 @@ process_event_stop_test (struct execution_control_state *ecs) if (what.is_longjmp) { - check_longjmp_breakpoint_for_call_dummy (ecs->event_thread->num); + check_longjmp_breakpoint_for_call_dummy (ecs->event_thread); if (!frame_id_p (ecs->event_thread->initiating_frame)) { @@ -4573,9 +4897,7 @@ process_event_stop_test (struct execution_control_state *ecs) exists. */ delete_step_resume_breakpoint (ecs->event_thread); - ecs->event_thread->control.stop_step = 1; - print_end_stepping_range_reason (); - stop_stepping (ecs); + end_stepping_range (ecs); } return; @@ -4625,10 +4947,12 @@ process_event_stop_test (struct execution_control_state *ecs) fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_NOISY\n"); stop_print_frame = 1; - /* We are about to nuke the step_resume_breakpointt via the - cleanup chain, so no need to worry about it here. */ + /* Assume the thread stopped for a breapoint. We'll still check + whether a/the breakpoint is there when the thread is next + resumed. */ + ecs->event_thread->stepping_over_breakpoint = 1; - stop_stepping (ecs); + stop_waiting (ecs); return; case BPSTAT_WHAT_STOP_SILENT: @@ -4636,10 +4960,11 @@ process_event_stop_test (struct execution_control_state *ecs) fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_SILENT\n"); stop_print_frame = 0; - /* We are about to nuke the step_resume_breakpoin via the - cleanup chain, so no need to worry about it here. */ - - stop_stepping (ecs); + /* Assume the thread stopped for a breapoint. We'll still check + whether a/the breakpoint is there when the thread is next + resumed. */ + ecs->event_thread->stepping_over_breakpoint = 1; + stop_waiting (ecs); return; case BPSTAT_WHAT_HP_STEP_RESUME: @@ -4663,6 +4988,31 @@ process_event_stop_test (struct execution_control_state *ecs) break; } + /* If we stepped a permanent breakpoint and we had a high priority + step-resume breakpoint for the address we stepped, but we didn't + hit it, then we must have stepped into the signal handler. The + step-resume was only necessary to catch the case of _not_ + stepping into the handler, so delete it, and fall through to + checking whether the step finished. */ + if (ecs->event_thread->stepped_breakpoint) + { + struct breakpoint *sr_bp + = ecs->event_thread->control.step_resume_breakpoint; + + if (sr_bp != NULL + && sr_bp->loc->permanent + && sr_bp->type == bp_hp_step_resume + && sr_bp->loc->address == ecs->event_thread->prev_pc) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: stepped permanent breakpoint, stopped in " + "handler\n"); + delete_step_resume_breakpoint (ecs->event_thread); + ecs->event_thread->step_after_step_resume_breakpoint = 0; + } + } + /* We come here if we hit a breakpoint but should not stop for it. Possibly we also were stepping and should stop for that. So fall through and test for stepping. But, if not stepping, do not @@ -4734,11 +5084,7 @@ process_event_stop_test (struct execution_control_state *ecs) if (stop_pc == ecs->event_thread->control.step_range_start && stop_pc != ecs->stop_func_start && execution_direction == EXEC_REVERSE) - { - ecs->event_thread->control.stop_step = 1; - print_end_stepping_range_reason (); - stop_stepping (ecs); - } + end_stepping_range (ecs); else keep_going (ecs); @@ -4870,28 +5216,21 @@ process_event_stop_test (struct execution_control_state *ecs) ecs->event_thread->control.step_stack_frame_id) && (!frame_id_eq (ecs->event_thread->control.step_stack_frame_id, outer_frame_id) - || step_start_function != find_pc_function (stop_pc)))) + || (ecs->event_thread->control.step_start_function + != find_pc_function (stop_pc))))) { CORE_ADDR real_stop_pc; if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: stepped into subroutine\n"); - if ((ecs->event_thread->control.step_over_calls == STEP_OVER_NONE) - || ((ecs->event_thread->control.step_range_end == 1) - && in_prologue (gdbarch, ecs->event_thread->prev_pc, - ecs->stop_func_start))) + if (ecs->event_thread->control.step_over_calls == STEP_OVER_NONE) { /* I presume that step_over_calls is only 0 when we're supposed to be stepping at the assembly language level ("stepi"). Just stop. */ - /* Also, maybe we just did a "nexti" inside a prolog, so we - thought it was a subroutine call but it was not. Stop as - well. FENN */ /* And this works the same backward as frontward. MVS */ - ecs->event_thread->control.stop_step = 1; - print_end_stepping_range_reason (); - stop_stepping (ecs); + end_stepping_range (ecs); return; } @@ -5005,9 +5344,7 @@ process_event_stop_test (struct execution_control_state *ecs) if (ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE && step_stop_if_no_debug) { - ecs->event_thread->control.stop_step = 1; - print_end_stepping_range_reason (); - stop_stepping (ecs); + end_stepping_range (ecs); return; } @@ -5101,9 +5438,7 @@ process_event_stop_test (struct execution_control_state *ecs) /* If we have no line number and the step-stop-if-no-debug is set, we stop the step so that the user has a chance to switch in assembly mode. */ - ecs->event_thread->control.stop_step = 1; - print_end_stepping_range_reason (); - stop_stepping (ecs); + end_stepping_range (ecs); return; } else @@ -5122,9 +5457,7 @@ process_event_stop_test (struct execution_control_state *ecs) one instruction. */ if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: stepi/nexti\n"); - ecs->event_thread->control.stop_step = 1; - print_end_stepping_range_reason (); - stop_stepping (ecs); + end_stepping_range (ecs); return; } @@ -5136,9 +5469,7 @@ process_event_stop_test (struct execution_control_state *ecs) or can this happen as a result of a return or longjmp?). */ if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: no line number info\n"); - ecs->event_thread->control.stop_step = 1; - print_end_stepping_range_reason (); - stop_stepping (ecs); + end_stepping_range (ecs); return; } @@ -5169,9 +5500,7 @@ process_event_stop_test (struct execution_control_state *ecs) && call_sal.symtab == ecs->event_thread->current_symtab) step_into_inline_frame (ecs->ptid); - ecs->event_thread->control.stop_step = 1; - print_end_stepping_range_reason (); - stop_stepping (ecs); + end_stepping_range (ecs); return; } else @@ -5183,11 +5512,7 @@ process_event_stop_test (struct execution_control_state *ecs) && call_sal.symtab == ecs->event_thread->current_symtab) keep_going (ecs); else - { - ecs->event_thread->control.stop_step = 1; - print_end_stepping_range_reason (); - stop_stepping (ecs); - } + end_stepping_range (ecs); return; } } @@ -5210,11 +5535,7 @@ process_event_stop_test (struct execution_control_state *ecs) if (ecs->event_thread->control.step_over_calls == STEP_OVER_ALL) keep_going (ecs); else - { - ecs->event_thread->control.stop_step = 1; - print_end_stepping_range_reason (); - stop_stepping (ecs); - } + end_stepping_range (ecs); return; } @@ -5229,9 +5550,7 @@ process_event_stop_test (struct execution_control_state *ecs) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: stepped to a different line\n"); - ecs->event_thread->control.stop_step = 1; - print_end_stepping_range_reason (); - stop_stepping (ecs); + end_stepping_range (ecs); return; } @@ -5263,22 +5582,144 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) if (!non_stop) { 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 + again, do that first. */ + + /* However, if we see an event for the stepping thread, then we + know all other threads have been moved past their breakpoints + already. Let the caller check whether the step is finished, + etc., before deciding to move it past a breakpoint. */ + if (ecs->event_thread->control.step_range_end != 0) + return 0; + + /* Check if the current thread is blocked on an incomplete + step-over, interrupted by a random signal. */ + if (ecs->event_thread->control.trap_expected + && ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_TRAP) + { + if (debug_infrun) + { + fprintf_unfiltered (gdb_stdlog, + "infrun: need to finish step-over of [%s]\n", + target_pid_to_str (ecs->event_thread->ptid)); + } + keep_going (ecs); + return 1; + } + + /* Check if the current thread is blocked by a single-step + breakpoint of another thread. */ + if (ecs->hit_singlestep_breakpoint) + { + if (debug_infrun) + { + fprintf_unfiltered (gdb_stdlog, + "infrun: need to step [%s] over single-step " + "breakpoint\n", + target_pid_to_str (ecs->ptid)); + } + keep_going (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 scheduler locking applies even if not stepping, there's no + need to walk over threads. Above we've checked whether the + current thread is stepping. If some other thread not the + event thread is stepping, then it must be that scheduler + locking is not in effect. */ + 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 + step/next/etc. */ + stepping_thread = NULL; + step_over = NULL; + ALL_NON_EXITED_THREADS (tp) + { + /* Ignore threads of processes we're not resuming. */ + if (!sched_multi + && ptid_get_pid (tp->ptid) != ptid_get_pid (inferior_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); + + /* Did we find the stepping thread? */ + if (tp->control.step_range_end) + { + /* Yep. There should only one though. */ + gdb_assert (stepping_thread == NULL); + + /* The event thread is handled at the top, before we + enter this loop. */ + gdb_assert (tp != ecs->event_thread); + + /* If some thread other than the event thread is + stepping, then scheduler locking can't be in effect, + otherwise we wouldn't have resumed the current event + thread in the first place. */ + gdb_assert (!schedlock_applies (tp)); + + 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; + } + } - tp = iterate_over_threads (currently_stepping_or_nexting_callback, - ecs->event_thread); - if (tp) + if (step_over != NULL) { - /* However, if the current thread is blocked on some internal - breakpoint, and we simply need to step over that breakpoint - to get it going again, do that first. */ - if ((ecs->event_thread->control.trap_expected - && ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_TRAP) - || ecs->event_thread->stepping_over_breakpoint) + tp = step_over; + if (debug_infrun) { - keep_going (ecs); - return 1; + fprintf_unfiltered (gdb_stdlog, + "infrun: need to step-over [%s]\n", + target_pid_to_str (tp->ptid)); } + /* Only the stepping thread should have this set. */ + gdb_assert (tp->control.step_range_end == 0); + + ecs->ptid = tp->ptid; + ecs->event_thread = tp; + switch_to_thread (ecs->ptid); + keep_going (ecs); + return 1; + } + + if (stepping_thread != NULL) + { + struct frame_info *frame; + struct gdbarch *gdbarch; + + 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. @@ -5311,11 +5752,6 @@ 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 would do as well, if we called it. */ - ecs->event_thread->control.trap_expected = 0; - if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: switching back to stepped thread\n"); @@ -5323,7 +5759,59 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) ecs->event_thread = tp; ecs->ptid = tp->ptid; context_switch (ecs->ptid); - keep_going (ecs); + + stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid)); + frame = get_current_frame (); + gdbarch = get_frame_arch (frame); + + /* 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: + + - setting a break at the current PC + - resuming that particular thread, only (by setting + trap expected) + + This prevents us continuously moving the single-step + breakpoint forward, one instruction at a time, + overstepping. */ + + if (stop_pc != tp->prev_pc) + { + ptid_t resume_ptid; + + 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); + } + return 1; } } @@ -5338,22 +5826,10 @@ currently_stepping (struct thread_info *tp) return ((tp->control.step_range_end && tp->control.step_resume_breakpoint == NULL) || tp->control.trap_expected + || tp->stepped_breakpoint || bpstat_should_step ()); } -/* Returns true if any thread *but* the one passed in "data" is in the - middle of stepping or of handling a "next". */ - -static int -currently_stepping_or_nexting_callback (struct thread_info *tp, void *data) -{ - if (tp == data) - return 0; - - return (tp->control.step_range_end - || tp->control.trap_expected); -} - /* Inferior has stepped into a subroutine call with source code that we should not step over. Do step to the first line of code in it. */ @@ -5362,13 +5838,13 @@ static void handle_step_into_function (struct gdbarch *gdbarch, struct execution_control_state *ecs) { - struct symtab *s; + struct compunit_symtab *cust; struct symtab_and_line stop_func_sal, sr_sal; fill_in_stop_func (gdbarch, ecs); - s = find_pc_symtab (stop_pc); - if (s && s->language != language_asm) + cust = find_pc_compunit_symtab (stop_pc); + if (cust != NULL && compunit_language (cust) != language_asm) ecs->stop_func_start = gdbarch_skip_prologue (gdbarch, ecs->stop_func_start); @@ -5410,9 +5886,7 @@ handle_step_into_function (struct gdbarch *gdbarch, if (ecs->stop_func_start == stop_pc) { /* We are already there: stop now. */ - ecs->event_thread->control.stop_step = 1; - print_end_stepping_range_reason (); - stop_stepping (ecs); + end_stepping_range (ecs); return; } else @@ -5443,13 +5917,13 @@ static void handle_step_into_function_backward (struct gdbarch *gdbarch, struct execution_control_state *ecs) { - struct symtab *s; + struct compunit_symtab *cust; struct symtab_and_line stop_func_sal; fill_in_stop_func (gdbarch, ecs); - s = find_pc_symtab (stop_pc); - if (s && s->language != language_asm) + cust = find_pc_compunit_symtab (stop_pc); + if (cust != NULL && compunit_language (cust) != language_asm) ecs->stop_func_start = gdbarch_skip_prologue (gdbarch, ecs->stop_func_start); @@ -5459,9 +5933,7 @@ handle_step_into_function_backward (struct gdbarch *gdbarch, if (stop_func_sal.pc == stop_pc) { /* We're there already. Just stop stepping now. */ - ecs->event_thread->control.stop_step = 1; - print_end_stepping_range_reason (); - stop_stepping (ecs); + end_stepping_range (ecs); } else { @@ -5601,14 +6073,11 @@ insert_longjmp_resume_breakpoint (struct gdbarch *gdbarch, CORE_ADDR pc) static void insert_exception_resume_breakpoint (struct thread_info *tp, - struct block *b, + const struct block *b, struct frame_info *frame, struct symbol *sym) { - volatile struct gdb_exception e; - - /* We want to ignore errors here. */ - TRY_CATCH (e, RETURN_MASK_ERROR) + TRY { struct symbol *vsym; struct value *value; @@ -5637,6 +6106,11 @@ insert_exception_resume_breakpoint (struct thread_info *tp, inferior_thread ()->control.exception_resume_breakpoint = bp; } } + CATCH (e, RETURN_MASK_ERROR) + { + /* We want to ignore errors here. */ + } + END_CATCH } /* A helper for check_exception_resume that sets an @@ -5644,7 +6118,7 @@ insert_exception_resume_breakpoint (struct thread_info *tp, static void insert_exception_resume_from_probe (struct thread_info *tp, - const struct probe *probe, + const struct bound_probe *probe, struct frame_info *frame) { struct value *arg_value; @@ -5677,8 +6151,7 @@ static void check_exception_resume (struct execution_control_state *ecs, struct frame_info *frame) { - volatile struct gdb_exception e; - const struct probe *probe; + struct bound_probe probe; struct symbol *func; /* First see if this exception unwinding breakpoint was set via a @@ -5686,9 +6159,9 @@ check_exception_resume (struct execution_control_state *ecs, CFA and the HANDLER. We ignore the CFA, extract the handler, and set a breakpoint there. */ probe = find_probe_by_pc (get_frame_pc (frame)); - if (probe) + if (probe.probe) { - insert_exception_resume_from_probe (ecs->event_thread, probe, frame); + insert_exception_resume_from_probe (ecs->event_thread, &probe, frame); return; } @@ -5696,9 +6169,9 @@ check_exception_resume (struct execution_control_state *ecs, if (!func) return; - TRY_CATCH (e, RETURN_MASK_ERROR) + TRY { - struct block *b; + const struct block *b; struct block_iterator iter; struct symbol *sym; int argno = 0; @@ -5733,13 +6206,19 @@ check_exception_resume (struct execution_control_state *ecs, } } } + CATCH (e, RETURN_MASK_ERROR) + { + } + END_CATCH } static void -stop_stepping (struct execution_control_state *ecs) +stop_waiting (struct execution_control_state *ecs) { if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: stop_stepping\n"); + fprintf_unfiltered (gdb_stdlog, "infrun: stop_waiting\n"); + + clear_step_over_info (); /* Let callers know we don't want to wait for the inferior anymore. */ ecs->wait_some_more = 0; @@ -5768,11 +6247,14 @@ keep_going (struct execution_control_state *ecs) are supposed to pass through to the inferior. Simply continue. */ discard_cleanups (old_cleanups); - resume (currently_stepping (ecs->event_thread), - ecs->event_thread->suspend.stop_signal); + resume (ecs->event_thread->suspend.stop_signal); } else { + struct regcache *regcache = get_current_regcache (); + int remove_bp; + int remove_wps; + /* Either the trap was not expected, but we are continuing anyway (if we got a signal, the user asked it be passed to the child) @@ -5786,37 +6268,47 @@ keep_going (struct execution_control_state *ecs) already inserted breakpoints. Therefore, we don't care if breakpoints were already inserted, or not. */ - if (ecs->event_thread->stepping_over_breakpoint) + /* 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. */ + + 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); + + /* 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)))) { - struct regcache *thread_regcache = get_thread_regcache (ecs->ptid); - - if (!use_displaced_stepping (get_regcache_arch (thread_regcache))) - { - /* Since we can't do a displaced step, we have to remove - the breakpoint while we step it. To keep things - simple, we remove them all. */ - remove_breakpoints (); - } + set_step_over_info (get_regcache_aspace (regcache), + regcache_read_pc (regcache), remove_wps); } + else if (remove_wps) + set_step_over_info (NULL, 0, remove_wps); else - { - volatile struct gdb_exception e; + clear_step_over_info (); - /* Stop stepping if inserting breakpoints fails. */ - TRY_CATCH (e, RETURN_MASK_ERROR) - { - insert_breakpoints (); - } - if (e.reason < 0) - { - exception_print (gdb_stderr, e); - stop_stepping (ecs); - return; - } + /* Stop stepping if inserting breakpoints fails. */ + TRY + { + insert_breakpoints (); + } + CATCH (e, RETURN_MASK_ERROR) + { + exception_print (gdb_stderr, e); + stop_waiting (ecs); + discard_cleanups (old_cleanups); + return; } + END_CATCH - ecs->event_thread->control.trap_expected - = ecs->event_thread->stepping_over_breakpoint; + 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 @@ -5833,8 +6325,7 @@ keep_going (struct execution_control_state *ecs) ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0; discard_cleanups (old_cleanups); - resume (currently_stepping (ecs->event_thread), - ecs->event_thread->suspend.stop_signal); + resume (ecs->event_thread->suspend.stop_signal); } prepare_to_wait (ecs); @@ -5856,35 +6347,42 @@ prepare_to_wait (struct execution_control_state *ecs) ecs->wait_some_more = 1; } +/* We are done with the step range of a step/next/si/ni command. + Called once for each n of a "step n" operation. */ + +static void +end_stepping_range (struct execution_control_state *ecs) +{ + ecs->event_thread->control.stop_step = 1; + stop_waiting (ecs); +} + /* Several print_*_reason functions to print why the inferior has stopped. We always print something when the inferior exits, or receives a signal. The rest of the cases are dealt with later on in normal_stop and print_it_typical. Ideally there should be a call to one of these print_*_reason functions functions from handle_inferior_event each time - stop_stepping is called. */ + stop_waiting is called. -/* Print why the inferior has stopped. - We are done with a step/next/si/ni command, print why the inferior has - stopped. For now print nothing. Print a message only if not in the middle - of doing a "step n" operation for n > 1. */ + Note that we don't call these directly, instead we delegate that to + the interpreters, through observers. Interpreters then call these + with whatever uiout is right. */ -static void -print_end_stepping_range_reason (void) +void +print_end_stepping_range_reason (struct ui_out *uiout) { - if ((!inferior_thread ()->step_multi - || !inferior_thread ()->control.stop_step) - && ui_out_is_mi_like_p (current_uiout)) - ui_out_field_string (current_uiout, "reason", - async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE)); -} + /* For CLI-like interpreters, print nothing. */ -/* The inferior was terminated by a signal, print why it stopped. */ + if (ui_out_is_mi_like_p (uiout)) + { + ui_out_field_string (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE)); + } +} -static void -print_signal_exited_reason (enum gdb_signal siggnal) +void +print_signal_exited_reason (struct ui_out *uiout, enum gdb_signal siggnal) { - struct ui_out *uiout = current_uiout; - annotate_signalled (); if (ui_out_is_mi_like_p (uiout)) ui_out_field_string @@ -5903,14 +6401,11 @@ print_signal_exited_reason (enum gdb_signal siggnal) ui_out_text (uiout, "The program no longer exists.\n"); } -/* The inferior program is finished, print why it stopped. */ - -static void -print_exited_reason (int exitstatus) +void +print_exited_reason (struct ui_out *uiout, int exitstatus) { struct inferior *inf = current_inferior (); const char *pidstr = target_pid_to_str (pid_to_ptid (inf->pid)); - struct ui_out *uiout = current_uiout; annotate_exited (exitstatus); if (exitstatus) @@ -5937,18 +6432,11 @@ print_exited_reason (int exitstatus) ui_out_text (uiout, pidstr); ui_out_text (uiout, ") exited normally]\n"); } - /* Support the --return-child-result option. */ - return_child_result_value = exitstatus; } -/* Signal received, print why the inferior has stopped. The signal table - tells us to print about it. */ - -static void -print_signal_received_reason (enum gdb_signal siggnal) +void +print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal) { - struct ui_out *uiout = current_uiout; - annotate_signal (); if (siggnal == GDB_SIGNAL_0 && !ui_out_is_mi_like_p (uiout)) @@ -5980,13 +6468,72 @@ print_signal_received_reason (enum gdb_signal siggnal) ui_out_text (uiout, ".\n"); } -/* Reverse execution: target ran out of history info, print why the inferior - has stopped. */ +void +print_no_history_reason (struct ui_out *uiout) +{ + ui_out_text (uiout, "\nNo more reverse-execution history.\n"); +} + +/* Print current location without a level number, if we have changed + functions or hit a breakpoint. Print source line if we have one. + bpstat_print contains the logic deciding in detail what to print, + based on the event(s) that just occurred. */ -static void -print_no_history_reason (void) +void +print_stop_event (struct target_waitstatus *ws) { - ui_out_text (current_uiout, "\nNo more reverse-execution history.\n"); + int bpstat_ret; + int source_flag; + int do_frame_printing = 1; + struct thread_info *tp = inferior_thread (); + + bpstat_ret = bpstat_print (tp->control.stop_bpstat, ws->kind); + switch (bpstat_ret) + { + case PRINT_UNKNOWN: + /* FIXME: cagney/2002-12-01: Given that a frame ID does (or + should) carry around the function and does (or should) use + that when doing a frame comparison. */ + if (tp->control.stop_step + && frame_id_eq (tp->control.step_frame_id, + get_frame_id (get_current_frame ())) + && tp->control.step_start_function == find_pc_function (stop_pc)) + { + /* Finished step, just print source line. */ + source_flag = SRC_LINE; + } + else + { + /* Print location and source line. */ + source_flag = SRC_AND_LOC; + } + break; + case PRINT_SRC_AND_LOC: + /* Print location and source line. */ + source_flag = SRC_AND_LOC; + break; + case PRINT_SRC_ONLY: + source_flag = SRC_LINE; + break; + case PRINT_NOTHING: + /* Something bogus. */ + source_flag = SRC_LINE; + do_frame_printing = 0; + break; + default: + internal_error (__FILE__, __LINE__, _("Unknown value.")); + } + + /* The behavior of this routine with respect to the source + flag is: + SRC_LINE: Print only source line + LOCATION: Print only location + SRC_AND_LOC: Print location and source line. */ + if (do_frame_printing) + print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1); + + /* Display the auto-display expressions. */ + do_displays (); } /* Here to return control to GDB when the inferior stops for real. @@ -6017,10 +6564,18 @@ normal_stop (void) && last.kind != TARGET_WAITKIND_NO_RESUMED) make_cleanup (finish_thread_state_cleanup, &inferior_ptid); - /* In non-stop mode, we don't want GDB to switch threads behind the - user's back, to avoid races where the user is typing a command to - apply to thread x, but GDB switches to thread y before the user - finishes entering the command. */ + /* As we're presenting a stop, and potentially removing breakpoints, + update the thread list so we can tell whether there are threads + running on the target. With target remote, for example, we can + only learn about new threads when we explicitly update the thread + list. Do this before notifying the interpreters about signal + stops, end of stepping ranges, etc., so that the "new thread" + output is emitted before e.g., "Program received signal FOO", + instead of after. */ + update_thread_list (); + + if (last.kind == TARGET_WAITKIND_STOPPED && stopped_by_random_signal) + observer_notify_signal_received (inferior_thread ()->suspend.stop_signal); /* As with the notification of thread events, we want to delay notifying the user that we've switched thread context until @@ -6028,7 +6583,16 @@ normal_stop (void) There's no point in saying anything if the inferior has exited. Note that SIGNALLED here means "exited with a signal", not - "received a signal". */ + "received a signal". + + Also skip saying anything in non-stop mode. In that mode, as we + don't want GDB to switch threads behind the user's back, to avoid + races where the user is typing a command to apply to thread x, + but GDB switches to thread y before the user finishes entering + the command, fetch_inferior_event installs a cleanup to restore + the current thread back to the thread the user had selected right + after this event is handled, so we're not really switching, only + informing of a stop. */ if (!non_stop && !ptid_equal (previous_inferior_ptid, inferior_ptid) && target_has_execution @@ -6051,7 +6615,8 @@ normal_stop (void) printf_filtered (_("No unwaited-for children left.\n")); } - if (!breakpoints_always_inserted_mode () && target_has_execution) + /* Note: this depends on the update_thread_list call above. */ + if (!breakpoints_should_be_inserted_now () && target_has_execution) { if (remove_breakpoints ()) { @@ -6068,14 +6633,19 @@ normal_stop (void) if (stopped_by_random_signal) disable_current_display (); - /* Don't print a message if in the middle of doing a "step n" - operation for n > 1 */ + /* 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 ()->step_multi && inferior_thread ()->control.stop_step) - goto done; + { + /* 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 (); @@ -6084,10 +6654,20 @@ normal_stop (void) 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 (), 1); - - /* Let the user/frontend see the threads as stopped. */ - do_cleanups (old_chain); + 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). */ @@ -6111,65 +6691,11 @@ normal_stop (void) { select_frame (get_current_frame ()); - /* Print current location without a level number, if - we have changed functions or hit a breakpoint. - Print source line if we have one. - bpstat_print() contains the logic deciding in detail - what to print, based on the event(s) that just occurred. */ - /* 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) - { - int bpstat_ret; - int source_flag; - int do_frame_printing = 1; - struct thread_info *tp = inferior_thread (); - - bpstat_ret = bpstat_print (tp->control.stop_bpstat, last.kind); - switch (bpstat_ret) - { - case PRINT_UNKNOWN: - /* FIXME: cagney/2002-12-01: Given that a frame ID does - (or should) carry around the function and does (or - should) use that when doing a frame comparison. */ - if (tp->control.stop_step - && frame_id_eq (tp->control.step_frame_id, - get_frame_id (get_current_frame ())) - && step_start_function == find_pc_function (stop_pc)) - source_flag = SRC_LINE; /* Finished step, just - print source line. */ - else - source_flag = SRC_AND_LOC; /* Print location and - source line. */ - break; - case PRINT_SRC_AND_LOC: - source_flag = SRC_AND_LOC; /* Print location and - source line. */ - break; - case PRINT_SRC_ONLY: - source_flag = SRC_LINE; - break; - case PRINT_NOTHING: - source_flag = SRC_LINE; /* something bogus */ - do_frame_printing = 0; - break; - default: - internal_error (__FILE__, __LINE__, _("Unknown value.")); - } - - /* The behavior of this routine with respect to the source - flag is: - SRC_LINE: Print only source line - LOCATION: Print only location - SRC_AND_LOC: Print location and source line. */ - if (do_frame_printing) - print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1); - - /* Display the auto-display expressions. */ - do_displays (); - } + print_stop_event (&last); } /* Save the function value return registers, if we care. @@ -6577,72 +7103,6 @@ handle_completer (struct cmd_list_element *ignore, return return_val; } -static void -xdb_handle_command (char *args, int from_tty) -{ - char **argv; - struct cleanup *old_chain; - - if (args == NULL) - error_no_arg (_("xdb command")); - - /* Break the command line up into args. */ - - argv = gdb_buildargv (args); - old_chain = make_cleanup_freeargv (argv); - if (argv[1] != (char *) NULL) - { - char *argBuf; - int bufLen; - - bufLen = strlen (argv[0]) + 20; - argBuf = (char *) xmalloc (bufLen); - if (argBuf) - { - int validFlag = 1; - enum gdb_signal oursig; - - oursig = gdb_signal_from_name (argv[0]); - memset (argBuf, 0, bufLen); - if (strcmp (argv[1], "Q") == 0) - sprintf (argBuf, "%s %s", argv[0], "noprint"); - else - { - if (strcmp (argv[1], "s") == 0) - { - if (!signal_stop[oursig]) - sprintf (argBuf, "%s %s", argv[0], "stop"); - else - sprintf (argBuf, "%s %s", argv[0], "nostop"); - } - else if (strcmp (argv[1], "i") == 0) - { - if (!signal_program[oursig]) - sprintf (argBuf, "%s %s", argv[0], "pass"); - else - sprintf (argBuf, "%s %s", argv[0], "nopass"); - } - else if (strcmp (argv[1], "r") == 0) - { - if (!signal_print[oursig]) - sprintf (argBuf, "%s %s", argv[0], "print"); - else - sprintf (argBuf, "%s %s", argv[0], "noprint"); - } - else - validFlag = 0; - } - if (validFlag) - handle_command (argBuf, from_tty); - else - printf_filtered (_("Invalid signal handling flag.\n")); - if (argBuf) - xfree (argBuf); - } - } - do_cleanups (old_chain); -} - enum gdb_signal gdb_signal_from_command (int num) { @@ -6851,7 +7311,7 @@ save_infcall_suspend_state (void) } } - inf_state = XZALLOC (struct infcall_suspend_state); + inf_state = XCNEW (struct infcall_suspend_state); if (siginfo_data) { @@ -7083,20 +7543,6 @@ discard_infcall_control_state (struct infcall_control_state *inf_status) xfree (inf_status); } -int -ptid_match (ptid_t ptid, ptid_t filter) -{ - if (ptid_equal (filter, minus_one_ptid)) - return 1; - if (ptid_is_pid (filter) - && ptid_get_pid (ptid) == ptid_get_pid (filter)) - return 1; - else if (ptid_equal (ptid, filter)) - return 1; - - return 0; -} - /* restore_inferior_ptid() will be used by the cleanup machinery to restore the inferior_ptid value saved in a call to save_inferior_ptid(). */ @@ -7124,7 +7570,7 @@ save_inferior_ptid (void) return make_cleanup (restore_inferior_ptid, saved_ptid_ptr); } -/* See inferior.h. */ +/* See infrun.h. */ void clear_exit_convenience_vars (void) @@ -7239,29 +7685,6 @@ may be interspersed with actions, with the actions being performed for\n\ all signals cumulatively specified.")); set_cmd_completer (c, handle_completer); - if (xdb_commands) - { - add_com ("lz", class_info, signals_info, _("\ -What debugger does when program gets various signals.\n\ -Specify a signal as argument to print info on that signal only.")); - add_com ("z", class_run, xdb_handle_command, _("\ -Specify how to handle a signal.\n\ -Args are signals and actions to apply to those signals.\n\ -Symbolic signals (e.g. SIGSEGV) are recommended but numeric signals\n\ -from 1-15 are allowed for compatibility with old versions of GDB.\n\ -Numeric ranges may be specified with the form LOW-HIGH (e.g. 1-5).\n\ -The special arg \"all\" is recognized to mean all signals except those\n\ -used by the debugger, typically SIGTRAP and SIGINT.\n\ -Recognized actions include \"s\" (toggles between stop and nostop),\n\ -\"r\" (toggles between print and noprint), \"i\" (toggles between pass and \ -nopass), \"Q\" (noprint)\n\ -Stop means reenter debugger if this signal happens (implies print).\n\ -Print means print a message if this signal happens.\n\ -Pass means let program see this signal; otherwise program doesn't know.\n\ -Ignore is a synonym for nopass and noignore is a synonym for pass.\n\ -Pass and Stop may be combined.")); - } - if (!dbx_commands) stop_command = add_cmd ("stop", class_obscure, not_just_help_class_command, _("\ @@ -7315,7 +7738,7 @@ leave it stopped or free to run as needed."), signal_catch = (unsigned char *) xmalloc (sizeof (signal_catch[0]) * numsigs); signal_pass = (unsigned char *) - xmalloc (sizeof (signal_program[0]) * numsigs); + xmalloc (sizeof (signal_pass[0]) * numsigs); for (i = 0; i < numsigs; i++) { signal_stop[i] = 1; @@ -7418,9 +7841,8 @@ 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 every single-step operation.\n\ - In this mode, no other thread may run during a step command.\n\ - Other threads may run while stepping over a function call ('next')."), +step == scheduler locked during stepping commands (step, next, stepi, nexti).\n\ + In this mode, other threads may run during other commands."), set_schedlock_func, /* traps on target vector */ show_scheduler_mode, &setlist, &showlist);