X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Finfrun.c;h=033699bc3f73c7684ada386a981a614fafb2779d;hb=8b8da1a9f31941fa167c9f2bd2a80cdd1dccb452;hp=104c29abf0a97cfac0bbb927c6f89d0b602a8fb3;hpb=b7e077222ee350f4bd6c76134064acdbd2ce2b32;p=binutils-gdb.git diff --git a/gdb/infrun.c b/gdb/infrun.c index 104c29abf0a..033699bc3f7 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -96,6 +96,13 @@ static void resume (gdb_signal sig); static void wait_for_inferior (inferior *inf); +static void restart_threads (struct thread_info *event_thread, + inferior *inf = nullptr); + +static bool start_step_over (void); + +static bool step_over_info_valid_p (void); + /* Asynchronous signal handler registered as event loop source for when we have pending events ready to be passed to the core. */ static struct async_event_handler *infrun_async_inferior_event_token; @@ -138,7 +145,7 @@ static void show_step_stop_if_no_debug (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("Mode of the step operation is %s.\n"), value); + gdb_printf (file, _("Mode of the step operation is %s.\n"), value); } /* proceed and normal_stop use this to notify the user when the @@ -159,7 +166,7 @@ static void show_debug_infrun (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("Inferior debugging is %s.\n"), value); + gdb_printf (file, _("Inferior debugging is %s.\n"), value); } /* Support for disabling address space randomization. */ @@ -171,14 +178,14 @@ show_disable_randomization (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { if (target_supports_disable_randomization ()) - fprintf_filtered (file, - _("Disabling randomization of debuggee's " - "virtual address space is %s.\n"), - value); + gdb_printf (file, + _("Disabling randomization of debuggee's " + "virtual address space is %s.\n"), + value); else - fputs_filtered (_("Disabling randomization of debuggee's " - "virtual address space is unsupported on\n" - "this platform.\n"), file); + gdb_puts (_("Disabling randomization of debuggee's " + "virtual address space is unsupported on\n" + "this platform.\n"), file); } static void @@ -213,9 +220,9 @@ static void show_non_stop (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, - _("Controlling the inferior in non-stop mode is %s.\n"), - value); + gdb_printf (file, + _("Controlling the inferior in non-stop mode is %s.\n"), + value); } /* "Observer mode" is somewhat like a more extreme version of @@ -257,15 +264,15 @@ set_observer_mode (const char *args, int from_tty, } if (from_tty) - printf_filtered (_("Observer mode is now %s.\n"), - (observer_mode ? "on" : "off")); + gdb_printf (_("Observer mode is now %s.\n"), + (observer_mode ? "on" : "off")); } static void show_observer_mode (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("Observer mode is %s.\n"), value); + gdb_printf (file, _("Observer mode is %s.\n"), value); } /* This updates the value of observer mode based on changes in @@ -285,8 +292,8 @@ update_observer_mode (void) /* Let the user know if things change. */ if (newval != observer_mode) - printf_filtered (_("Observer mode is now %s.\n"), - (newval ? "on" : "off")); + gdb_printf (_("Observer mode is now %s.\n"), + (newval ? "on" : "off")); observer_mode = observer_mode_1 = newval; } @@ -358,8 +365,8 @@ static void show_stop_on_solib_events (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("Stopping for shared library events is %s.\n"), - value); + gdb_printf (file, _("Stopping for shared library events is %s.\n"), + value); } /* True after stop if current stack frame should be printed. */ @@ -389,10 +396,10 @@ static void show_follow_fork_mode_string (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, - _("Debugger response to a program " - "call of fork or vfork is \"%s\".\n"), - value); + gdb_printf (file, + _("Debugger response to a program " + "call of fork or vfork is \"%s\".\n"), + value); } @@ -422,7 +429,7 @@ follow_fork_inferior (bool follow_child, bool detach_fork) 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, _("\ + gdb_printf (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")); @@ -432,6 +439,8 @@ holding the child stopped. Try \"set detach-on-fork\" or \ inferior *parent_inf = current_inferior (); inferior *child_inf = nullptr; + gdb_assert (parent_inf->thread_waiting_for_vfork_done == nullptr); + if (!follow_child) { /* Detach new forked process? */ @@ -456,9 +465,9 @@ holding the child stopped. Try \"set detach-on-fork\" or \ ptid_t process_ptid = ptid_t (child_ptid.pid ()); target_terminal::ours_for_output (); - printf_filtered (_("[Detaching after %s from child %s]\n"), - has_vforked ? "vfork" : "fork", - target_pid_to_str (process_ptid).c_str ()); + gdb_printf (_("[Detaching after %s from child %s]\n"), + has_vforked ? "vfork" : "fork", + target_pid_to_str (process_ptid).c_str ()); } } else @@ -492,7 +501,7 @@ holding the child stopped. Try \"set detach-on-fork\" or \ } else { - child_inf->aspace = new_address_space (); + child_inf->aspace = new address_space (); child_inf->pspace = new program_space (child_inf->aspace); child_inf->removable = 1; clone_program_space (child_inf->pspace, parent_inf->pspace); @@ -508,7 +517,8 @@ holding the child stopped. Try \"set detach-on-fork\" or \ 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->thread_waiting_for_vfork_done + = detach_fork ? inferior_thread () : nullptr; parent_inf->pspace->breakpoints_not_allowed = detach_fork; } } @@ -522,10 +532,10 @@ holding the child stopped. Try \"set detach-on-fork\" or \ std::string child_pid = target_pid_to_str (child_ptid); target_terminal::ours_for_output (); - printf_filtered (_("[Attaching after %s %s to child %s]\n"), - parent_pid.c_str (), - has_vforked ? "vfork" : "fork", - child_pid.c_str ()); + gdb_printf (_("[Attaching after %s %s to child %s]\n"), + parent_pid.c_str (), + has_vforked ? "vfork" : "fork", + child_pid.c_str ()); } /* Add the new inferior first, so that the target_detach below @@ -563,7 +573,7 @@ holding the child stopped. Try \"set detach-on-fork\" or \ child_inf->aspace = parent_inf->aspace; child_inf->pspace = parent_inf->pspace; - parent_inf->aspace = new_address_space (); + parent_inf->aspace = new address_space (); parent_inf->pspace = new program_space (parent_inf->aspace); clone_program_space (parent_inf->pspace, child_inf->pspace); @@ -573,7 +583,7 @@ holding the child stopped. Try \"set detach-on-fork\" or \ } else { - child_inf->aspace = new_address_space (); + child_inf->aspace = new address_space (); child_inf->pspace = new program_space (child_inf->aspace); child_inf->removable = 1; child_inf->symfile_flags = SYMFILE_NO_READ; @@ -640,7 +650,6 @@ holding the child stopped. Try \"set detach-on-fork\" or \ 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) { @@ -650,9 +659,9 @@ holding the child stopped. Try \"set detach-on-fork\" or \ ptid_t process_ptid = ptid_t (parent_ptid.pid ()); target_terminal::ours_for_output (); - printf_filtered (_("[Detaching after fork from " - "parent %s]\n"), - target_pid_to_str (process_ptid).c_str ()); + gdb_printf (_("[Detaching after fork from " + "parent %s]\n"), + target_pid_to_str (process_ptid).c_str ()); } target_detach (parent_inf, 0); @@ -772,6 +781,12 @@ follow_fork () parent = inferior_ptid; child = tp->pending_follow.child_ptid (); + /* If handling a vfork, stop all the inferior's threads, they will be + restarted when the vfork shared region is complete. */ + if (tp->pending_follow.kind () == TARGET_WAITKIND_VFORKED + && target_is_non_stop_p ()) + stop_all_threads ("handling vfork", tp->inf); + process_stratum_target *parent_targ = tp->inf->process_target (); /* Set up inferior(s) as specified by the caller, and tell the target to do whatever is necessary to follow either parent @@ -962,13 +977,13 @@ handle_vfork_child_exec_or_exit (int exec) if (exec) { - printf_filtered (_("[Detaching vfork parent %s " - "after child exec]\n"), pidstr.c_str ()); + gdb_printf (_("[Detaching vfork parent %s " + "after child exec]\n"), pidstr.c_str ()); } else { - printf_filtered (_("[Detaching vfork parent %s " - "after child exit]\n"), pidstr.c_str ()); + gdb_printf (_("[Detaching vfork parent %s " + "after child exit]\n"), pidstr.c_str ()); } } @@ -1033,6 +1048,55 @@ handle_vfork_child_exec_or_exit (int exec) } } +/* Handle TARGET_WAITKIND_VFORK_DONE. */ + +static void +handle_vfork_done (thread_info *event_thread) +{ + /* We only care about this event if inferior::thread_waiting_for_vfork_done is + set, that is if we are waiting for a vfork child not under our control + (because we detached it) to exec or exit. + + If an inferior has vforked and we are debugging the child, we don't use + the vfork-done event to get notified about the end of the shared address + space window. We rely instead on the child's exec or exit event, and the + inferior::vfork_{parent,child} fields are used instead. See + handle_vfork_child_exec_or_exit for that. */ + if (event_thread->inf->thread_waiting_for_vfork_done == nullptr) + { + infrun_debug_printf ("not waiting for a vfork-done event"); + return; + } + + INFRUN_SCOPED_DEBUG_ENTER_EXIT; + + /* We stopped all threads (other than the vforking thread) of the inferior in + follow_fork and kept them stopped until now. It should therefore not be + possible for another thread to have reported a vfork during that window. + If THREAD_WAITING_FOR_VFORK_DONE is set, it has to be the same thread whose + vfork-done we are handling right now. */ + gdb_assert (event_thread->inf->thread_waiting_for_vfork_done == event_thread); + + event_thread->inf->thread_waiting_for_vfork_done = nullptr; + event_thread->inf->pspace->breakpoints_not_allowed = 0; + + /* On non-stop targets, we stopped all the inferior's threads in follow_fork, + resume them now. On all-stop targets, everything that needs to be resumed + will be when we resume the event thread. */ + if (target_is_non_stop_p ()) + { + /* restart_threads and start_step_over may change the current thread, make + sure we leave the event thread as the current thread. */ + scoped_restore_current_thread restore_thread; + + insert_breakpoints (); + start_step_over (); + + if (!step_over_info_valid_p ()) + restart_threads (event_thread, event_thread->inf); + } +} + /* Enum strings for "set|show follow-exec-mode". */ static const char follow_exec_mode_new[] = "new"; @@ -1049,7 +1113,7 @@ static void show_follow_exec_mode_string (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("Follow exec mode is \"%s\".\n"), value); + gdb_printf (file, _("Follow exec mode is \"%s\".\n"), value); } /* EXEC_FILE_TARGET is assumed to be non-NULL. */ @@ -1130,9 +1194,9 @@ follow_exec (ptid_t ptid, const char *exec_file_target) /* What is this a.out's name? */ process_ptid = ptid_t (pid); - printf_unfiltered (_("%s is executing new program: %s\n"), - target_pid_to_str (process_ptid).c_str (), - exec_file_target); + gdb_printf (_("%s is executing new program: %s\n"), + target_pid_to_str (process_ptid).c_str (), + exec_file_target); /* We've followed the inferior through an exec. Therefore, the inferior has essentially been killed & reborn. */ @@ -1484,6 +1548,7 @@ static void infrun_inferior_exit (struct inferior *inf) { inf->displaced_step_state.reset (); + inf->thread_waiting_for_vfork_done = nullptr; } static void @@ -1502,6 +1567,8 @@ infrun_inferior_execd (inferior *inf) one in progress at the time of the exec, it must have been the exec'ing thread. */ clear_step_over_info (); + + inf->thread_waiting_for_vfork_done = nullptr; } /* If ON, and the architecture supports it, GDB will use displaced @@ -1519,14 +1586,14 @@ show_can_use_displaced_stepping (struct ui_file *file, int from_tty, const char *value) { if (can_use_displaced_stepping == AUTO_BOOLEAN_AUTO) - fprintf_filtered (file, - _("Debugger's willingness to use displaced stepping " - "to step over breakpoints is %s (currently %s).\n"), - value, target_is_non_stop_p () ? "on" : "off"); + gdb_printf (file, + _("Debugger's willingness to use displaced stepping " + "to step over breakpoints is %s (currently %s).\n"), + value, target_is_non_stop_p () ? "on" : "off"); else - fprintf_filtered (file, - _("Debugger's willingness to use displaced stepping " - "to step over breakpoints is %s.\n"), value); + gdb_printf (file, + _("Debugger's willingness to use displaced stepping " + "to step over breakpoints is %s.\n"), value); } /* Return true if the gdbarch implements the required methods to use @@ -1904,6 +1971,16 @@ start_step_over (void) continue; } + if (tp->inf->thread_waiting_for_vfork_done != nullptr) + { + /* When we stop all threads, handling a vfork, any thread in the step + over chain remains there. A user could also try to continue a + thread stopped at a breakpoint while another thread is waiting for + a vfork-done event. In any case, we don't want to start a step + over right now. */ + continue; + } + /* Remove thread from the THREADS_TO_STEP chain. If anything goes wrong while we try to prepare the displaced step, we don't add it back to the global step over chain. This is to avoid a thread staying in the @@ -2033,10 +2110,10 @@ static void show_scheduler_mode (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, - _("Mode for locking scheduler " - "during execution is \"%s\".\n"), - value); + gdb_printf (file, + _("Mode for locking scheduler " + "during execution is \"%s\".\n"), + value); } static void @@ -2139,8 +2216,41 @@ internal_resume_ptid (int user_step) return a wildcard ptid. */ if (target_is_non_stop_p ()) return inferior_ptid; - else - return user_visible_resume_ptid (user_step); + + /* The rest of the function assumes non-stop==off and + target-non-stop==off. + + If a thread is waiting for a vfork-done event, it means breakpoints are out + for this inferior (well, program space in fact). We don't want to resume + any thread other than the one waiting for vfork done, otherwise these other + threads could miss breakpoints. So if a thread in the resumption set is + waiting for a vfork-done event, resume only that thread. + + The resumption set width depends on whether schedule-multiple is on or off. + + Note that if the target_resume interface was more flexible, we could be + smarter here when schedule-multiple is on. For example, imagine 3 + inferiors with 2 threads each (1.1, 1.2, 2.1, 2.2, 3.1 and 3.2). Threads + 2.1 and 3.2 are both waiting for a vfork-done event. Then we could ask the + target(s) to resume: + + - All threads of inferior 1 + - Thread 2.1 + - Thread 3.2 + + Since we don't have that flexibility (we can only pass one ptid), just + resume the first thread waiting for a vfork-done event we find (e.g. thread + 2.1). */ + if (sched_multi) + { + for (inferior *inf : all_non_exited_inferiors ()) + if (inf->thread_waiting_for_vfork_done != nullptr) + return inf->thread_waiting_for_vfork_done->ptid; + } + else if (current_inferior ()->thread_waiting_for_vfork_done != nullptr) + return current_inferior ()->thread_waiting_for_vfork_done->ptid; + + return user_visible_resume_ptid (user_step); } /* Wrapper for target_resume, that handles infrun-specific @@ -2185,6 +2295,10 @@ do_target_resume (ptid_t resume_ptid, bool step, enum gdb_signal sig) else target_pass_signals (signal_pass); + infrun_debug_printf ("resume_ptid=%s, step=%d, sig=%s", + resume_ptid.to_string ().c_str (), + step, gdb_signal_to_symbol_string (sig)); + target_resume (resume_ptid, step, sig); } @@ -2239,7 +2353,7 @@ resume_1 (enum gdb_signal sig) if (target_can_async_p ()) { - target_async (1); + target_async (true); /* Tell the event loop we have an event to process. */ mark_async_event_handler (infrun_async_inferior_event_token); } @@ -2251,7 +2365,7 @@ resume_1 (enum gdb_signal sig) /* Depends on stepped_breakpoint. */ step = currently_stepping (tp); - if (current_inferior ()->waiting_for_vfork_done) + if (current_inferior ()->thread_waiting_for_vfork_done != nullptr) { /* Don't try to single-step a vfork parent that is waiting for the child to get out of the shared memory region (by exec'ing @@ -2371,7 +2485,7 @@ resume_1 (enum gdb_signal sig) && use_displaced_stepping (tp) && !step_over_info_valid_p () && sig == GDB_SIGNAL_0 - && !current_inferior ()->waiting_for_vfork_done) + && current_inferior ()->thread_waiting_for_vfork_done == nullptr) { displaced_step_prepare_status prepare_status = displaced_step_prepare (tp); @@ -2388,7 +2502,7 @@ resume_1 (enum gdb_signal sig) /* Fallback to stepping over the breakpoint in-line. */ if (target_is_non_stop_p ()) - stop_all_threads (); + stop_all_threads ("displaced stepping falling back on inline stepping"); set_step_over_info (regcache->aspace (), regcache_read_pc (regcache), 0, tp->global_num); @@ -3246,6 +3360,19 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) continue; } + /* If a thread of that inferior is waiting for a vfork-done + (for a detached vfork child to exec or exit), breakpoints are + removed. We must not resume any thread of that inferior, other + than the one waiting for the vfork-done. */ + if (tp->inf->thread_waiting_for_vfork_done != nullptr + && tp != tp->inf->thread_waiting_for_vfork_done) + { + infrun_debug_printf ("[%s] another thread of this inferior is " + "waiting for vfork-done", + tp->ptid.to_string ().c_str ()); + continue; + } + infrun_debug_printf ("resuming %s", tp->ptid.to_string ().c_str ()); @@ -3256,7 +3383,13 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) error (_("Command aborted.")); } } - else if (!cur_thr->resumed () && !thread_is_in_step_over_chain (cur_thr)) + else if (!cur_thr->resumed () + && !thread_is_in_step_over_chain (cur_thr) + /* In non-stop, forbid resuming a thread if some other thread of + that inferior is waiting for a vfork-done event (this means + breakpoints are out for this inferior). */ + && !(non_stop + && cur_thr->inf->thread_waiting_for_vfork_done != nullptr)) { /* The thread wasn't started, and isn't queued, run it now. */ reset_ecs (ecs, cur_thr); @@ -3740,7 +3873,6 @@ struct wait_one_event }; static bool handle_one (const wait_one_event &event); -static void restart_threads (struct thread_info *event_thread); /* Prepare and stabilize the inferior for detaching it. E.g., detaching while a thread is displaced stepping is a recipe for @@ -3839,6 +3971,16 @@ prepare_for_detach (void) } } +/* If all-stop, but there exists a non-stop target, stop all threads + now that we're presenting the stop to the user. */ + +static void +stop_all_threads_if_all_stop_mode () +{ + if (!non_stop && exists_non_stop_target ()) + stop_all_threads ("presenting stop to user in all-stop"); +} + /* Wait for control to return from inferior to debugger. If inferior gets a signal, we may decide to start it up again @@ -3885,6 +4027,8 @@ wait_for_inferior (inferior *inf) break; } + stop_all_threads_if_all_stop_mode (); + /* No error, don't finish the state yet. */ finish_state.release (); } @@ -3924,12 +4068,19 @@ reinstall_readline_callback_handler_cleanup () static void clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs) { + /* The first clean_up call below assumes the event thread is the current + one. */ + if (ecs->event_thread != nullptr) + gdb_assert (ecs->event_thread == inferior_thread ()); + if (ecs->event_thread != nullptr && ecs->event_thread->thread_fsm () != nullptr) ecs->event_thread->thread_fsm ()->clean_up (ecs->event_thread); if (!non_stop) { + scoped_restore_current_thread restore_thread; + for (thread_info *thr : all_non_exited_threads ()) { if (thr->thread_fsm () == nullptr) @@ -3940,9 +4091,6 @@ clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs) switch_to_thread (thr); thr->thread_fsm ()->clean_up (thr); } - - if (ecs->event_thread != nullptr) - switch_to_thread (ecs->event_thread); } } @@ -3960,7 +4108,7 @@ check_curr_ui_sync_execution_done (void) { target_terminal::ours (); gdb::observers::sync_execution_done.notify (); - ui_register_input_event_handler (ui); + ui->register_file_handler (); } } @@ -4104,6 +4252,8 @@ fetch_inferior_event () bool should_notify_stop = true; int proceeded = 0; + stop_all_threads_if_all_stop_mode (); + clean_up_just_stopped_threads_fsms (ecs); if (thr != nullptr && thr->thread_fsm () != nullptr) @@ -4150,6 +4300,18 @@ fetch_inferior_event () reinstalled here. */ } + /* Handling this event might have caused some inferiors to become prunable. + For example, the exit of an inferior that was automatically added. Try + to get rid of them. Keeping those around slows down things linearly. + + Note that this never removes the current inferior. Therefore, call this + after RESTORE_THREAD went out of scope, in case the event inferior (which was + temporarily made the current inferior) is meant to be deleted. + + Call this before all_uis_check_sync_execution_done, so that notifications about + removed inferiors appear before the prompt. */ + prune_inferiors (); + /* If a UI was in sync execution mode, and now isn't, restore its prompt (a synchronous execution command has finished, and we're ready for input). */ @@ -4159,7 +4321,7 @@ fetch_inferior_event () && exec_done_display_p && (inferior_ptid == null_ptid || inferior_thread ()->state != THREAD_RUNNING)) - printf_unfiltered (_("completed.\n")); + gdb_printf (_("completed.\n")); } /* See infrun.h. */ @@ -4491,9 +4653,9 @@ handle_syscall_event (struct execution_control_state *ecs) infrun_debug_printf ("syscall number=%d", syscall_number); ecs->event_thread->control.stop_bpstat - = bpstat_stop_status (regcache->aspace (), - ecs->event_thread->stop_pc (), - ecs->event_thread, ecs->ws); + = bpstat_stop_status_nowatch (regcache->aspace (), + ecs->event_thread->stop_pc (), + ecs->event_thread, ecs->ws); if (handle_stop_requested (ecs)) return false; @@ -4543,8 +4705,8 @@ fill_in_stop_func (struct gdbarch *gdbarch, stop_func_start is NOT advanced when in a range of a non-contiguous block that does not contain the entry pc. */ if (block != nullptr - && ecs->stop_func_start <= BLOCK_ENTRY_PC (block) - && BLOCK_ENTRY_PC (block) < ecs->stop_func_end) + && ecs->stop_func_start <= block->entry_pc () + && block->entry_pc () < ecs->stop_func_end) { ecs->stop_func_start += gdbarch_deprecated_function_start_offset (gdbarch); @@ -4619,7 +4781,7 @@ wait_one () { /* If nothing is resumed, remove the target from the event loop. */ - target_async (0); + target_async (false); } else if (event.ws.kind () != TARGET_WAITKIND_IGNORE) return event; @@ -4904,7 +5066,7 @@ handle_one (const wait_one_event &event) /* See infrun.h. */ void -stop_all_threads (void) +stop_all_threads (const char *reason, inferior *inf) { /* We may need multiple passes to discover all threads. */ int pass; @@ -4912,22 +5074,32 @@ stop_all_threads (void) gdb_assert (exists_non_stop_target ()); - infrun_debug_printf ("starting"); + INFRUN_SCOPED_DEBUG_START_END ("reason=%s, inf=%d", reason, + inf != nullptr ? inf->num : -1); + + infrun_debug_show_threads ("non-exited threads", + all_non_exited_threads ()); scoped_restore_current_thread restore_thread; - /* Enable thread events of all targets. */ + /* Enable thread events on relevant targets. */ for (auto *target : all_non_exited_process_targets ()) { + if (inf != nullptr && inf->process_target () != target) + continue; + switch_to_target_no_thread (target); target_thread_events (true); } SCOPE_EXIT { - /* Disable thread events of all targets. */ + /* Disable thread events on relevant targets. */ for (auto *target : all_non_exited_process_targets ()) { + if (inf != nullptr && inf->process_target () != target) + continue; + switch_to_target_no_thread (target); target_thread_events (false); } @@ -4952,6 +5124,9 @@ stop_all_threads (void) for (auto *target : all_non_exited_process_targets ()) { + if (inf != nullptr && inf->process_target () != target) + continue; + switch_to_target_no_thread (target); update_thread_list (); } @@ -4960,6 +5135,9 @@ stop_all_threads (void) to tell the target to stop. */ for (thread_info *t : all_non_exited_threads ()) { + if (inf != nullptr && t->inf != inf) + continue; + /* For a single-target setting with an all-stop target, we would not even arrive here. For a multi-target setting, until GDB is able to handle a mixture of @@ -5087,12 +5265,7 @@ handle_no_resumed (struct execution_control_state *ecs) inferior *curr_inf = current_inferior (); scoped_restore_current_thread restore_thread; - - for (auto *target : all_non_exited_process_targets ()) - { - switch_to_target_no_thread (target); - update_thread_list (); - } + update_thread_list (); /* If: @@ -5288,9 +5461,9 @@ handle_inferior_event (struct execution_control_state *ecs) ecs->event_thread->set_stop_pc (regcache_read_pc (regcache)); ecs->event_thread->control.stop_bpstat - = bpstat_stop_status (regcache->aspace (), - ecs->event_thread->stop_pc (), - ecs->event_thread, ecs->ws); + = bpstat_stop_status_nowatch (regcache->aspace (), + ecs->event_thread->stop_pc (), + ecs->event_thread, ecs->ws); if (handle_stop_requested (ecs)) return; @@ -5531,9 +5704,9 @@ handle_inferior_event (struct execution_control_state *ecs) (regcache_read_pc (get_thread_regcache (ecs->event_thread))); ecs->event_thread->control.stop_bpstat - = bpstat_stop_status (get_current_regcache ()->aspace (), - ecs->event_thread->stop_pc (), - ecs->event_thread, ecs->ws); + = bpstat_stop_status_nowatch (get_current_regcache ()->aspace (), + ecs->event_thread->stop_pc (), + ecs->event_thread, ecs->ws); if (handle_stop_requested (ecs)) return; @@ -5593,7 +5766,18 @@ handle_inferior_event (struct execution_control_state *ecs) ecs->ptid = inferior_ptid; if (should_resume) - keep_going (ecs); + { + /* Never call switch_back_to_stepped_thread if we are waiting for + vfork-done (waiting for an external vfork child to exec or + exit). We will resume only the vforking thread for the purpose + of collecting the vfork-done event, and we will restart any + step once the critical shared address space window is done. */ + if ((!follow_child + && detach_fork + && parent->inf->thread_waiting_for_vfork_done != nullptr) + || !switch_back_to_stepped_thread (ecs)) + keep_going (ecs); + } else stop_waiting (ecs); return; @@ -5607,15 +5791,19 @@ handle_inferior_event (struct execution_control_state *ecs) context_switch (ecs); - current_inferior ()->waiting_for_vfork_done = 0; - current_inferior ()->pspace->breakpoints_not_allowed = 0; + handle_vfork_done (ecs->event_thread); + gdb_assert (inferior_thread () == ecs->event_thread); if (handle_stop_requested (ecs)) return; - /* This also takes care of reinserting breakpoints in the - previously locked inferior. */ - keep_going (ecs); + if (!switch_back_to_stepped_thread (ecs)) + { + gdb_assert (inferior_thread () == ecs->event_thread); + /* This also takes care of reinserting breakpoints in the + previously locked inferior. */ + keep_going (ecs); + } return; case TARGET_WAITKIND_EXECD: @@ -5642,9 +5830,9 @@ handle_inferior_event (struct execution_control_state *ecs) (regcache_read_pc (get_thread_regcache (ecs->event_thread))); ecs->event_thread->control.stop_bpstat - = bpstat_stop_status (get_current_regcache ()->aspace (), - ecs->event_thread->stop_pc (), - ecs->event_thread, ecs->ws); + = bpstat_stop_status_nowatch (get_current_regcache ()->aspace (), + ecs->event_thread->stop_pc (), + ecs->event_thread, ecs->ws); if (handle_stop_requested (ecs)) return; @@ -5702,17 +5890,28 @@ handle_inferior_event (struct execution_control_state *ecs) } /* Restart threads back to what they were trying to do back when we - paused them for an in-line step-over. The EVENT_THREAD thread is - ignored. */ + paused them (because of an in-line step-over or vfork, for example). + The EVENT_THREAD thread is ignored (not restarted). + + If INF is non-nullptr, only resume threads from INF. */ static void -restart_threads (struct thread_info *event_thread) +restart_threads (struct thread_info *event_thread, inferior *inf) { + INFRUN_SCOPED_DEBUG_START_END ("event_thread=%s, inf=%d", + event_thread->ptid.to_string ().c_str (), + inf != nullptr ? inf->num : -1); + + gdb_assert (!step_over_info_valid_p ()); + /* In case the instruction just stepped spawned a new thread. */ update_thread_list (); for (thread_info *tp : all_non_exited_threads ()) { + if (inf != nullptr && tp->inf != inf) + continue; + if (tp->inf->detaching) { infrun_debug_printf ("restart threads: [%s] inferior detaching", @@ -7925,7 +8124,7 @@ check_exception_resume (struct execution_control_state *ecs, cases such as throwing an exception from inside a signal handler. */ - b = SYMBOL_BLOCK_VALUE (func); + b = func->value_block (); ALL_BLOCK_SYMBOLS (b, iter, sym) { if (!sym->is_argument ()) @@ -7953,11 +8152,6 @@ stop_waiting (struct execution_control_state *ecs) /* Let callers know we don't want to wait for the inferior anymore. */ ecs->wait_some_more = 0; - - /* If all-stop, but there exists a non-stop target, stop all - threads now that we're presenting the stop to the user. */ - if (!non_stop && exists_non_stop_target ()) - stop_all_threads (); } /* Like keep_going, but passes the signal to the inferior, even if the @@ -8057,7 +8251,7 @@ keep_going_pass_signal (struct execution_control_state *ecs) we're about to step over, otherwise other threads could miss it. */ if (step_over_info_valid_p () && target_is_non_stop_p ()) - stop_all_threads (); + stop_all_threads ("starting in-line step-over"); /* Stop stepping if inserting breakpoints fails. */ try @@ -8354,9 +8548,9 @@ maybe_remove_breakpoints (void) if (remove_breakpoints ()) { target_terminal::ours_for_output (); - printf_filtered (_("Cannot remove breakpoints because " - "program is no longer writable.\nFurther " - "execution is probably impossible.\n")); + gdb_printf (_("Cannot remove breakpoints because " + "program is no longer writable.\nFurther " + "execution is probably impossible.\n")); } } } @@ -8500,8 +8694,8 @@ normal_stop (void) SWITCH_THRU_ALL_UIS () { target_terminal::ours_for_output (); - printf_filtered (_("[Switching to %s]\n"), - target_pid_to_str (inferior_ptid).c_str ()); + gdb_printf (_("[Switching to %s]\n"), + target_pid_to_str (inferior_ptid).c_str ()); annotate_thread_changed (); } previous_inferior_ptid = inferior_ptid; @@ -8513,7 +8707,7 @@ normal_stop (void) if (current_ui->prompt_state == PROMPT_BLOCKED) { target_terminal::ours_for_output (); - printf_filtered (_("No unwaited-for children left.\n")); + gdb_printf (_("No unwaited-for children left.\n")); } } @@ -8564,29 +8758,26 @@ normal_stop (void) /* Look up the hook_stop and run it (CLI internally handles problem of stop_command's pre-hook not existing). */ - if (stop_command != NULL) - { - stop_context saved_context; - - try - { - execute_cmd_pre_hook (stop_command); - } - catch (const gdb_exception &ex) - { - exception_fprintf (gdb_stderr, ex, - "Error while running hook_stop:\n"); - } + stop_context saved_context; - /* If the stop hook resumes the target, then there's no point in - trying to notify about the previous stop; its context is - gone. Likewise if the command switches thread or inferior -- - the observers would print a stop for the wrong - thread/inferior. */ - if (saved_context.changed ()) - return 1; + try + { + execute_cmd_pre_hook (stop_command); + } + catch (const gdb_exception &ex) + { + exception_fprintf (gdb_stderr, ex, + "Error while running hook_stop:\n"); } + /* If the stop hook resumes the target, then there's no point in + trying to notify about the previous stop; its context is + gone. Likewise if the command switches thread or inferior -- + the observers would print a stop for the wrong + thread/inferior. */ + if (saved_context.changed ()) + return 1; + /* Notify observers about the stop. This is where the interpreters print the stop event. */ if (inferior_ptid != null_ptid) @@ -8607,11 +8798,6 @@ normal_stop (void) breakpoint_auto_delete (inferior_thread ()->control.stop_bpstat); } - /* Try to get rid of automatically added inferiors that are no - longer needed. Keeping those around slows down things linearly. - Note that this never removes the current inferior. */ - prune_inferiors (); - return 0; } @@ -8697,8 +8883,8 @@ signal_catch_update (const unsigned int *info) static void sig_print_header (void) { - printf_filtered (_("Signal Stop\tPrint\tPass " - "to program\tDescription\n")); + gdb_printf (_("Signal Stop\tPrint\tPass " + "to program\tDescription\n")); } static void @@ -8710,12 +8896,12 @@ sig_print_info (enum gdb_signal oursig) if (name_padding <= 0) name_padding = 0; - printf_filtered ("%s", name); - printf_filtered ("%*.*s ", name_padding, name_padding, " "); - printf_filtered ("%s\t", signal_stop[oursig] ? "Yes" : "No"); - printf_filtered ("%s\t", signal_print[oursig] ? "Yes" : "No"); - printf_filtered ("%s\t\t", signal_program[oursig] ? "Yes" : "No"); - printf_filtered ("%s\n", gdb_signal_to_string (oursig)); + gdb_printf ("%s", name); + gdb_printf ("%*.*s ", name_padding, name_padding, " "); + gdb_printf ("%s\t", signal_stop[oursig] ? "Yes" : "No"); + gdb_printf ("%s\t", signal_print[oursig] ? "Yes" : "No"); + gdb_printf ("%s\t\t", signal_program[oursig] ? "Yes" : "No"); + gdb_printf ("%s\n", gdb_signal_to_string (oursig)); } /* Specify how various signals in the inferior should be handled. */ @@ -8851,7 +9037,7 @@ Are you sure you want to change it? "), sigs[signum] = 1; } else - printf_unfiltered (_("Not confirmed, unchanged.\n")); + gdb_printf (_("Not confirmed, unchanged.\n")); } break; case GDB_SIGNAL_0: @@ -8946,7 +9132,7 @@ info_signals_command (const char *signum_exp, int from_tty) return; } - printf_filtered ("\n"); + gdb_printf ("\n"); /* These ugly casts brought to you by the native VAX compiler. */ for (oursig = GDB_SIGNAL_FIRST; (int) oursig < (int) GDB_SIGNAL_LAST; @@ -8959,8 +9145,8 @@ info_signals_command (const char *signum_exp, int from_tty) sig_print_info (oursig); } - printf_filtered (_("\nUse the \"handle\" command " - "to change these tables.\n")); + gdb_printf (_("\nUse the \"handle\" command " + "to change these tables.\n")); } /* The $_siginfo convenience variable is a bit special. We don't know @@ -9333,10 +9519,10 @@ show_exec_direction_func (struct ui_file *out, int from_tty, { switch (execution_direction) { case EXEC_FORWARD: - fprintf_filtered (out, _("Forward.\n")); + gdb_printf (out, _("Forward.\n")); break; case EXEC_REVERSE: - fprintf_filtered (out, _("Reverse.\n")); + gdb_printf (out, _("Reverse.\n")); break; default: internal_error (__FILE__, __LINE__, @@ -9349,8 +9535,8 @@ static void show_schedule_multiple (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) { - fprintf_filtered (file, _("Resuming the execution of threads " - "of all processes is %s.\n"), value); + gdb_printf (file, _("Resuming the execution of threads " + "of all processes is %s.\n"), value); } /* Implementation of `siginfo' variable. */ @@ -9489,9 +9675,8 @@ may be interspersed with actions, with the actions being performed for\n\ all signals cumulatively specified.")); set_cmd_completer (c, handle_completer); - if (!dbx_commands) - stop_command = add_cmd ("stop", class_obscure, - not_just_help_class_command, _("\ + stop_command = add_cmd ("stop", class_obscure, + not_just_help_class_command, _("\ There is no `stop' command, but you can set a hook on `stop'.\n\ This allows you to set a list of commands to be run each time execution\n\ of the program stops."), &cmdlist);