X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Finfrun.c;h=707c053e3ff93a02377f31edcff0e28b23ff5170;hb=5b6d1e4fa4fc6827c7b3f0e99ff120dfa14d65d2;hp=4c732340d1ec2887f60372754ee5839513c700f1;hpb=ecdc3a72c89e43e0e13c5478723b4f70b3964e9f;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/infrun.c b/gdb/infrun.c index 4c732340d1..707c053e3f 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-2018 Free Software Foundation, Inc. + Copyright (C) 1986-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -25,16 +25,13 @@ #include "frame.h" #include "inferior.h" #include "breakpoint.h" -#include "gdb_wait.h" #include "gdbcore.h" #include "gdbcmd.h" -#include "cli/cli-script.h" #include "target.h" #include "gdbthread.h" #include "annotate.h" #include "symfile.h" #include "top.h" -#include #include "inf-loop.h" #include "regcache.h" #include "value.h" @@ -42,7 +39,6 @@ #include "language.h" #include "solib.h" #include "main.h" -#include "dictionary.h" #include "block.h" #include "mi/mi-common.h" #include "event-top.h" @@ -51,8 +47,6 @@ #include "inline-frame.h" #include "jit.h" #include "tracepoint.h" -#include "continuations.h" -#include "interps.h" #include "skip.h" #include "probe.h" #include "objfiles.h" @@ -63,10 +57,14 @@ #include "solist.h" #include "event-loop.h" #include "thread-fsm.h" -#include "common/enum-flags.h" +#include "gdbsupport/enum-flags.h" #include "progspace-and-thread.h" -#include "common/gdb_optional.h" +#include "gdbsupport/gdb_optional.h" #include "arch-utils.h" +#include "gdbsupport/scope-exit.h" +#include "gdbsupport/forward-scope-exit.h" +#include "gdb_select.h" +#include /* Prototypes for local functions */ @@ -82,8 +80,6 @@ static void follow_inferior_reset_breakpoints (void); static int currently_stepping (struct thread_info *tp); -void nullify_last_target_wait_ptid (void); - static void insert_hp_step_resume_breakpoint_at_frame (struct frame_info *); static void insert_step_resume_breakpoint_at_caller (struct frame_info *); @@ -92,6 +88,10 @@ static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR); static int maybe_software_singlestep (struct gdbarch *gdbarch, CORE_ADDR pc); +static void resume (gdb_signal sig); + +static void wait_for_inferior (inferior *inf); + /* 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; @@ -132,7 +132,7 @@ mark_infrun_async_event_handler (void) /* 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. */ -int step_stop_if_no_debug = 0; +bool step_stop_if_no_debug = false; static void show_step_stop_if_no_debug (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -151,9 +151,9 @@ static ptid_t previous_inferior_ptid; Exactly which branch is detached depends on 'set follow-fork-mode' setting. */ -static int detach_fork = 1; +static bool detach_fork = true; -int debug_displaced = 0; +bool debug_displaced = false; static void show_debug_displaced (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -172,7 +172,7 @@ show_debug_infrun (struct ui_file *file, int from_tty, /* Support for disabling address space randomization. */ -int disable_randomization = 1; +bool disable_randomization = true; static void show_disable_randomization (struct ui_file *file, int from_tty, @@ -201,8 +201,8 @@ set_disable_randomization (const char *args, int from_tty, /* User interface for non-stop mode. */ -int non_stop = 0; -static int non_stop_1 = 0; +bool non_stop = false; +static bool non_stop_1 = false; static void set_non_stop (const char *args, int from_tty, @@ -230,8 +230,8 @@ show_non_stop (struct ui_file *file, int from_tty, non-stop, in which all GDB operations that might affect the target's execution have been disabled. */ -int observer_mode = 0; -static int observer_mode_1 = 0; +bool observer_mode = false; +static bool observer_mode_1 = false; static void set_observer_mode (const char *args, int from_tty, @@ -252,7 +252,7 @@ set_observer_mode (const char *args, int from_tty, /* We can insert fast tracepoints in or out of observer mode, but enable them if we're going into this mode. */ if (observer_mode) - may_insert_fast_tracepoints = 1; + may_insert_fast_tracepoints = true; may_stop = !observer_mode; update_target_permissions (); @@ -261,7 +261,7 @@ set_observer_mode (const char *args, int from_tty, if (observer_mode) { pagination_enabled = 0; - non_stop = non_stop_1 = 1; + non_stop = non_stop_1 = true; } if (from_tty) @@ -285,13 +285,11 @@ show_observer_mode (struct ui_file *file, int from_tty, void update_observer_mode (void) { - int newval; - - newval = (!may_insert_breakpoints - && !may_insert_tracepoints - && may_insert_fast_tracepoints - && !may_stop - && non_stop); + bool newval = (!may_insert_breakpoints + && !may_insert_tracepoints + && may_insert_fast_tracepoints + && !may_stop + && non_stop); /* Let the user know if things change. */ if (newval != observer_mode) @@ -303,20 +301,19 @@ update_observer_mode (void) /* Tables of how to react to signals; the user sets them. */ -static unsigned char *signal_stop; -static unsigned char *signal_print; -static unsigned char *signal_program; +static unsigned char signal_stop[GDB_SIGNAL_LAST]; +static unsigned char signal_print[GDB_SIGNAL_LAST]; +static unsigned char signal_program[GDB_SIGNAL_LAST]; /* Table of signals that are registered with "catch signal". A non-zero entry indicates that the signal is caught by some "catch - signal" command. This has size GDB_SIGNAL_LAST, to accommodate all - signals. */ -static unsigned char *signal_catch; + signal" command. */ +static unsigned char signal_catch[GDB_SIGNAL_LAST]; /* Table of signals that the target may silently handle. This is automatically determined from the flags above, and simply cached here. */ -static unsigned char *signal_pass; +static unsigned char signal_pass[GDB_SIGNAL_LAST]; #define SET_SIGS(nsigs,sigs,flags) \ do { \ @@ -340,7 +337,7 @@ static unsigned char *signal_pass; void update_signals_program_target (void) { - target_program_signals ((int) GDB_SIGNAL_LAST, signal_program); + target_program_signals (signal_program); } /* Value to pass to target_resume() to cause all threads to resume. */ @@ -377,9 +374,10 @@ show_stop_on_solib_events (struct ui_file *file, int from_tty, static int stop_print_frame; -/* This is a cached copy of the pid/waitstatus of the last event - returned by target_wait()/deprecated_target_wait_hook(). This - information is returned by get_last_target_status(). */ +/* This is a cached copy of the target/ptid/waitstatus of the last + event returned by target_wait()/deprecated_target_wait_hook(). + This information is returned by get_last_target_status(). */ +static process_stratum_target *target_last_proc_target; static ptid_t target_last_wait_ptid; static struct target_waitstatus target_last_waitstatus; @@ -437,7 +435,6 @@ follow_fork_inferior (int follow_child, int detach_fork) 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; } @@ -462,13 +459,13 @@ holding the child stopped. Try \"set detach-on-fork\" or \ if (print_inferior_events) { /* Ensure that we have a process ptid. */ - ptid_t process_ptid = pid_to_ptid (ptid_get_pid (child_ptid)); + ptid_t process_ptid = ptid_t (child_ptid.pid ()); target_terminal::ours_for_output (); fprintf_filtered (gdb_stdlog, _("[Detaching after %s from child %s]\n"), has_vforked ? "vfork" : "fork", - target_pid_to_str (process_ptid)); + target_pid_to_str (process_ptid).c_str ()); } } else @@ -476,7 +473,7 @@ holding the child stopped. Try \"set detach-on-fork\" or \ struct inferior *parent_inf, *child_inf; /* Add process to GDB's tables. */ - child_inf = add_inferior (ptid_get_pid (child_ptid)); + child_inf = add_inferior (child_ptid.pid ()); parent_inf = current_inferior (); child_inf->attach_flag = parent_inf->attach_flag; @@ -486,10 +483,12 @@ holding the child stopped. Try \"set detach-on-fork\" or \ scoped_restore_current_pspace_and_thread restore_pspace_thread; - inferior_ptid = child_ptid; - add_thread_silent (inferior_ptid); set_current_inferior (child_inf); + switch_to_no_thread (); child_inf->symfile_flags = SYMFILE_NO_READ; + push_target (parent_inf->process_target ()); + add_thread_silent (child_inf->process_target (), child_ptid); + inferior_ptid = child_ptid; /* If this is a vfork child, then the address-space is shared with the parent. */ @@ -498,6 +497,8 @@ holding the child stopped. Try \"set detach-on-fork\" or \ child_inf->pspace = parent_inf->pspace; child_inf->aspace = parent_inf->aspace; + exec_on_vfork (); + /* The parent will be frozen until the child is done with the shared region. Keep track of the parent. */ @@ -563,7 +564,7 @@ holding the child stopped. Try \"set detach-on-fork\" or \ /* 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)); + child_inf = add_inferior (child_ptid.pid ()); parent_inf = current_inferior (); child_inf->attach_flag = parent_inf->attach_flag; @@ -573,52 +574,64 @@ holding the child stopped. Try \"set detach-on-fork\" or \ 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). */ + process_stratum_target *target = parent_inf->process_target (); - 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 (print_inferior_events) - { - /* Ensure that we have a process ptid. */ - ptid_t process_ptid = pid_to_ptid (ptid_get_pid (parent_ptid)); + { + /* Hold a strong reference to the target while (maybe) + detaching the parent. Otherwise detaching could close the + target. */ + auto target_ref = target_ops_ref::new_reference (target); + + /* 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 (print_inferior_events) + { + /* Ensure that we have a process ptid. */ + ptid_t process_ptid = ptid_t (parent_ptid.pid ()); + + target_terminal::ours_for_output (); + fprintf_filtered (gdb_stdlog, + _("[Detaching after fork from " + "parent %s]\n"), + target_pid_to_str (process_ptid).c_str ()); + } - target_terminal::ours_for_output (); - fprintf_filtered (gdb_stdlog, - _("[Detaching after fork from " - "parent %s]\n"), - target_pid_to_str (process_ptid)); - } + target_detach (parent_inf, 0); + parent_inf = NULL; + } - target_detach (parent_inf, 0); - } + /* Note that the detach above makes PARENT_INF dangling. */ - /* 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. */ - /* 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. */ + set_current_inferior (child_inf); + push_target (target); + } + add_thread_silent (target, child_ptid); inferior_ptid = child_ptid; - add_thread_silent (inferior_ptid); - set_current_inferior (child_inf); /* If this is a vfork child, then the address-space is shared with the parent. If we detached from the parent, then we can @@ -627,6 +640,8 @@ holding the child stopped. Try \"set detach-on-fork\" or \ { child_inf->pspace = parent_pspace; child_inf->aspace = child_inf->pspace->aspace; + + exec_on_vfork (); } else { @@ -673,11 +688,12 @@ follow_fork (void) if (!non_stop) { + process_stratum_target *wait_target; ptid_t wait_ptid; struct target_waitstatus wait_status; /* Get the last target status returned by target_wait(). */ - get_last_target_status (&wait_ptid, &wait_status); + get_last_target_status (&wait_target, &wait_ptid, &wait_status); /* If not stopped at a fork event, then there's nothing else to do. */ @@ -688,14 +704,14 @@ follow_fork (void) /* Check if we switched over from WAIT_PTID, since the event was reported. */ if (wait_ptid != minus_one_ptid - && inferior_ptid != wait_ptid) + && (current_inferior ()->process_target () != wait_target + || inferior_ptid != wait_ptid)) { /* We did. Switch back to WAIT_PTID thread, to tell the target to follow it (in either direction). We'll afterwards refuse to resume, and inform the user what happened. */ - thread_info *wait_thread - = find_thread_ptid (wait_ptid); + thread_info *wait_thread = find_thread_ptid (wait_target, wait_ptid); switch_to_thread (wait_thread); should_resume = 0; } @@ -741,6 +757,7 @@ follow_fork (void) parent = inferior_ptid; child = tp->pending_follow.value.related_pid; + 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 or child. */ @@ -756,7 +773,7 @@ follow_fork (void) or another. The previous selected thread may be gone from the lists by now, but if it is still around, need to clear the pending follow request. */ - tp = find_thread_ptid (parent); + tp = find_thread_ptid (parent_targ, parent); if (tp) tp->pending_follow.kind = TARGET_WAITKIND_SPURIOUS; @@ -767,7 +784,7 @@ follow_fork (void) /* If we followed the child, switch to it... */ if (follow_child) { - thread_info *child_thr = find_thread_ptid (child); + thread_info *child_thr = find_thread_ptid (parent_targ, child); switch_to_thread (child_thr); /* ... and preserve the stepping state, in case the @@ -873,7 +890,7 @@ proceed_after_vfork_done (struct thread_info *thread, if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: resuming vfork parent thread %s\n", - target_pid_to_str (thread->ptid)); + target_pid_to_str (thread->ptid).c_str ()); switch_to_thread (thread); clear_proceed_status (0); @@ -912,10 +929,14 @@ handle_vfork_child_exec_or_exit (int exec) int resume_parent = -1; /* This exec or exit marks the end of the shared memory region - between the parent and the child. If the user wanted to - detach from the parent, now is the time. */ + between the parent and the child. Break the bonds. */ + inferior *vfork_parent = inf->vfork_parent; + inf->vfork_parent->vfork_child = NULL; + inf->vfork_parent = NULL; - if (inf->vfork_parent->pending_detach) + /* If the user wanted to detach from the parent, now is the + time. */ + if (vfork_parent->pending_detach) { struct thread_info *tp; struct program_space *pspace; @@ -923,7 +944,7 @@ handle_vfork_child_exec_or_exit (int exec) /* follow-fork child, detach-on-fork on. */ - inf->vfork_parent->pending_detach = 0; + vfork_parent->pending_detach = 0; gdb::optional maybe_restore_inferior; @@ -938,7 +959,7 @@ handle_vfork_child_exec_or_exit (int exec) maybe_restore_thread.emplace (); /* We're letting loose of the parent. */ - tp = any_live_thread_of_inferior (inf->vfork_parent); + tp = any_live_thread_of_inferior (vfork_parent); switch_to_thread (tp); /* We're about to detach from the parent, which implicitly @@ -960,8 +981,8 @@ handle_vfork_child_exec_or_exit (int exec) if (print_inferior_events) { - const char *pidstr - = target_pid_to_str (pid_to_ptid (inf->vfork_parent->pid)); + std::string pidstr + = target_pid_to_str (ptid_t (vfork_parent->pid)); target_terminal::ours_for_output (); @@ -969,17 +990,17 @@ handle_vfork_child_exec_or_exit (int exec) { fprintf_filtered (gdb_stdlog, _("[Detaching vfork parent %s " - "after child exec]\n"), pidstr); + "after child exec]\n"), pidstr.c_str ()); } else { fprintf_filtered (gdb_stdlog, _("[Detaching vfork parent %s " - "after child exit]\n"), pidstr); + "after child exit]\n"), pidstr.c_str ()); } } - target_detach (inf->vfork_parent, 0); + target_detach (vfork_parent, 0); /* Put it back. */ inf->pspace = pspace; @@ -994,10 +1015,7 @@ handle_vfork_child_exec_or_exit (int exec) inf->removable = 1; set_current_program_space (inf->pspace); - resume_parent = inf->vfork_parent->pid; - - /* Break the bonds. */ - inf->vfork_parent->vfork_child = NULL; + resume_parent = vfork_parent->pid; } else { @@ -1027,17 +1045,13 @@ handle_vfork_child_exec_or_exit (int exec) set_current_program_space (pspace); inf->removable = 1; inf->symfile_flags = SYMFILE_NO_READ; - clone_program_space (pspace, inf->vfork_parent->pspace); + clone_program_space (pspace, vfork_parent->pspace); inf->pspace = pspace; inf->aspace = pspace->aspace; - resume_parent = inf->vfork_parent->pid; - /* Break the bonds. */ - inf->vfork_parent->vfork_child = NULL; + resume_parent = vfork_parent->pid; } - inf->vfork_parent = NULL; - gdb_assert (current_program_space == inf->pspace); if (non_stop && resume_parent != -1) @@ -1078,13 +1092,16 @@ show_follow_exec_mode_string (struct ui_file *file, int from_tty, /* EXEC_FILE_TARGET is assumed to be non-NULL. */ static void -follow_exec (ptid_t ptid, char *exec_file_target) +follow_exec (ptid_t ptid, const char *exec_file_target) { - struct thread_info *th, *tmp; struct inferior *inf = current_inferior (); - int pid = ptid_get_pid (ptid); + int pid = ptid.pid (); ptid_t process_ptid; + /* Switch terminal for any messages produced e.g. by + breakpoint_re_set. */ + target_terminal::ours_for_output (); + /* 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 momentary bp's, etc. @@ -1103,7 +1120,7 @@ follow_exec (ptid_t ptid, char *exec_file_target) And, we DON'T want to call delete_breakpoints() here, since that may write the bp's "shadow contents" (the instruction - value that was overwritten witha TRAP instruction). Since + value that was overwritten with a TRAP instruction). Since we now have a new a.out, those shadow contents aren't valid. */ mark_breakpoints_out (); @@ -1127,15 +1144,15 @@ follow_exec (ptid_t ptid, char *exec_file_target) 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)) + for (thread_info *th : all_threads_safe ()) + if (th->ptid.pid () == pid && th->ptid != ptid) delete_thread (th); /* 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 (); + thread_info *th = inferior_thread (); th->control.step_resume_breakpoint = NULL; th->control.exception_resume_breakpoint = NULL; th->control.single_step_breakpoints = NULL; @@ -1150,16 +1167,14 @@ follow_exec (ptid_t ptid, char *exec_file_target) update_breakpoints_after_exec (); /* What is this a.out's name? */ - process_ptid = pid_to_ptid (pid); + process_ptid = ptid_t (pid); printf_unfiltered (_("%s is executing new program: %s\n"), - target_pid_to_str (process_ptid), + 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. */ - gdb_flush (gdb_stdout); - breakpoint_init_inferior (inf_execd); gdb::unique_xmalloc_ptr exec_file_host @@ -1187,17 +1202,22 @@ follow_exec (ptid_t ptid, char *exec_file_target) /* The user wants to keep the old inferior and program spaces around. Create a new fresh one, and switch to it. */ - /* Do exit processing for the original inferior before adding - the new inferior so we don't have two active inferiors with - the same ptid, which can confuse find_inferior_ptid. */ - exit_inferior_num_silent (current_inferior ()->num); - + /* Do exit processing for the original inferior before setting the new + inferior's pid. Having two inferiors with the same pid would confuse + find_inferior_p(t)id. Transfer the terminal state and info from the + old to the new inferior. */ inf = add_inferior_with_spaces (); + swap_terminal_info (inf, current_inferior ()); + exit_inferior_silent (current_inferior ()); + inf->pid = pid; target_follow_exec (inf, exec_file_target); - set_current_inferior (inf); - set_current_program_space (inf->pspace); + inferior *org_inferior = current_inferior (); + switch_to_inferior_no_thread (inf); + push_target (org_inferior->process_target ()); + thread_info *thr = add_thread (inf->process_target (), ptid); + switch_to_thread (thr); } else { @@ -1227,11 +1247,6 @@ follow_exec (ptid_t ptid, char *exec_file_target) registers. */ target_find_description (); - /* The add_thread call ends up reading registers, so do it after updating the - target description. */ - if (follow_exec_mode_string == follow_exec_mode_new) - add_thread (ptid); - solib_create_inferior_hook (0); jit_inferior_created_hook (); @@ -1432,7 +1447,7 @@ step_over_info_valid_p (void) register contents, and memory. We use this in step n1. - gdbarch_displaced_step_fixup adjusts registers and memory after - we have successfuly single-stepped the instruction, to yield the + we have successfully single-stepped the instruction, to yield the same effect the instruction would have had if we had executed it at its original address. We use this in step n3. @@ -1477,74 +1492,27 @@ step_over_info_valid_p (void) displaced_step_closure::~displaced_step_closure () = default; -/* Per-inferior displaced stepping state. */ -struct displaced_step_inferior_state -{ - /* Pointer to next in linked list. */ - struct displaced_step_inferior_state *next; - - /* The process this displaced step state refers to. */ - inferior *inf; - - /* True if preparing a displaced step ever failed. If so, we won't - try displaced stepping for this inferior again. */ - int failed_before; - - /* If this is not nullptr, this is the thread carrying out a - displaced single-step in process PID. This thread's state will - require fixing up once it has completed its step. */ - thread_info *step_thread; - - /* The architecture the thread had when we stepped it. */ - struct gdbarch *step_gdbarch; - - /* The closure provided gdbarch_displaced_step_copy_insn, to be used - for post-step cleanup. */ - struct displaced_step_closure *step_closure; - - /* The address of the original instruction, and the copy we - made. */ - CORE_ADDR step_original, step_copy; - - /* Saved contents of copy area. */ - gdb_byte *step_saved_copy; -}; - -/* The list of states of processes involved in displaced stepping - presently. */ -static struct displaced_step_inferior_state *displaced_step_inferior_states; - /* Get the displaced stepping state of process PID. */ -static struct displaced_step_inferior_state * +static displaced_step_inferior_state * get_displaced_stepping_state (inferior *inf) { - struct displaced_step_inferior_state *state; - - for (state = displaced_step_inferior_states; - state != NULL; - state = state->next) - if (state->inf == inf) - return state; - - return NULL; + return &inf->displaced_step_state; } /* Returns true if any inferior has a thread doing a displaced step. */ -static int -displaced_step_in_progress_any_inferior (void) +static bool +displaced_step_in_progress_any_inferior () { - struct displaced_step_inferior_state *state; - - for (state = displaced_step_inferior_states; - state != NULL; - state = state->next) - if (state->step_thread != nullptr) - return 1; + for (inferior *i : all_inferiors ()) + { + if (i->displaced_step_state.step_thread != nullptr) + return true; + } - return 0; + return false; } /* Return true if thread represented by PTID is doing a displaced @@ -1553,13 +1521,9 @@ displaced_step_in_progress_any_inferior (void) static int displaced_step_in_progress_thread (thread_info *thread) { - struct displaced_step_inferior_state *displaced; - gdb_assert (thread != NULL); - displaced = get_displaced_stepping_state (thread->inf); - - return (displaced != NULL && displaced->step_thread == thread); + return get_displaced_stepping_state (thread->inf)->step_thread == thread; } /* Return true if process PID has a thread doing a displaced step. */ @@ -1567,36 +1531,7 @@ displaced_step_in_progress_thread (thread_info *thread) static int displaced_step_in_progress (inferior *inf) { - struct displaced_step_inferior_state *displaced; - - displaced = get_displaced_stepping_state (inf); - if (displaced != NULL && displaced->step_thread != nullptr) - 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. */ - -static struct displaced_step_inferior_state * -add_displaced_stepping_state (inferior *inf) -{ - struct displaced_step_inferior_state *state; - - for (state = displaced_step_inferior_states; - state != NULL; - state = state->next) - if (state->inf == inf) - return state; - - state = XCNEW (struct displaced_step_inferior_state); - state->inf = inf; - state->next = displaced_step_inferior_states; - displaced_step_inferior_states = state; - - return state; + return get_displaced_stepping_state (inf)->step_thread != nullptr; } /* If inferior is in displaced stepping, and ADDR equals to starting address @@ -1606,47 +1541,21 @@ add_displaced_stepping_state (inferior *inf) struct displaced_step_closure* get_displaced_step_closure_by_addr (CORE_ADDR addr) { - struct displaced_step_inferior_state *displaced + displaced_step_inferior_state *displaced = get_displaced_stepping_state (current_inferior ()); /* If checking the mode of displaced instruction in copy area. */ - if (displaced != NULL - && displaced->step_thread != nullptr + if (displaced->step_thread != nullptr && displaced->step_copy == addr) return displaced->step_closure; return NULL; } -/* Remove the displaced stepping state of process PID. */ - -static void -remove_displaced_stepping_state (inferior *inf) -{ - struct displaced_step_inferior_state *it, **prev_next_p; - - gdb_assert (inf != nullptr); - - it = displaced_step_inferior_states; - prev_next_p = &displaced_step_inferior_states; - while (it) - { - if (it->inf == inf) - { - *prev_next_p = it->next; - xfree (it); - return; - } - - prev_next_p = &it->next; - it = *prev_next_p; - } -} - static void infrun_inferior_exit (struct inferior *inf) { - remove_displaced_stepping_state (inf); + inf->displaced_step_state.reset (); } /* If ON, and the architecture supports it, GDB will use displaced @@ -1683,17 +1592,15 @@ use_displaced_stepping (struct thread_info *tp) { struct regcache *regcache = get_thread_regcache (tp); struct gdbarch *gdbarch = regcache->arch (); - struct displaced_step_inferior_state *displaced_state; - - displaced_state = get_displaced_stepping_state (tp->inf); + displaced_step_inferior_state *displaced_state + = get_displaced_stepping_state (tp->inf); return (((can_use_displaced_stepping == AUTO_BOOLEAN_AUTO && target_is_non_stop_p ()) || can_use_displaced_stepping == AUTO_BOOLEAN_TRUE) && gdbarch_displaced_step_copy_insn_p (gdbarch) && find_record_target () == NULL - && (displaced_state == NULL - || !displaced_state->failed_before)); + && !displaced_state->failed_before); } /* Clean out any stray displaced stepping state. */ @@ -1707,14 +1614,9 @@ displaced_step_clear (struct displaced_step_inferior_state *displaced) displaced->step_closure = NULL; } -static void -displaced_step_clear_cleanup (void *arg) -{ - struct displaced_step_inferior_state *state - = (struct displaced_step_inferior_state *) arg; - - displaced_step_clear (state); -} +/* A cleanup that wraps displaced_step_clear. */ +using displaced_step_clear_cleanup + = FORWARD_SCOPE_EXIT (displaced_step_clear); /* Dump LEN bytes at BUF in hex to FILE, followed by a newline. */ void @@ -1748,14 +1650,12 @@ displaced_step_dump_bytes (struct ui_file *file, static int displaced_step_prepare_throw (thread_info *tp) { - struct cleanup *ignore_cleanups; regcache *regcache = get_thread_regcache (tp); struct gdbarch *gdbarch = regcache->arch (); const address_space *aspace = regcache->aspace (); CORE_ADDR original, copy; ULONGEST len; struct displaced_step_closure *closure; - struct displaced_step_inferior_state *displaced; int status; /* We should never reach this function if the architecture does not @@ -1774,7 +1674,8 @@ displaced_step_prepare_throw (thread_info *tp) /* We have to displaced step one thread at a time, as we only have access to a single scratch space per inferior. */ - displaced = add_displaced_stepping_state (tp->inf); + displaced_step_inferior_state *displaced + = get_displaced_stepping_state (tp->inf); if (displaced->step_thread != nullptr) { @@ -1784,7 +1685,7 @@ displaced_step_prepare_throw (thread_info *tp) if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: deferring step of %s\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); thread_step_over_chain_enqueue (tp); return 0; @@ -1794,7 +1695,7 @@ displaced_step_prepare_throw (thread_info *tp) if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: stepping %s now\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); } displaced_step_clear (displaced); @@ -1830,10 +1731,8 @@ displaced_step_prepare_throw (thread_info *tp) } /* Save the original contents of the copy area. */ - displaced->step_saved_copy = (gdb_byte *) xmalloc (len); - ignore_cleanups = make_cleanup (free_current_contents, - &displaced->step_saved_copy); - status = target_read_memory (copy, displaced->step_saved_copy, len); + displaced->step_saved_copy.resize (len); + status = target_read_memory (copy, displaced->step_saved_copy.data (), len); if (status != 0) throw_error (MEMORY_ERROR, _("Error accessing memory address %s (%s) for " @@ -1844,7 +1743,7 @@ displaced_step_prepare_throw (thread_info *tp) fprintf_unfiltered (gdb_stdlog, "displaced: saved %s: ", paddress (gdbarch, copy)); displaced_step_dump_bytes (gdb_stdlog, - displaced->step_saved_copy, + displaced->step_saved_copy.data (), len); }; @@ -1855,7 +1754,6 @@ displaced_step_prepare_throw (thread_info *tp) /* The architecture doesn't know how or want to displaced step this instruction or instruction sequence. Fallback to stepping over the breakpoint in-line. */ - do_cleanups (ignore_cleanups); return -1; } @@ -1867,12 +1765,14 @@ displaced_step_prepare_throw (thread_info *tp) displaced->step_original = original; displaced->step_copy = copy; - make_cleanup (displaced_step_clear_cleanup, displaced); + { + displaced_step_clear_cleanup cleanup (displaced); - /* Resume execution at the copy. */ - regcache_write_pc (regcache, copy); + /* Resume execution at the copy. */ + regcache_write_pc (regcache, copy); - discard_cleanups (ignore_cleanups); + cleanup.release (); + } if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: displaced pc to %s\n", @@ -1889,23 +1789,23 @@ displaced_step_prepare (thread_info *thread) { int prepared = -1; - TRY + try { prepared = displaced_step_prepare_throw (thread); } - CATCH (ex, RETURN_MASK_ERROR) + catch (const gdb_exception_error &ex) { struct displaced_step_inferior_state *displaced_state; if (ex.error != MEMORY_ERROR && ex.error != NOT_SUPPORTED_ERROR) - throw_exception (ex); + throw; if (debug_infrun) { fprintf_unfiltered (gdb_stdlog, "infrun: disabling displaced stepping: %s\n", - ex.message); + ex.what ()); } /* Be verbose if "set displaced-stepping" is "on", silent if @@ -1913,7 +1813,7 @@ displaced_step_prepare (thread_info *thread) if (can_use_displaced_stepping == AUTO_BOOLEAN_TRUE) { warning (_("disabling displaced stepping: %s"), - ex.message); + ex.what ()); } /* Disable further displaced stepping attempts. */ @@ -1921,7 +1821,6 @@ displaced_step_prepare (thread_info *thread) = get_displaced_stepping_state (thread->inf); displaced_state->failed_before = 1; } - END_CATCH return prepared; } @@ -1945,10 +1844,10 @@ displaced_step_restore (struct displaced_step_inferior_state *displaced, ULONGEST len = gdbarch_max_insn_length (displaced->step_gdbarch); write_memory_ptid (ptid, displaced->step_copy, - displaced->step_saved_copy, len); + displaced->step_saved_copy.data (), len); if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: restored %s %s\n", - target_pid_to_str (ptid), + target_pid_to_str (ptid).c_str (), paddress (displaced->step_gdbarch, displaced->step_copy)); } @@ -1962,20 +1861,15 @@ displaced_step_restore (struct displaced_step_inferior_state *displaced, static int displaced_step_fixup (thread_info *event_thread, enum gdb_signal signal) { - struct cleanup *old_cleanups; struct displaced_step_inferior_state *displaced = get_displaced_stepping_state (event_thread->inf); int ret; - /* Was any thread of this process doing a displaced step? */ - if (displaced == NULL) - return 0; - /* Was this event for the thread we displaced? */ if (displaced->step_thread != event_thread) return 0; - old_cleanups = make_cleanup (displaced_step_clear_cleanup, displaced); + displaced_step_clear_cleanup cleanup (displaced); displaced_step_restore (displaced, displaced->step_thread->ptid); @@ -2010,10 +1904,6 @@ displaced_step_fixup (thread_info *event_thread, enum gdb_signal signal) ret = -1; } - do_cleanups (old_cleanups); - - displaced->step_thread = nullptr; - return ret; } @@ -2021,6 +1911,7 @@ displaced_step_fixup (thread_info *event_thread, enum gdb_signal signal) discarded between events. */ struct execution_control_state { + process_stratum_target *target; ptid_t ptid; /* The thread that got the event, if this was a thread event; NULL otherwise. */ @@ -2111,7 +2002,7 @@ start_step_over (void) internal_error (__FILE__, __LINE__, "[%s] has inconsistent state: " "trap_expected=%d, resumed=%d, executing=%d\n", - target_pid_to_str (tp->ptid), + target_pid_to_str (tp->ptid).c_str (), tp->control.trap_expected, tp->resumed, tp->executing); @@ -2120,7 +2011,7 @@ start_step_over (void) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: resuming [%s] for step-over\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); /* keep_going_pass_signal skips the step-over if the breakpoint is no longer inserted. In all-stop, we want to keep looking @@ -2174,9 +2065,7 @@ start_step_over (void) static void infrun_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid) { - struct displaced_step_inferior_state *displaced; - - if (ptid_equal (inferior_ptid, old_ptid)) + if (inferior_ptid == old_ptid) inferior_ptid = new_ptid; } @@ -2217,7 +2106,7 @@ set_schedlock_func (const char *args, int from_tty, struct cmd_list_element *c) /* True if execution commands resume all threads of all processes by default; otherwise, resume only threads of the current inferior process. */ -int sched_multi = 0; +bool sched_multi = false; /* Try to setup for software single stepping over the specified location. Return 1 if target_resume() should use hardware single step. @@ -2268,7 +2157,7 @@ user_visible_resume_ptid (int step) { /* Resume all threads of the current process (and none of other processes). */ - resume_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid)); + resume_ptid = ptid_t (inferior_ptid.pid ()); } else { @@ -2279,6 +2168,16 @@ user_visible_resume_ptid (int step) return resume_ptid; } +/* See infrun.h. */ + +process_stratum_target * +user_visible_resume_target (ptid_t resume_ptid) +{ + return (resume_ptid == minus_one_ptid && sched_multi + ? NULL + : current_inferior ()->process_target ()); +} + /* Return a ptid representing the set of threads that we will resume, in the perspective of the target, assuming run control handling does not require leaving some threads stopped (e.g., stepping past @@ -2336,13 +2235,16 @@ do_target_resume (ptid_t resume_ptid, int step, enum gdb_signal sig) valid. */ if (step_over_info_valid_p () || displaced_step_in_progress (tp->inf)) - target_pass_signals (0, NULL); + target_pass_signals ({}); else - target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass); + target_pass_signals (signal_pass); target_resume (resume_ptid, step, sig); target_commit_resume (); + + if (target_can_async_p ()) + target_async (1); } /* Resume the inferior. SIG is the signal to give the inferior @@ -2381,10 +2283,12 @@ resume_1 (enum gdb_signal sig) fprintf_unfiltered (gdb_stdlog, "infrun: resume: thread %s has pending wait " "status %s (currently_stepping=%d).\n", - target_pid_to_str (tp->ptid), statstr.c_str (), + target_pid_to_str (tp->ptid).c_str (), + statstr.c_str (), currently_stepping (tp)); } + tp->inf->process_target ()->threads_executing = true; tp->resumed = 1; /* FIXME: What should we do if we are supposed to resume this @@ -2393,7 +2297,8 @@ resume_1 (enum gdb_signal sig) if (sig != GDB_SIGNAL_0) { warning (_("Couldn't deliver signal %s to %s."), - gdb_signal_to_name (sig), target_pid_to_str (tp->ptid)); + gdb_signal_to_name (sig), + target_pid_to_str (tp->ptid).c_str ()); } tp->suspend.stop_signal = GDB_SIGNAL_0; @@ -2437,7 +2342,7 @@ resume_1 (enum gdb_signal sig) "trap_expected=%d, current thread [%s] at %s\n", step, gdb_signal_to_symbol_string (sig), tp->control.trap_expected, - target_pid_to_str (inferior_ptid), + target_pid_to_str (inferior_ptid).c_str (), paddress (gdbarch, pc)); /* Normally, by the time we reach `resume', the breakpoints are either @@ -2686,7 +2591,7 @@ resume_1 (enum gdb_signal sig) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: resume: [%s] stepped breakpoint\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); tp->stepped_breakpoint = 1; @@ -2731,14 +2636,14 @@ resume_1 (enum gdb_signal sig) (GDB_SIGNAL_0 for none). This is a wrapper around 'resume_1' that rolls back state on error. */ -void +static void resume (gdb_signal sig) { - TRY + try { resume_1 (sig); } - CATCH (ex, RETURN_MASK_ALL) + catch (const gdb_exception &ex) { /* If resuming is being aborted for any reason, delete any single-step breakpoint resume_1 may have created, to avoid @@ -2747,9 +2652,8 @@ resume (gdb_signal sig) we're running in non-stop mode. */ if (inferior_ptid != null_ptid) delete_single_step_breakpoints (inferior_thread ()); - throw_exception (ex); + throw; } - END_CATCH } @@ -2791,7 +2695,7 @@ clear_proceed_status_thread (struct thread_info *tp) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: clear_proceed_status_thread (%s)\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); /* If we're starting a new sequence, then the previous finished single-step is no longer relevant. */ @@ -2804,7 +2708,7 @@ clear_proceed_status_thread (struct thread_info *tp) "infrun: clear_proceed_status: pending " "event of %s was a finished step. " "Discarding.\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); tp->suspend.waitstatus_pending_p = 0; tp->suspend.stop_reason = TARGET_STOPPED_BY_NO_REASON; @@ -2818,7 +2722,8 @@ clear_proceed_status_thread (struct thread_info *tp) "infrun: clear_proceed_status_thread: thread %s " "has pending wait status %s " "(currently_stepping=%d).\n", - target_pid_to_str (tp->ptid), statstr.c_str (), + target_pid_to_str (tp->ptid).c_str (), + statstr.c_str (), currently_stepping (tp)); } } @@ -2828,7 +2733,7 @@ clear_proceed_status_thread (struct thread_info *tp) if (!signal_pass_state (tp->suspend.stop_signal)) tp->suspend.stop_signal = GDB_SIGNAL_0; - thread_fsm_delete (tp->thread_fsm); + delete tp->thread_fsm; tp->thread_fsm = NULL; tp->control.trap_expected = 0; @@ -2866,24 +2771,19 @@ clear_proceed_status (int step) execution_direction)) target_record_stop_replaying (); - if (!non_stop) + if (!non_stop && inferior_ptid != null_ptid) { - struct thread_info *tp; - ptid_t resume_ptid; - - resume_ptid = user_visible_resume_ptid (step); + ptid_t resume_ptid = user_visible_resume_ptid (step); + process_stratum_target *resume_target + = user_visible_resume_target (resume_ptid); /* 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); - } + for (thread_info *tp : all_non_exited_threads (resume_target, resume_ptid)) + clear_proceed_status_thread (tp); } - if (!ptid_equal (inferior_ptid, null_ptid)) + if (inferior_ptid != null_ptid) { struct inferior *inferior; @@ -2956,15 +2856,36 @@ schedlock_applies (struct thread_info *tp) execution_direction))); } +/* Calls target_commit_resume on all targets. */ + +static void +commit_resume_all_targets () +{ + scoped_restore_current_thread restore_thread; + + /* Map between process_target and a representative inferior. This + is to avoid committing a resume in the same target more than + once. Resumptions must be idempotent, so this is an + optimization. */ + std::unordered_map conn_inf; + + for (inferior *inf : all_non_exited_inferiors ()) + if (inf->has_execution ()) + conn_inf[inf->process_target ()] = inf; + + for (const auto &ci : conn_inf) + { + inferior *inf = ci.second; + switch_to_inferior_no_thread (inf); + target_commit_resume (); + } +} + /* Basic routine for continuing the program in various fashions. ADDR is the address to resume at, or -1 for resume where stopped. - SIGGNAL is the signal to give it, or 0 for none, - or -1 for act according to how it stopped. - STEP is nonzero if should trap after one instruction. - -1 means return after that and print nothing. - You should probably set various step_... variables - before calling here, if you are stepping. + SIGGNAL is the signal to give it, or GDB_SIGNAL_0 for none, + or GDB_SIGNAL_DEFAULT for act according to how it stopped. You should call clear_proceed_status before calling proceed. */ @@ -2973,9 +2894,7 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) { struct regcache *regcache; struct gdbarch *gdbarch; - struct thread_info *tp; CORE_ADDR pc; - ptid_t resume_ptid; struct execution_control_state ecss; struct execution_control_state *ecs = &ecss; int started; @@ -3000,16 +2919,21 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) const address_space *aspace = regcache->aspace (); pc = regcache_read_pc (regcache); - tp = inferior_thread (); + thread_info *cur_thr = inferior_thread (); /* Fill in with reasonable starting values. */ - init_thread_stepping_state (tp); + init_thread_stepping_state (cur_thr); - gdb_assert (!thread_is_in_step_over_chain (tp)); + gdb_assert (!thread_is_in_step_over_chain (cur_thr)); + + ptid_t resume_ptid + = user_visible_resume_ptid (cur_thr->control.stepping_command); + process_stratum_target *resume_target + = user_visible_resume_target (resume_ptid); if (addr == (CORE_ADDR) -1) { - if (pc == stop_pc + if (pc == cur_thr->suspend.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, @@ -3020,13 +2944,13 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) 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. */ - tp->stepping_over_breakpoint = 1; + cur_thr->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. */ - tp->stepping_over_breakpoint = 1; + cur_thr->stepping_over_breakpoint = 1; } else { @@ -3034,14 +2958,12 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) } if (siggnal != GDB_SIGNAL_DEFAULT) - tp->suspend.stop_signal = siggnal; - - resume_ptid = user_visible_resume_ptid (tp->control.stepping_command); + cur_thr->suspend.stop_signal = siggnal; /* If an exception is thrown from this point on, make sure to propagate GDB's knowledge of the executing state to the frontend/user running state. */ - scoped_finish_thread_state finish_state (resume_ptid); + scoped_finish_thread_state finish_state (resume_target, resume_ptid); /* Even if RESUME_PTID is a wildcard, and we end up resuming fewer threads (e.g., we might need to set threads stepping over @@ -3049,8 +2971,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) threads in RESUME_PTID are now running. Unless we're calling an inferior function, as in that case we pretend the inferior doesn't run at all. */ - if (!tp->control.in_infcall) - set_running (resume_ptid, 1); + if (!cur_thr->control.in_infcall) + set_running (resume_target, resume_ptid, 1); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, @@ -3083,19 +3005,16 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) /* If scheduler locking applies, we can avoid iterating over all threads. */ - if (!non_stop && !schedlock_applies (tp)) + if (!non_stop && !schedlock_applies (cur_thr)) { - struct thread_info *current = tp; + for (thread_info *tp : all_non_exited_threads (resume_target, + resume_ptid)) + { + switch_to_thread_no_regs (tp); - ALL_NON_EXITED_THREADS (tp) - { /* Ignore the current thread here. It's handled afterwards. */ - if (tp == current) - continue; - - /* Ignore threads of processes we're not resuming. */ - if (!ptid_match (tp->ptid, resume_ptid)) + if (tp == cur_thr) continue; if (!thread_still_needs_step_over (tp)) @@ -3106,25 +3025,25 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: need to step-over [%s] first\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); thread_step_over_chain_enqueue (tp); } - tp = current; + switch_to_thread (cur_thr); } /* Enqueue the current thread last, so that we move all other threads over their breakpoints first. */ - if (tp->stepping_over_breakpoint) - thread_step_over_chain_enqueue (tp); + if (cur_thr->stepping_over_breakpoint) + thread_step_over_chain_enqueue (cur_thr); /* If the thread isn't started, we'll still need to set its prev_pc, so that switch_back_to_stepped_thread knows the thread hasn't advanced. Must do this before resuming any thread, as in all-stop/remote, once we resume we can't send any other packet until the target stops again. */ - tp->prev_pc = regcache_read_pc (regcache); + cur_thr->prev_pc = regcache_read_pc (regcache); { scoped_restore save_defer_tc = make_scoped_defer_target_commit_resume (); @@ -3146,18 +3065,27 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) { /* In all-stop, but the target is always in non-stop mode. Start all other threads that are implicitly resumed too. */ - ALL_NON_EXITED_THREADS (tp) - { - /* Ignore threads of processes we're not resuming. */ - if (!ptid_match (tp->ptid, resume_ptid)) - continue; + for (thread_info *tp : all_non_exited_threads (resume_target, + resume_ptid)) + { + switch_to_thread_no_regs (tp); + + if (!tp->inf->has_execution ()) + { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: proceed: [%s] target has " + "no execution\n", + target_pid_to_str (tp->ptid).c_str ()); + continue; + } if (tp->resumed) { if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: proceed: [%s] resumed\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); gdb_assert (tp->executing || tp->suspend.waitstatus_pending_p); continue; } @@ -3167,14 +3095,14 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: proceed: [%s] needs step-over\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); continue; } if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: proceed: resuming %s\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); reset_ecs (ecs, tp); switch_to_thread (tp); @@ -3183,21 +3111,26 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) error (_("Command aborted.")); } } - else if (!tp->resumed && !thread_is_in_step_over_chain (tp)) + else if (!cur_thr->resumed && !thread_is_in_step_over_chain (cur_thr)) { /* The thread wasn't started, and isn't queued, run it now. */ - reset_ecs (ecs, tp); - switch_to_thread (tp); + reset_ecs (ecs, cur_thr); + switch_to_thread (cur_thr); keep_going_pass_signal (ecs); if (!ecs->wait_some_more) error (_("Command aborted.")); } } - target_commit_resume (); + commit_resume_all_targets (); finish_state.release (); + /* If we've switched threads above, switch back to the previously + current thread. We don't want the user to see a different + selected thread. */ + switch_to_thread (cur_thr); + /* Tell the event loop to wait for it to stop. If the target supports asynchronous execution, it'll do this from within target_resume. */ @@ -3211,10 +3144,8 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal) void start_remote (int from_tty) { - struct inferior *inferior; - - inferior = current_inferior (); - inferior->control.stop_soon = STOP_QUIETLY_REMOTE; + inferior *inf = current_inferior (); + inf->control.stop_soon = STOP_QUIETLY_REMOTE; /* Always go on waiting for the target, regardless of the mode. */ /* FIXME: cagney/1999-09-23: At present it isn't possible to @@ -3230,7 +3161,7 @@ start_remote (int from_tty) target_open() return to the caller an indication that the target is currently running and GDB state should be set to the same as for an async run. */ - wait_for_inferior (); + wait_for_inferior (inf); /* Now that the inferior has stopped, do any bookkeeping like loading shared libraries. We want to do this before normal_stop, @@ -3251,12 +3182,9 @@ init_wait_for_inferior (void) clear_proceed_status (0); - target_last_wait_ptid = minus_one_ptid; + nullify_last_target_wait_ptid (); previous_inferior_ptid = inferior_ptid; - - /* Discard any skipped inlined frames. */ - clear_inline_frame_state (minus_one_ptid); } @@ -3284,59 +3212,59 @@ static int switch_back_to_stepped_thread (struct execution_control_state *ecs); static void infrun_thread_stop_requested (ptid_t ptid) { - struct thread_info *tp; + process_stratum_target *curr_target = current_inferior ()->process_target (); /* PTID was requested to stop. If the thread was already stopped, but the user/frontend doesn't know about that yet (e.g., the thread had been temporarily paused for some step-over), set up for reporting the stop now. */ - ALL_NON_EXITED_THREADS (tp) - if (ptid_match (tp->ptid, ptid)) - { - if (tp->state != THREAD_RUNNING) - continue; - if (tp->executing) - continue; + for (thread_info *tp : all_threads (curr_target, ptid)) + { + if (tp->state != THREAD_RUNNING) + continue; + if (tp->executing) + continue; - /* Remove matching threads from the step-over queue, so - start_step_over doesn't try to resume them - automatically. */ - if (thread_is_in_step_over_chain (tp)) - thread_step_over_chain_remove (tp); - - /* If the thread is stopped, but the user/frontend doesn't - know about that yet, queue a pending event, as if the - thread had just stopped now. Unless the thread already had - a pending event. */ - if (!tp->suspend.waitstatus_pending_p) - { - tp->suspend.waitstatus_pending_p = 1; - tp->suspend.waitstatus.kind = TARGET_WAITKIND_STOPPED; - tp->suspend.waitstatus.value.sig = GDB_SIGNAL_0; - } + /* Remove matching threads from the step-over queue, so + start_step_over doesn't try to resume them + automatically. */ + if (thread_is_in_step_over_chain (tp)) + thread_step_over_chain_remove (tp); - /* Clear the inline-frame state, since we're re-processing the - stop. */ - clear_inline_frame_state (tp->ptid); + /* If the thread is stopped, but the user/frontend doesn't + know about that yet, queue a pending event, as if the + thread had just stopped now. Unless the thread already had + a pending event. */ + if (!tp->suspend.waitstatus_pending_p) + { + tp->suspend.waitstatus_pending_p = 1; + tp->suspend.waitstatus.kind = TARGET_WAITKIND_STOPPED; + tp->suspend.waitstatus.value.sig = GDB_SIGNAL_0; + } - /* If this thread was paused because some other thread was - doing an inline-step over, let that finish first. Once - that happens, we'll restart all threads and consume pending - stop events then. */ - if (step_over_info_valid_p ()) - continue; + /* Clear the inline-frame state, since we're re-processing the + stop. */ + clear_inline_frame_state (tp); - /* Otherwise we can process the (new) pending event now. Set - it so this pending event is considered by - do_target_wait. */ - tp->resumed = 1; - } + /* If this thread was paused because some other thread was + doing an inline-step over, let that finish first. Once + that happens, we'll restart all threads and consume pending + stop events then. */ + if (step_over_info_valid_p ()) + continue; + + /* Otherwise we can process the (new) pending event now. Set + it so this pending event is considered by + do_target_wait. */ + tp->resumed = 1; + } } static void infrun_thread_thread_exit (struct thread_info *tp, int silent) { - if (ptid_equal (target_last_wait_ptid, tp->ptid)) + if (target_last_proc_target == tp->inf->process_target () + && target_last_wait_ptid == tp->ptid) nullify_last_target_wait_ptid (); } @@ -3361,7 +3289,7 @@ typedef void (*for_each_just_stopped_thread_callback_func) static 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 (!target_has_execution || inferior_ptid == null_ptid) return; if (target_is_non_stop_p ()) @@ -3371,13 +3299,9 @@ for_each_just_stopped_thread (for_each_just_stopped_thread_callback_func func) } else { - struct thread_info *tp; - /* In all-stop mode, all threads have stopped. */ - ALL_NON_EXITED_THREADS (tp) - { - func (tp); - } + for (thread_info *tp : all_non_exited_threads ()) + func (tp); } } @@ -3399,14 +3323,6 @@ delete_just_stopped_threads_single_step_breakpoints (void) for_each_just_stopped_thread (delete_single_step_breakpoints); } -/* A cleanup wrapper. */ - -static void -delete_just_stopped_threads_infrun_breakpoints_cleanup (void *arg) -{ - delete_just_stopped_threads_infrun_breakpoints (); -} - /* See infrun.h. */ void @@ -3422,17 +3338,17 @@ print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid, is set. */ stb.printf ("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) - stb.printf (" [%s]", target_pid_to_str (waiton_ptid)); + waiton_ptid.pid (), + waiton_ptid.lwp (), + waiton_ptid.tid ()); + if (waiton_ptid.pid () != -1) + stb.printf (" [%s]", target_pid_to_str (waiton_ptid).c_str ()); stb.printf (", status) =\n"); stb.printf ("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)); + result_ptid.pid (), + result_ptid.lwp (), + result_ptid.tid (), + target_pid_to_str (result_ptid).c_str ()); stb.printf ("infrun: %s\n", status_string.c_str ()); /* This uses %s in part to handle %'s in the text, but also to avoid @@ -3444,26 +3360,29 @@ print_target_wait_results (ptid_t waiton_ptid, ptid_t result_ptid, had events. */ static struct thread_info * -random_pending_event_thread (ptid_t waiton_ptid) +random_pending_event_thread (inferior *inf, ptid_t waiton_ptid) { - struct thread_info *event_tp; int num_events = 0; - int random_selector; + + auto has_event = [&] (thread_info *tp) + { + return (tp->ptid.matches (waiton_ptid) + && tp->resumed + && tp->suspend.waitstatus_pending_p); + }; /* First see how many events we have. Count only resumed threads that have an event pending. */ - ALL_NON_EXITED_THREADS (event_tp) - if (ptid_match (event_tp->ptid, waiton_ptid) - && event_tp->resumed - && event_tp->suspend.waitstatus_pending_p) + for (thread_info *tp : inf->non_exited_threads ()) + if (has_event (tp)) num_events++; if (num_events == 0) return NULL; /* Now randomly pick a thread out of those that have had events. */ - random_selector = (int) - ((num_events * (double) rand ()) / (RAND_MAX + 1.0)); + int random_selector = (int) ((num_events * (double) rand ()) + / (RAND_MAX + 1.0)); if (debug_infrun && num_events > 1) fprintf_unfiltered (gdb_stdlog, @@ -3471,41 +3390,41 @@ random_pending_event_thread (ptid_t waiton_ptid) num_events, random_selector); /* Select the Nth thread that has had an event. */ - ALL_NON_EXITED_THREADS (event_tp) - if (ptid_match (event_tp->ptid, waiton_ptid) - && event_tp->resumed - && event_tp->suspend.waitstatus_pending_p) + for (thread_info *tp : inf->non_exited_threads ()) + if (has_event (tp)) if (random_selector-- == 0) - break; + return tp; - return event_tp; + gdb_assert_not_reached ("event thread not found"); } /* Wrapper for target_wait that first checks whether threads have pending statuses to report before actually asking the target for - more events. */ + more events. INF is the inferior we're using to call target_wait + on. */ static ptid_t -do_target_wait (ptid_t ptid, struct target_waitstatus *status, int options) +do_target_wait_1 (inferior *inf, ptid_t ptid, + target_waitstatus *status, int options) { ptid_t event_ptid; struct thread_info *tp; /* First check if there is a resumed thread with a wait status pending. */ - if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid)) + if (ptid == minus_one_ptid || ptid.is_pid ()) { - tp = random_pending_event_thread (ptid); + tp = random_pending_event_thread (inf, ptid); } else { if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: Waiting for specific thread %s.\n", - target_pid_to_str (ptid)); + target_pid_to_str (ptid).c_str ()); /* We have a specific thread to check. */ - tp = find_thread_ptid (ptid); + tp = find_thread_ptid (inf, ptid); gdb_assert (tp != NULL); if (!tp->suspend.waitstatus_pending_p) tp = NULL; @@ -3527,7 +3446,7 @@ do_target_wait (ptid_t ptid, struct target_waitstatus *status, int options) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: PC of %s changed. was=%s, now=%s\n", - target_pid_to_str (tp->ptid), + target_pid_to_str (tp->ptid).c_str (), paddress (gdbarch, tp->suspend.stop_pc), paddress (gdbarch, pc)); discard = 1; @@ -3537,7 +3456,7 @@ do_target_wait (ptid_t ptid, struct target_waitstatus *status, int options) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: previous breakpoint of %s, at %s gone\n", - target_pid_to_str (tp->ptid), + target_pid_to_str (tp->ptid).c_str (), paddress (gdbarch, pc)); discard = 1; @@ -3548,7 +3467,7 @@ do_target_wait (ptid_t ptid, struct target_waitstatus *status, int options) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: pending event of %s cancelled.\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); tp->suspend.waitstatus.kind = TARGET_WAITKIND_SPURIOUS; tp->suspend.stop_reason = TARGET_STOPPED_BY_NO_REASON; @@ -3565,7 +3484,7 @@ do_target_wait (ptid_t ptid, struct target_waitstatus *status, int options) fprintf_unfiltered (gdb_stdlog, "infrun: Using pending wait status %s for %s.\n", statstr.c_str (), - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); } /* Now that we've selected our final event LWP, un-adjust its PC @@ -3612,6 +3531,109 @@ do_target_wait (ptid_t ptid, struct target_waitstatus *status, int options) return event_ptid; } +/* Returns true if INF has any resumed thread with a status + pending. */ + +static bool +threads_are_resumed_pending_p (inferior *inf) +{ + for (thread_info *tp : inf->non_exited_threads ()) + if (tp->resumed + && tp->suspend.waitstatus_pending_p) + return true; + + return false; +} + +/* Wrapper for target_wait that first checks whether threads have + pending statuses to report before actually asking the target for + more events. Polls for events from all inferiors/targets. */ + +static bool +do_target_wait (ptid_t wait_ptid, execution_control_state *ecs, int options) +{ + int num_inferiors = 0; + int random_selector; + + /* For fairness, we pick the first inferior/target to poll at + random, and then continue polling the rest of the inferior list + starting from that one in a circular fashion until the whole list + is polled once. */ + + auto inferior_matches = [&wait_ptid] (inferior *inf) + { + return (inf->process_target () != NULL + && (threads_are_executing (inf->process_target ()) + || threads_are_resumed_pending_p (inf)) + && ptid_t (inf->pid).matches (wait_ptid)); + }; + + /* First see how many resumed inferiors we have. */ + for (inferior *inf : all_inferiors ()) + if (inferior_matches (inf)) + num_inferiors++; + + if (num_inferiors == 0) + { + ecs->ws.kind = TARGET_WAITKIND_IGNORE; + return false; + } + + /* Now randomly pick an inferior out of those that were resumed. */ + random_selector = (int) + ((num_inferiors * (double) rand ()) / (RAND_MAX + 1.0)); + + if (debug_infrun && num_inferiors > 1) + fprintf_unfiltered (gdb_stdlog, + "infrun: Found %d inferiors, starting at #%d\n", + num_inferiors, random_selector); + + /* Select the Nth inferior that was resumed. */ + + inferior *selected = nullptr; + + for (inferior *inf : all_inferiors ()) + if (inferior_matches (inf)) + if (random_selector-- == 0) + { + selected = inf; + break; + } + + /* Now poll for events out of each of the resumed inferior's + targets, starting from the selected one. */ + + auto do_wait = [&] (inferior *inf) + { + switch_to_inferior_no_thread (inf); + + ecs->ptid = do_target_wait_1 (inf, wait_ptid, &ecs->ws, options); + ecs->target = inf->process_target (); + return (ecs->ws.kind != TARGET_WAITKIND_IGNORE); + }; + + /* Needed in all-stop+target-non-stop mode, because we end up here + spuriously after the target is all stopped and we've already + reported the stop to the user, polling for events. */ + scoped_restore_current_thread restore_thread; + + int inf_num = selected->num; + for (inferior *inf = selected; inf != NULL; inf = inf->next) + if (inferior_matches (inf)) + if (do_wait (inf)) + return true; + + for (inferior *inf = inferior_list; + inf != NULL && inf->num < inf_num; + inf = inf->next) + if (inferior_matches (inf)) + if (do_wait (inf)) + return true; + + ecs->ws.kind = TARGET_WAITKIND_IGNORE; + return false; +} + /* Prepare and stabilize the inferior for detaching it. E.g., detaching while a thread is displaced stepping is a recipe for crashing it, as nothing would readjust the PC out of the scratch @@ -3621,13 +3643,13 @@ void prepare_for_detach (void) { struct inferior *inf = current_inferior (); - ptid_t pid_ptid = pid_to_ptid (inf->pid); + ptid_t pid_ptid = ptid_t (inf->pid); displaced_step_inferior_state *displaced = get_displaced_stepping_state (inf); /* Is any thread of this process displaced stepping? If not, there's nothing else to do. */ - if (displaced == NULL || displaced->step_thread == nullptr) + if (displaced->step_thread == nullptr) return; if (debug_infrun) @@ -3651,7 +3673,7 @@ prepare_for_detach (void) don't get any event. */ target_dcache_invalidate (); - ecs->ptid = do_target_wait (pid_ptid, &ecs->ws, 0); + do_target_wait (pid_ptid, ecs, 0); if (debug_infrun) print_target_wait_results (pid_ptid, ecs->ptid, &ecs->ws); @@ -3659,7 +3681,8 @@ prepare_for_detach (void) /* If an error happens while handling the event, propagate GDB's knowledge of the executing state to the frontend/user running state. */ - scoped_finish_thread_state finish_state (minus_one_ptid); + scoped_finish_thread_state finish_state (inf->process_target (), + minus_one_ptid); /* Now figure out what to do with the result of the result. */ handle_inferior_event (ecs); @@ -3687,29 +3710,25 @@ prepare_for_detach (void) When this function actually returns it means the inferior should be left stopped and GDB should read more commands. */ -void -wait_for_inferior (void) +static void +wait_for_inferior (inferior *inf) { - struct cleanup *old_cleanups; - if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: wait_for_inferior ()\n"); - old_cleanups - = make_cleanup (delete_just_stopped_threads_infrun_breakpoints_cleanup, - NULL); + SCOPE_EXIT { delete_just_stopped_threads_infrun_breakpoints (); }; /* If an error happens while handling the event, propagate GDB's knowledge of the executing state to the frontend/user running state. */ - scoped_finish_thread_state finish_state (minus_one_ptid); + scoped_finish_thread_state finish_state + (inf->process_target (), minus_one_ptid); while (1) { struct execution_control_state ecss; struct execution_control_state *ecs = &ecss; - ptid_t waiton_ptid = minus_one_ptid; memset (ecs, 0, sizeof (*ecs)); @@ -3721,10 +3740,11 @@ wait_for_inferior (void) don't get any event. */ target_dcache_invalidate (); - ecs->ptid = do_target_wait (waiton_ptid, &ecs->ws, 0); + ecs->ptid = do_target_wait_1 (inf, minus_one_ptid, &ecs->ws, 0); + ecs->target = inf->process_target (); if (debug_infrun) - print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws); + print_target_wait_results (minus_one_ptid, ecs->ptid, &ecs->ws); /* Now figure out what to do with the result of the result. */ handle_inferior_event (ecs); @@ -3735,8 +3755,6 @@ wait_for_inferior (void) /* No error, don't finish the state yet. */ finish_state.release (); - - do_cleanups (old_cleanups); } /* Cleanup that reinstalls the readline callback handler, if the @@ -3750,7 +3768,7 @@ wait_for_inferior (void) input. */ static void -reinstall_readline_callback_handler_cleanup (void *arg) +reinstall_readline_callback_handler_cleanup () { struct ui *ui = current_ui; @@ -3774,14 +3792,13 @@ reinstall_readline_callback_handler_cleanup (void *arg) static void clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs) { - struct thread_info *thr = ecs->event_thread; - - if (thr != NULL && thr->thread_fsm != NULL) - thread_fsm_clean_up (thr->thread_fsm, thr); + if (ecs->event_thread != NULL + && ecs->event_thread->thread_fsm != NULL) + ecs->event_thread->thread_fsm->clean_up (ecs->event_thread); if (!non_stop) { - ALL_NON_EXITED_THREADS (thr) + for (thread_info *thr : all_non_exited_threads ()) { if (thr->thread_fsm == NULL) continue; @@ -3789,7 +3806,7 @@ clean_up_just_stopped_threads_fsms (struct execution_control_state *ecs) continue; switch_to_thread (thr); - thread_fsm_clean_up (thr->thread_fsm, thr); + thr->thread_fsm->clean_up (thr); } if (ecs->event_thread != NULL) @@ -3852,9 +3869,7 @@ fetch_inferior_event (void *client_data) { struct execution_control_state ecss; struct execution_control_state *ecs = &ecss; - struct cleanup *old_chain = make_cleanup (null_cleanup, NULL); int cmd_done = 0; - ptid_t waiton_ptid = minus_one_ptid; memset (ecs, 0, sizeof (*ecs)); @@ -3864,114 +3879,137 @@ fetch_inferior_event (void *client_data) scoped_restore save_ui = make_scoped_restore (¤t_ui, main_ui); /* End up with readline processing input, if necessary. */ - make_cleanup (reinstall_readline_callback_handler_cleanup, NULL); + { + SCOPE_EXIT { reinstall_readline_callback_handler_cleanup (); }; + + /* 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 + handling the event. */ + gdb::optional maybe_restore_traceframe; + if (non_stop) + { + maybe_restore_traceframe.emplace (); + set_current_traceframe (-1); + } - /* 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 - handling the event. */ - gdb::optional maybe_restore_traceframe; - if (non_stop) - { - maybe_restore_traceframe.emplace (); - set_current_traceframe (-1); - } + /* The user/frontend should not notice a thread switch due to + internal events. Make sure we revert to the user selected + thread and frame after handling the event and running any + breakpoint commands. */ + scoped_restore_current_thread restore_thread; - gdb::optional maybe_restore_thread; + overlay_cache_invalid = 1; + /* Flush target cache before starting to handle each event. Target + was running and cache could be stale. This is just a heuristic. + Running threads may modify target memory, but we don't get any + event. */ + target_dcache_invalidate (); - if (non_stop) - /* In non-stop mode, the user/frontend should not notice a thread - switch due to internal events. Make sure we reverse to the - user selected thread and frame after handling the event and - running any breakpoint commands. */ - maybe_restore_thread.emplace (); + scoped_restore save_exec_dir + = make_scoped_restore (&execution_direction, + target_execution_direction ()); - overlay_cache_invalid = 1; - /* Flush target cache before starting to handle each event. Target - was running and cache could be stale. This is just a heuristic. - Running threads may modify target memory, but we don't get any - event. */ - target_dcache_invalidate (); + if (!do_target_wait (minus_one_ptid, ecs, TARGET_WNOHANG)) + return; - scoped_restore save_exec_dir - = make_scoped_restore (&execution_direction, target_execution_direction ()); + gdb_assert (ecs->ws.kind != TARGET_WAITKIND_IGNORE); - ecs->ptid = do_target_wait (waiton_ptid, &ecs->ws, - target_can_async_p () ? TARGET_WNOHANG : 0); + /* Switch to the target that generated the event, so we can do + target calls. Any inferior bound to the target will do, so we + just switch to the first we find. */ + for (inferior *inf : all_inferiors (ecs->target)) + { + switch_to_inferior_no_thread (inf); + break; + } - if (debug_infrun) - print_target_wait_results (waiton_ptid, ecs->ptid, &ecs->ws); + if (debug_infrun) + print_target_wait_results (minus_one_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. */ - ptid_t finish_ptid = !target_is_non_stop_p () ? minus_one_ptid : ecs->ptid; - scoped_finish_thread_state finish_state (finish_ptid); + /* If an error happens while handling the event, propagate GDB's + knowledge of the executing state to the frontend/user running + state. */ + ptid_t finish_ptid = !target_is_non_stop_p () ? minus_one_ptid : ecs->ptid; + scoped_finish_thread_state finish_state (ecs->target, finish_ptid); - /* Get executed before make_cleanup_restore_current_thread above to apply - still for the thread which has thrown the exception. */ - struct cleanup *ts_old_chain = make_bpstat_clear_actions_cleanup (); + /* Get executed before scoped_restore_current_thread above to apply + still for the thread which has thrown the exception. */ + auto defer_bpstat_clear + = make_scope_exit (bpstat_clear_actions); + auto defer_delete_threads + = make_scope_exit (delete_just_stopped_threads_infrun_breakpoints); - 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); - /* 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_ptid (ecs->target, ecs->ptid); + int should_stop = 1; + struct thread_info *thr = ecs->event_thread; - if (!ecs->wait_some_more) - { - struct inferior *inf = find_inferior_ptid (ecs->ptid); - int should_stop = 1; - struct thread_info *thr = ecs->event_thread; + delete_just_stopped_threads_infrun_breakpoints (); - delete_just_stopped_threads_infrun_breakpoints (); + if (thr != NULL) + { + struct thread_fsm *thread_fsm = thr->thread_fsm; - if (thr != NULL) - { - struct thread_fsm *thread_fsm = thr->thread_fsm; + if (thread_fsm != NULL) + should_stop = thread_fsm->should_stop (thr); + } - if (thread_fsm != NULL) - should_stop = thread_fsm_should_stop (thread_fsm, thr); - } + if (!should_stop) + { + keep_going (ecs); + } + else + { + bool should_notify_stop = true; + int proceeded = 0; - if (!should_stop) - { - keep_going (ecs); - } - else - { - int should_notify_stop = 1; - int proceeded = 0; + clean_up_just_stopped_threads_fsms (ecs); - clean_up_just_stopped_threads_fsms (ecs); + if (thr != NULL && thr->thread_fsm != NULL) + should_notify_stop = thr->thread_fsm->should_notify_stop (); - if (thr != NULL && thr->thread_fsm != NULL) - { - should_notify_stop - = thread_fsm_should_notify_stop (thr->thread_fsm); - } + if (should_notify_stop) + { + /* We may not find an inferior if this was a process exit. */ + if (inf == NULL || inf->control.stop_soon == NO_STOP_QUIETLY) + proceeded = normal_stop (); + } - if (should_notify_stop) - { - /* We may not find an inferior if this was a process exit. */ - if (inf == NULL || inf->control.stop_soon == NO_STOP_QUIETLY) - proceeded = normal_stop (); - } + if (!proceeded) + { + inferior_event_handler (INF_EXEC_COMPLETE, NULL); + cmd_done = 1; + } - if (!proceeded) - { - inferior_event_handler (INF_EXEC_COMPLETE, NULL); - cmd_done = 1; - } - } - } + /* If we got a TARGET_WAITKIND_NO_RESUMED event, then the + previously selected thread is gone. We have two + choices - switch to no thread selected, or restore the + previously selected thread (now exited). We chose the + later, just because that's what GDB used to do. After + this, "info threads" says "The current thread has terminated." instead of "No thread + selected.". */ + if (!non_stop + && cmd_done + && ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED) + restore_thread.dont_restore (); + } + } - discard_cleanups (ts_old_chain); + defer_delete_threads.release (); + defer_bpstat_clear.release (); - /* No error, don't finish the thread states yet. */ - finish_state.release (); + /* No error, don't finish the thread states yet. */ + finish_state.release (); - /* Revert thread and frame. */ - do_cleanups (old_chain); + /* This scope is used to ensure that readline callbacks are + reinstalled here. */ + } /* If a UI was in sync execution mode, and now isn't, restore its prompt (a synchronous execution command has finished, and we're @@ -4009,31 +4047,39 @@ init_thread_stepping_state (struct thread_info *tss) tss->step_after_step_resume_breakpoint = 0; } -/* Set the cached copy of the last ptid/waitstatus. */ +/* See infrun.h. */ void -set_last_target_status (ptid_t ptid, struct target_waitstatus status) +set_last_target_status (process_stratum_target *target, ptid_t ptid, + target_waitstatus status) { + target_last_proc_target = target; 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 - after target_wait()/deprecated_target_wait_hook(). */ +/* See infrun.h. */ void -get_last_target_status (ptid_t *ptidp, struct target_waitstatus *status) +get_last_target_status (process_stratum_target **target, ptid_t *ptid, + target_waitstatus *status) { - *ptidp = target_last_wait_ptid; - *status = target_last_waitstatus; + if (target != nullptr) + *target = target_last_proc_target; + if (ptid != nullptr) + *ptid = target_last_wait_ptid; + if (status != nullptr) + *status = target_last_waitstatus; } +/* See infrun.h. */ + void nullify_last_target_wait_ptid (void) { + target_last_proc_target = nullptr; target_last_wait_ptid = minus_one_ptid; + target_last_waitstatus = {}; } /* Switch thread contexts. */ @@ -4043,12 +4089,13 @@ context_switch (execution_control_state *ecs) { if (debug_infrun && ecs->ptid != inferior_ptid - && ecs->event_thread != inferior_thread ()) + && (inferior_ptid == null_ptid + || ecs->event_thread != inferior_thread ())) { fprintf_unfiltered (gdb_stdlog, "infrun: Switching context from %s ", - target_pid_to_str (inferior_ptid)); + target_pid_to_str (inferior_ptid).c_str ()); fprintf_unfiltered (gdb_stdlog, "to %s\n", - target_pid_to_str (ecs->ptid)); + target_pid_to_str (ecs->ptid).c_str ()); } switch_to_thread (ecs->event_thread); @@ -4217,6 +4264,45 @@ stepped_in_from (struct frame_info *frame, struct frame_id step_frame_id) return 0; } +/* Look for an inline frame that is marked for skip. + If PREV_FRAME is TRUE start at the previous frame, + otherwise start at the current frame. Stop at the + first non-inline frame, or at the frame where the + step started. */ + +static bool +inline_frame_is_marked_for_skip (bool prev_frame, struct thread_info *tp) +{ + struct frame_info *frame = get_current_frame (); + + if (prev_frame) + frame = get_prev_frame (frame); + + for (; frame != NULL; frame = get_prev_frame (frame)) + { + const char *fn = NULL; + symtab_and_line sal; + struct symbol *sym; + + if (frame_id_eq (get_frame_id (frame), tp->control.step_frame_id)) + break; + if (get_frame_type (frame) != INLINE_FRAME) + break; + + sal = find_frame_sal (frame); + sym = get_frame_function (frame); + + if (sym != NULL) + fn = sym->print_name (); + + if (sal.line != 0 + && function_name_is_marked_for_skip (fn, sal)) + return true; + } + + return false; +} + /* If the event thread has the stop requested flag set, pretend it stopped for a GDB_SIGNAL_0 (i.e., as if it stopped due to target_stop). */ @@ -4249,7 +4335,7 @@ handle_syscall_event (struct execution_control_state *ecs) regcache = get_thread_regcache (ecs->event_thread); syscall_number = ecs->ws.value.syscall_number; - stop_pc = regcache_read_pc (regcache); + ecs->event_thread->suspend.stop_pc = regcache_read_pc (regcache); if (catch_syscall_enabled () > 0 && catching_syscall_number (syscall_number) > 0) @@ -4260,7 +4346,8 @@ handle_syscall_event (struct execution_control_state *ecs) ecs->event_thread->control.stop_bpstat = bpstat_stop_status (regcache->aspace (), - stop_pc, ecs->event_thread, &ecs->ws); + ecs->event_thread->suspend.stop_pc, + ecs->event_thread, &ecs->ws); if (handle_stop_requested (ecs)) return 0; @@ -4288,16 +4375,35 @@ fill_in_stop_func (struct gdbarch *gdbarch, { if (!ecs->stop_func_filled_in) { + const block *block; + /* Don't care about return value; stop_func_start and stop_func_name will both be 0 if it doesn't work. */ - find_pc_partial_function (stop_pc, &ecs->stop_func_name, - &ecs->stop_func_start, &ecs->stop_func_end); - 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); + find_pc_partial_function (ecs->event_thread->suspend.stop_pc, + &ecs->stop_func_name, + &ecs->stop_func_start, + &ecs->stop_func_end, + &block); + + /* The call to find_pc_partial_function, above, will set + stop_func_start and stop_func_end to the start and end + of the range containing the stop pc. If this range + contains the entry pc for the block (which is always the + case for contiguous blocks), advance stop_func_start past + the function's start offset and entrypoint. Note that + 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 + += 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; } @@ -4309,20 +4415,19 @@ fill_in_stop_func (struct gdbarch *gdbarch, static enum stop_kind get_inferior_stop_soon (execution_control_state *ecs) { - struct inferior *inf = find_inferior_ptid (ecs->ptid); + struct inferior *inf = find_inferior_ptid (ecs->target, ecs->ptid); gdb_assert (inf != NULL); return inf->control.stop_soon; } -/* Wait for one event. Store the resulting waitstatus in WS, and - return the event ptid. */ +/* Poll for one event out of the current target. Store the resulting + waitstatus in WS, and return the event ptid. Does not block. */ static ptid_t -wait_one (struct target_waitstatus *ws) +poll_one_curr_target (struct target_waitstatus *ws) { ptid_t event_ptid; - ptid_t wait_ptid = minus_one_ptid; overlay_cache_invalid = 1; @@ -4333,16 +4438,101 @@ wait_one (struct target_waitstatus *ws) target_dcache_invalidate (); if (deprecated_target_wait_hook) - event_ptid = deprecated_target_wait_hook (wait_ptid, ws, 0); + event_ptid = deprecated_target_wait_hook (minus_one_ptid, ws, TARGET_WNOHANG); else - event_ptid = target_wait (wait_ptid, ws, 0); + event_ptid = target_wait (minus_one_ptid, ws, TARGET_WNOHANG); if (debug_infrun) - print_target_wait_results (wait_ptid, event_ptid, ws); + print_target_wait_results (minus_one_ptid, event_ptid, ws); return event_ptid; } +/* An event reported by wait_one. */ + +struct wait_one_event +{ + /* The target the event came out of. */ + process_stratum_target *target; + + /* The PTID the event was for. */ + ptid_t ptid; + + /* The waitstatus. */ + target_waitstatus ws; +}; + +/* Wait for one event out of any target. */ + +static wait_one_event +wait_one () +{ + while (1) + { + for (inferior *inf : all_inferiors ()) + { + process_stratum_target *target = inf->process_target (); + if (target == NULL + || !target->is_async_p () + || !target->threads_executing) + continue; + + switch_to_inferior_no_thread (inf); + + wait_one_event event; + event.target = target; + event.ptid = poll_one_curr_target (&event.ws); + + if (event.ws.kind == TARGET_WAITKIND_NO_RESUMED) + { + /* If nothing is resumed, remove the target from the + event loop. */ + target_async (0); + } + else if (event.ws.kind != TARGET_WAITKIND_IGNORE) + return event; + } + + /* Block waiting for some event. */ + + fd_set readfds; + int nfds = 0; + + FD_ZERO (&readfds); + + for (inferior *inf : all_inferiors ()) + { + process_stratum_target *target = inf->process_target (); + if (target == NULL + || !target->is_async_p () + || !target->threads_executing) + continue; + + int fd = target->async_wait_fd (); + FD_SET (fd, &readfds); + if (nfds <= fd) + nfds = fd + 1; + } + + if (nfds == 0) + { + /* No waitable targets left. All must be stopped. */ + return {NULL, minus_one_ptid, {TARGET_WAITKIND_NO_RESUMED}}; + } + + QUIT; + + int numfds = interruptible_select (nfds, &readfds, 0, NULL, 0); + if (numfds < 0) + { + if (errno == EINTR) + continue; + else + perror_with_name ("interruptible_select"); + } + } +} + /* Generate a wrapper for target_stopped_by_REASON that works on PTID instead of the current thread. */ #define THREAD_STOPPED_BY(REASON) \ @@ -4365,7 +4555,7 @@ THREAD_STOPPED_BY (hw_breakpoint) /* Save the thread's event and stop reason to process it later. */ static void -save_waitstatus (struct thread_info *tp, struct target_waitstatus *ws) +save_waitstatus (struct thread_info *tp, const target_waitstatus *ws) { if (debug_infrun) { @@ -4374,9 +4564,9 @@ save_waitstatus (struct thread_info *tp, struct target_waitstatus *ws) fprintf_unfiltered (gdb_stdlog, "infrun: saving status %s for %d.%ld.%ld\n", statstr.c_str (), - ptid_get_pid (tp->ptid), - ptid_get_lwp (tp->ptid), - ptid_get_tid (tp->ptid)); + tp->ptid.pid (), + tp->ptid.lwp (), + tp->ptid.tid ()); } /* Record for later. */ @@ -4433,14 +4623,6 @@ save_waitstatus (struct thread_info *tp, struct target_waitstatus *ws) } } -/* A cleanup that disables thread create/exit events. */ - -static void -disable_thread_events (void *arg) -{ - target_thread_events (0); -} - /* See infrun.h. */ void @@ -4449,7 +4631,6 @@ stop_all_threads (void) /* We may need multiple passes to discover all threads. */ int pass; int iterations = 0; - struct cleanup *old_chain; gdb_assert (target_is_non_stop_p ()); @@ -4459,7 +4640,7 @@ stop_all_threads (void) scoped_restore_current_thread restore_thread; target_thread_events (1); - old_chain = make_cleanup (disable_thread_events, NULL); + SCOPE_EXIT { target_thread_events (0); }; /* Request threads to stop, and then wait for the stops. Because threads we already know about can spawn more threads while we're @@ -4474,16 +4655,13 @@ stop_all_threads (void) "iterations=%d\n", pass, iterations); while (1) { - ptid_t event_ptid; - struct target_waitstatus ws; int need_wait = 0; - struct thread_info *t; update_thread_list (); /* Go through all threads looking for threads that we need to tell the target to stop. */ - ALL_NON_EXITED_THREADS (t) + for (thread_info *t : all_non_exited_threads ()) { if (t->executing) { @@ -4495,7 +4673,8 @@ stop_all_threads (void) fprintf_unfiltered (gdb_stdlog, "infrun: %s executing, " "need stop\n", - target_pid_to_str (t->ptid)); + target_pid_to_str (t->ptid).c_str ()); + switch_to_thread_no_regs (t); target_stop (t->ptid); t->stop_requested = 1; } @@ -4505,7 +4684,7 @@ stop_all_threads (void) fprintf_unfiltered (gdb_stdlog, "infrun: %s executing, " "already stopping\n", - target_pid_to_str (t->ptid)); + target_pid_to_str (t->ptid).c_str ()); } if (t->stop_requested) @@ -4516,7 +4695,7 @@ stop_all_threads (void) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: %s not executing\n", - target_pid_to_str (t->ptid)); + target_pid_to_str (t->ptid).c_str ()); /* The thread may be not executing, but still be resumed with a pending status to process. */ @@ -4533,33 +4712,29 @@ stop_all_threads (void) if (pass > 0) pass = -1; - event_ptid = wait_one (&ws); + wait_one_event event = wait_one (); - if (ws.kind == TARGET_WAITKIND_NO_RESUMED) + if (debug_infrun) { - /* All resumed threads exited. */ + fprintf_unfiltered (gdb_stdlog, + "infrun: stop_all_threads %s %s\n", + target_waitstatus_to_string (&event.ws).c_str (), + target_pid_to_str (event.ptid).c_str ()); } - else if (ws.kind == TARGET_WAITKIND_THREAD_EXITED - || ws.kind == TARGET_WAITKIND_EXITED - || ws.kind == TARGET_WAITKIND_SIGNALLED) - { - if (debug_infrun) - { - ptid_t ptid = pid_to_ptid (ws.value.integer); - fprintf_unfiltered (gdb_stdlog, - "infrun: %s exited while " - "stopping threads\n", - target_pid_to_str (ptid)); - } + if (event.ws.kind == TARGET_WAITKIND_NO_RESUMED + || event.ws.kind == TARGET_WAITKIND_THREAD_EXITED + || event.ws.kind == TARGET_WAITKIND_EXITED + || event.ws.kind == TARGET_WAITKIND_SIGNALLED) + { + /* All resumed threads exited + or one thread/process exited/signalled. */ } else { - inferior *inf; - - t = find_thread_ptid (event_ptid); + thread_info *t = find_thread_ptid (event.target, event.ptid); if (t == NULL) - t = add_thread (event_ptid); + t = add_thread (event.target, event.ptid); t->stop_requested = 0; t->executing = 0; @@ -4568,15 +4743,15 @@ stop_all_threads (void) /* This may be the first time we see the inferior report a stop. */ - inf = find_inferior_ptid (event_ptid); + inferior *inf = find_inferior_ptid (event.target, event.ptid); if (inf->needs_setup) { switch_to_thread_no_regs (t); setup_inferior (0); } - if (ws.kind == TARGET_WAITKIND_STOPPED - && ws.value.sig == GDB_SIGNAL_0) + if (event.ws.kind == TARGET_WAITKIND_STOPPED + && event.ws.value.sig == GDB_SIGNAL_0) { /* We caught the event that we intended to catch, so there's no event pending. */ @@ -4592,7 +4767,7 @@ stop_all_threads (void) "infrun: displaced-step of %s " "canceled: adding back to the " "step-over queue\n", - target_pid_to_str (t->ptid)); + target_pid_to_str (t->ptid).c_str ()); } t->control.trap_expected = 0; thread_step_over_chain_enqueue (t); @@ -4605,22 +4780,22 @@ stop_all_threads (void) if (debug_infrun) { - std::string statstr = target_waitstatus_to_string (&ws); + std::string statstr = target_waitstatus_to_string (&event.ws); fprintf_unfiltered (gdb_stdlog, "infrun: target_wait %s, saving " "status for %d.%ld.%ld\n", statstr.c_str (), - ptid_get_pid (t->ptid), - ptid_get_lwp (t->ptid), - ptid_get_tid (t->ptid)); + t->ptid.pid (), + t->ptid.lwp (), + t->ptid.tid ()); } /* Record for later. */ - save_waitstatus (t, &ws); + save_waitstatus (t, &event.ws); - sig = (ws.kind == TARGET_WAITKIND_STOPPED - ? ws.value.sig : GDB_SIGNAL_0); + sig = (event.ws.kind == TARGET_WAITKIND_STOPPED + ? event.ws.value.sig : GDB_SIGNAL_0); if (displaced_step_fixup (t, sig) < 0) { @@ -4639,7 +4814,7 @@ stop_all_threads (void) "(currently_stepping=%d)\n", paddress (target_gdbarch (), t->suspend.stop_pc), - target_pid_to_str (t->ptid), + target_pid_to_str (t->ptid).c_str (), currently_stepping (t)); } } @@ -4647,8 +4822,6 @@ stop_all_threads (void) } } - do_cleanups (old_chain); - if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: stop_all_threads done\n"); } @@ -4658,9 +4831,6 @@ stop_all_threads (void) static int handle_no_resumed (struct execution_control_state *ecs) { - struct inferior *inf; - struct thread_info *thread; - if (target_can_async_p ()) { struct ui *ui; @@ -4723,7 +4893,7 @@ handle_no_resumed (struct execution_control_state *ecs) the synchronous command show "no unwaited-for " to the user. */ update_thread_list (); - ALL_NON_EXITED_THREADS (thread) + for (thread_info *thread : all_non_exited_threads (ecs->target)) { if (thread->executing || thread->suspend.waitstatus_pending_p) @@ -4743,11 +4913,8 @@ handle_no_resumed (struct execution_control_state *ecs) process exited meanwhile (thus updating the thread list results in an empty thread list). In this case we know we'll be getting a process exit event shortly. */ - ALL_INFERIORS (inf) + for (inferior *inf : all_non_exited_inferiors (ecs->target)) { - if (inf->pid == 0) - continue; - thread_info *thread = any_live_thread_of_inferior (inf); if (thread == NULL) { @@ -4778,10 +4945,19 @@ handle_no_resumed (struct execution_control_state *ecs) once). */ static void -handle_inferior_event_1 (struct execution_control_state *ecs) +handle_inferior_event (struct execution_control_state *ecs) { + /* Make sure that all temporary struct value objects that were + created during the handling of the event get deleted at the + end. */ + scoped_value_mark free_values; + enum stop_kind stop_soon; + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "infrun: handle_inferior_event %s\n", + target_waitstatus_to_string (&ecs->ws).c_str ()); + if (ecs->ws.kind == TARGET_WAITKIND_IGNORE) { /* We had an event in the inferior, but we are not interested in @@ -4793,16 +4969,12 @@ handle_inferior_event_1 (struct execution_control_state *ecs) not stopped, and we are ignoring the event. Another possible circumstance is any event which the lower level knows will be reported multiple times without an intervening resume. */ - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_IGNORE\n"); prepare_to_wait (ecs); return; } if (ecs->ws.kind == TARGET_WAITKIND_THREAD_EXITED) { - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_THREAD_EXITED\n"); prepare_to_wait (ecs); return; } @@ -4811,8 +4983,8 @@ handle_inferior_event_1 (struct execution_control_state *ecs) && handle_no_resumed (ecs)) return; - /* Cache the last pid/waitstatus. */ - set_last_target_status (ecs->ptid, ecs->ws); + /* Cache the last target/ptid/waitstatus. */ + set_last_target_status (ecs->target, ecs->ptid, ecs->ws); /* Always clear state belonging to the previous time we stopped. */ stop_stack_dummy = STOP_NONE; @@ -4821,9 +4993,6 @@ handle_inferior_event_1 (struct execution_control_state *ecs) { /* No unwaited-for children left. IOW, all resumed children have exited. */ - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_NO_RESUMED\n"); - stop_print_frame = 0; stop_waiting (ecs); return; @@ -4832,10 +5001,10 @@ handle_inferior_event_1 (struct execution_control_state *ecs) if (ecs->ws.kind != TARGET_WAITKIND_EXITED && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED) { - ecs->event_thread = find_thread_ptid (ecs->ptid); + ecs->event_thread = find_thread_ptid (ecs->target, ecs->ptid); /* If it's a new thread, add it to the thread database. */ if (ecs->event_thread == NULL) - ecs->event_thread = add_thread (ecs->ptid); + ecs->event_thread = add_thread (ecs->target, ecs->ptid); /* Disable range stepping. If the next step request could use a range, this will be end up re-enabled then. */ @@ -4902,22 +5071,20 @@ handle_inferior_event_1 (struct execution_control_state *ecs) process as not-executing so that finish_thread_state marks them stopped (in the user's perspective) if/when we present the stop to the user. */ - mark_ptid = pid_to_ptid (ptid_get_pid (ecs->ptid)); + mark_ptid = ptid_t (ecs->ptid.pid ()); } else mark_ptid = ecs->ptid; - set_executing (mark_ptid, 0); + set_executing (ecs->target, mark_ptid, 0); /* Likewise the resumed flag. */ - set_resumed (mark_ptid, 0); + set_resumed (ecs->target, mark_ptid, 0); } switch (ecs->ws.kind) { case TARGET_WAITKIND_LOADED: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_LOADED\n"); context_switch (ecs); /* Ignore gracefully during startup of the inferior, as it might be the shell which has just loaded some objects, otherwise @@ -4937,7 +5104,8 @@ handle_inferior_event_1 (struct execution_control_state *ecs) ecs->event_thread->control.stop_bpstat = bpstat_stop_status (regcache->aspace (), - stop_pc, ecs->event_thread, &ecs->ws); + ecs->event_thread->suspend.stop_pc, + ecs->event_thread, &ecs->ws); if (handle_stop_requested (ecs)) return; @@ -4994,8 +5162,6 @@ handle_inferior_event_1 (struct execution_control_state *ecs) _("unhandled stop_soon: %d"), (int) stop_soon); case TARGET_WAITKIND_SPURIOUS: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SPURIOUS\n"); if (handle_stop_requested (ecs)) return; context_switch (ecs); @@ -5004,8 +5170,6 @@ handle_inferior_event_1 (struct execution_control_state *ecs) return; case TARGET_WAITKIND_THREAD_CREATED: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_THREAD_CREATED\n"); if (handle_stop_requested (ecs)) return; context_switch (ecs); @@ -5015,18 +5179,8 @@ handle_inferior_event_1 (struct execution_control_state *ecs) case TARGET_WAITKIND_EXITED: case TARGET_WAITKIND_SIGNALLED: - if (debug_infrun) - { - if (ecs->ws.kind == TARGET_WAITKIND_EXITED) - fprintf_unfiltered (gdb_stdlog, - "infrun: TARGET_WAITKIND_EXITED\n"); - else - fprintf_unfiltered (gdb_stdlog, - "infrun: TARGET_WAITKIND_SIGNALLED\n"); - } - inferior_ptid = ecs->ptid; - set_current_inferior (find_inferior_ptid (ecs->ptid)); + set_current_inferior (find_inferior_ptid (ecs->target, 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. */ @@ -5089,14 +5243,6 @@ Cannot fill $_exitsignal with the correct signal number.\n")); the above cases end in a continue or goto. */ case TARGET_WAITKIND_FORKED: case TARGET_WAITKIND_VFORKED: - if (debug_infrun) - { - if (ecs->ws.kind == TARGET_WAITKIND_FORKED) - fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_FORKED\n"); - else - fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_VFORKED\n"); - } - /* Check whether the inferior is displaced stepping. */ { struct regcache *regcache = get_thread_regcache (ecs->event_thread); @@ -5107,7 +5253,7 @@ Cannot fill $_exitsignal with the correct signal number.\n")); if (displaced_step_in_progress_thread (ecs->event_thread)) { struct inferior *parent_inf - = find_inferior_ptid (ecs->ptid); + = find_inferior_ptid (ecs->target, ecs->ptid); struct regcache *child_regcache; CORE_ADDR parent_pc; @@ -5138,7 +5284,8 @@ Cannot fill $_exitsignal with the correct signal number.\n")); list yet at this point. */ child_regcache - = get_thread_arch_aspace_regcache (ecs->ws.value.related_pid, + = get_thread_arch_aspace_regcache (parent_inf->process_target (), + ecs->ws.value.related_pid, gdbarch, parent_inf->aspace); /* Read PC value of parent process. */ @@ -5183,11 +5330,13 @@ Cannot fill $_exitsignal with the correct signal number.\n")); and not immediately. */ ecs->event_thread->pending_follow = ecs->ws; - stop_pc = regcache_read_pc (get_thread_regcache (ecs->event_thread)); + ecs->event_thread->suspend.stop_pc + = regcache_read_pc (get_thread_regcache (ecs->event_thread)); ecs->event_thread->control.stop_bpstat = bpstat_stop_status (get_current_regcache ()->aspace (), - stop_pc, ecs->event_thread, &ecs->ws); + ecs->event_thread->suspend.stop_pc, + ecs->event_thread, &ecs->ws); if (handle_stop_requested (ecs)) return; @@ -5204,10 +5353,16 @@ Cannot fill $_exitsignal with the correct signal number.\n")); ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0; + process_stratum_target *targ + = ecs->event_thread->inf->process_target (); + should_resume = follow_fork (); + /* Note that one of these may be an invalid pointer, + depending on detach_fork. */ thread_info *parent = ecs->event_thread; - thread_info *child = find_thread_ptid (ecs->ws.value.related_pid); + thread_info *child + = find_thread_ptid (targ, ecs->ws.value.related_pid); /* At this point, the parent is marked running, and the child is marked stopped. */ @@ -5255,10 +5410,6 @@ Cannot fill $_exitsignal with the correct signal number.\n")); /* Done with the shared memory region. Re-insert breakpoints in the parent, and keep going. */ - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: TARGET_WAITKIND_VFORK_DONE\n"); - context_switch (ecs); current_inferior ()->waiting_for_vfork_done = 0; @@ -5273,8 +5424,6 @@ Cannot fill $_exitsignal with the correct signal number.\n")); return; case TARGET_WAITKIND_EXECD: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXECD\n"); /* Note we can't read registers yet (the stop_pc), because we don't yet know the inferior's post-exec architecture. @@ -5294,11 +5443,13 @@ Cannot fill $_exitsignal with the correct signal number.\n")); execd thread for that case (this is a nop otherwise). */ ecs->event_thread = inferior_thread (); - stop_pc = regcache_read_pc (get_thread_regcache (ecs->event_thread)); + ecs->event_thread->suspend.stop_pc + = regcache_read_pc (get_thread_regcache (ecs->event_thread)); ecs->event_thread->control.stop_bpstat = bpstat_stop_status (get_current_regcache ()->aspace (), - stop_pc, ecs->event_thread, &ecs->ws); + ecs->event_thread->suspend.stop_pc, + ecs->event_thread, &ecs->ws); /* Note that this may be referenced from inside bpstat_stop_status above, through inferior_has_execd. */ @@ -5321,9 +5472,6 @@ Cannot fill $_exitsignal with the correct signal number.\n")); /* Be careful not to try to gather much state about a thread that's in a syscall. It's frequently a losing proposition. */ case TARGET_WAITKIND_SYSCALL_ENTRY: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: TARGET_WAITKIND_SYSCALL_ENTRY\n"); /* Getting the current syscall number. */ if (handle_syscall_event (ecs) == 0) process_event_stop_test (ecs); @@ -5335,22 +5483,15 @@ Cannot fill $_exitsignal with the correct signal number.\n")); syscall. Stepping one instruction seems to get it back into user code.) */ case TARGET_WAITKIND_SYSCALL_RETURN: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, - "infrun: TARGET_WAITKIND_SYSCALL_RETURN\n"); if (handle_syscall_event (ecs) == 0) process_event_stop_test (ecs); return; case TARGET_WAITKIND_STOPPED: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_STOPPED\n"); handle_signal_stop (ecs); return; case TARGET_WAITKIND_NO_HISTORY: - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_NO_HISTORY\n"); /* Reverse execution: target ran out of history info. */ /* Switch to the stopped thread. */ @@ -5359,7 +5500,8 @@ Cannot fill $_exitsignal with the correct signal number.\n")); fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n"); delete_just_stopped_threads_single_step_breakpoints (); - stop_pc = regcache_read_pc (get_thread_regcache (inferior_thread ())); + ecs->event_thread->suspend.stop_pc + = regcache_read_pc (get_thread_regcache (inferior_thread ())); if (handle_stop_requested (ecs)) return; @@ -5370,22 +5512,6 @@ Cannot fill $_exitsignal with the correct signal number.\n")); } } -/* A wrapper around handle_inferior_event_1, which also makes sure - that all temporary struct value objects that were created during - the handling of the event get deleted at the end. */ - -static void -handle_inferior_event (struct execution_control_state *ecs) -{ - struct value *mark = value_mark (); - - handle_inferior_event_1 (ecs); - /* Purge all temporary values created during the event handling, - as it could be a long time before we return to the command level - where such values would otherwise be purged. */ - value_free_to_mark (mark); -} - /* Restart threads back to what they were trying to do back when we paused them for an in-line step-over. The EVENT_THREAD thread is ignored. */ @@ -5393,20 +5519,20 @@ handle_inferior_event (struct execution_control_state *ecs) static void restart_threads (struct thread_info *event_thread) { - struct thread_info *tp; - /* In case the instruction just stepped spawned a new thread. */ update_thread_list (); - ALL_NON_EXITED_THREADS (tp) + for (thread_info *tp : all_non_exited_threads ()) { + switch_to_thread_no_regs (tp); + if (tp == event_thread) { if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: restart threads: " "[%s] is event thread\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); continue; } @@ -5416,7 +5542,7 @@ restart_threads (struct thread_info *event_thread) fprintf_unfiltered (gdb_stdlog, "infrun: restart threads: " "[%s] not meant to be running\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); continue; } @@ -5425,7 +5551,7 @@ restart_threads (struct thread_info *event_thread) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: restart threads: [%s] resumed\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); gdb_assert (tp->executing || tp->suspend.waitstatus_pending_p); continue; } @@ -5436,7 +5562,7 @@ restart_threads (struct thread_info *event_thread) fprintf_unfiltered (gdb_stdlog, "infrun: restart threads: " "[%s] needs step-over\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); gdb_assert (!tp->resumed); continue; } @@ -5448,7 +5574,7 @@ restart_threads (struct thread_info *event_thread) fprintf_unfiltered (gdb_stdlog, "infrun: restart threads: " "[%s] has pending status\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); tp->resumed = 1; continue; } @@ -5463,7 +5589,7 @@ restart_threads (struct thread_info *event_thread) internal_error (__FILE__, __LINE__, "thread [%s] needs a step-over, but not in " "step-over queue\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); } if (currently_stepping (tp)) @@ -5471,7 +5597,7 @@ restart_threads (struct thread_info *event_thread) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: restart threads: [%s] was stepping\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); keep_going_stepped_thread (tp); } else @@ -5482,7 +5608,7 @@ restart_threads (struct thread_info *event_thread) if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: restart threads: [%s] continuing\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); reset_ecs (ecs, tp); switch_to_thread (tp); keep_going_pass_signal (ecs); @@ -5603,7 +5729,7 @@ finish_step_over (struct execution_control_state *ecs) "(currently_stepping=%d)\n", paddress (target_gdbarch (), tp->suspend.stop_pc), - target_pid_to_str (tp->ptid), + target_pid_to_str (tp->ptid).c_str (), currently_stepping (tp)); } @@ -5651,18 +5777,19 @@ handle_signal_stop (struct execution_control_state *ecs) && 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->event_thread)); + ecs->event_thread->suspend.stop_pc + = regcache_read_pc (get_thread_regcache (ecs->event_thread)); if (debug_infrun) { struct regcache *regcache = get_thread_regcache (ecs->event_thread); - struct gdbarch *gdbarch = regcache->arch (); - scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid); + struct gdbarch *reg_gdbarch = regcache->arch (); - inferior_ptid = ecs->ptid; + switch_to_thread (ecs->event_thread); fprintf_unfiltered (gdb_stdlog, "infrun: stop_pc = %s\n", - paddress (gdbarch, stop_pc)); + paddress (reg_gdbarch, + ecs->event_thread->suspend.stop_pc)); if (target_stopped_by_watchpoint ()) { CORE_ADDR addr; @@ -5672,7 +5799,7 @@ handle_signal_stop (struct execution_control_state *ecs) if (target_stopped_data_address (current_top_target (), &addr)) fprintf_unfiltered (gdb_stdlog, "infrun: stopped data address = %s\n", - paddress (gdbarch, addr)); + paddress (reg_gdbarch, addr)); else fprintf_unfiltered (gdb_stdlog, "infrun: (no data address available)\n"); @@ -5725,7 +5852,7 @@ handle_signal_stop (struct execution_control_state *ecs) /* See if something interesting happened to the non-current thread. If so, then switch to that thread. */ - if (!ptid_equal (ecs->ptid, inferior_ptid)) + if (ecs->ptid != inferior_ptid) { if (debug_infrun) fprintf_unfiltered (gdb_stdlog, "infrun: context switch\n"); @@ -5764,7 +5891,7 @@ handle_signal_stop (struct execution_control_state *ecs) fprintf_unfiltered (gdb_stdlog, "infrun: [%s] hit another thread's " "single-step breakpoint\n", - target_pid_to_str (ecs->ptid)); + target_pid_to_str (ecs->ptid).c_str ()); } ecs->hit_singlestep_breakpoint = 1; } @@ -5776,7 +5903,7 @@ handle_signal_stop (struct execution_control_state *ecs) fprintf_unfiltered (gdb_stdlog, "infrun: [%s] hit its " "single-step breakpoint\n", - target_pid_to_str (ecs->ptid)); + target_pid_to_str (ecs->ptid).c_str ()); } } } @@ -5858,14 +5985,18 @@ handle_signal_stop (struct execution_control_state *ecs) user had set a breakpoint on that inlined code, the missing skip_inline_frames call would break things. Fortunately that's an extremely unlikely scenario. */ - if (!pc_at_non_inline_function (aspace, stop_pc, &ecs->ws) + if (!pc_at_non_inline_function (aspace, + ecs->event_thread->suspend.stop_pc, + &ecs->ws) && !(ecs->event_thread->suspend.stop_signal == GDB_SIGNAL_TRAP && ecs->event_thread->control.trap_expected && pc_at_non_inline_function (aspace, ecs->event_thread->prev_pc, &ecs->ws))) { - stop_chain = build_bpstat_chain (aspace, stop_pc, &ecs->ws); + stop_chain = build_bpstat_chain (aspace, + ecs->event_thread->suspend.stop_pc, + &ecs->ws); skip_inline_frames (ecs->event_thread, stop_chain); /* Re-fetch current thread's frame in case that invalidated @@ -5915,7 +6046,8 @@ handle_signal_stop (struct execution_control_state *ecs) handles this event. */ ecs->event_thread->control.stop_bpstat = bpstat_stop_status (get_current_regcache ()->aspace (), - stop_pc, ecs->event_thread, &ecs->ws, stop_chain); + ecs->event_thread->suspend.stop_pc, + ecs->event_thread, &ecs->ws, stop_chain); /* Following in case break condition called a function. */ @@ -5967,7 +6099,8 @@ handle_signal_stop (struct execution_control_state *ecs) been removed. */ if (random_signal && target_stopped_by_sw_breakpoint ()) { - if (program_breakpoint_here_p (gdbarch, stop_pc)) + if (program_breakpoint_here_p (gdbarch, + ecs->event_thread->suspend.stop_pc)) { struct regcache *regcache; int decr_pc; @@ -5985,7 +6118,8 @@ handle_signal_stop (struct execution_control_state *ecs) restore_operation_disable.emplace (record_full_gdb_operation_disable_set ()); - regcache_write_pc (regcache, stop_pc + decr_pc); + regcache_write_pc (regcache, + ecs->event_thread->suspend.stop_pc + decr_pc); } } else @@ -6041,7 +6175,7 @@ handle_signal_stop (struct execution_control_state *ecs) if (random_signal) { /* Signal not for debugging purposes. */ - struct inferior *inf = find_inferior_ptid (ecs->ptid); + struct inferior *inf = find_inferior_ptid (ecs->target, ecs->ptid); enum gdb_signal stop_signal = ecs->event_thread->suspend.stop_signal; if (debug_infrun) @@ -6077,7 +6211,7 @@ handle_signal_stop (struct execution_control_state *ecs) if (signal_program[ecs->event_thread->suspend.stop_signal] == 0) ecs->event_thread->suspend.stop_signal = GDB_SIGNAL_0; - if (ecs->event_thread->prev_pc == stop_pc + if (ecs->event_thread->prev_pc == ecs->event_thread->suspend.stop_pc && ecs->event_thread->control.trap_expected && ecs->event_thread->control.step_resume_breakpoint == NULL) { @@ -6109,7 +6243,8 @@ handle_signal_stop (struct execution_control_state *ecs) } if (ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_0 - && (pc_in_thread_step_range (stop_pc, ecs->event_thread) + && (pc_in_thread_step_range (ecs->event_thread->suspend.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) @@ -6138,7 +6273,7 @@ handle_signal_stop (struct execution_control_state *ecs) return; } - /* Note: step_resume_breakpoint may be non-NULL. This occures + /* Note: step_resume_breakpoint may be non-NULL. This occurs when either there's a nested signal, or when there's a pending signal enabled just as the signal handler returns (leaving the inferior at the step-resume-breakpoint without @@ -6339,7 +6474,7 @@ process_event_stop_test (struct execution_control_state *ecs) return; } fill_in_stop_func (gdbarch, ecs); - if (stop_pc == ecs->stop_func_start + if (ecs->event_thread->suspend.stop_pc == ecs->stop_func_start && execution_direction == EXEC_REVERSE) { /* We are stepping over a function call in reverse, and just @@ -6472,7 +6607,8 @@ process_event_stop_test (struct execution_control_state *ecs) through a function epilogue and therefore must detect when the current-frame changes in the middle of a line. */ - if (pc_in_thread_step_range (stop_pc, ecs->event_thread) + if (pc_in_thread_step_range (ecs->event_thread->suspend.stop_pc, + ecs->event_thread) && (execution_direction != EXEC_REVERSE || frame_id_eq (get_frame_id (frame), ecs->event_thread->control.step_frame_id))) @@ -6491,6 +6627,7 @@ process_event_stop_test (struct execution_control_state *ecs) /* When stepping backward, stop at beginning of line range (unless it's the function entry point, in which case keep going back to the call point). */ + CORE_ADDR stop_pc = ecs->event_thread->suspend.stop_pc; if (stop_pc == ecs->event_thread->control.step_range_start && stop_pc != ecs->stop_func_start && execution_direction == EXEC_REVERSE) @@ -6517,10 +6654,11 @@ process_event_stop_test (struct execution_control_state *ecs) if (execution_direction != EXEC_REVERSE && ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE - && in_solib_dynsym_resolve_code (stop_pc)) + && in_solib_dynsym_resolve_code (ecs->event_thread->suspend.stop_pc)) { CORE_ADDR pc_after_resolver = - gdbarch_skip_solib_resolver (gdbarch, stop_pc); + gdbarch_skip_solib_resolver (gdbarch, + ecs->event_thread->suspend.stop_pc); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, @@ -6544,7 +6682,8 @@ process_event_stop_test (struct execution_control_state *ecs) /* Step through an indirect branch thunk. */ if (ecs->event_thread->control.step_over_calls != STEP_OVER_NONE - && gdbarch_in_indirect_branch_thunk (gdbarch, stop_pc)) + && gdbarch_in_indirect_branch_thunk (gdbarch, + ecs->event_thread->suspend.stop_pc)) { if (debug_infrun) fprintf_unfiltered (gdb_stdlog, @@ -6576,13 +6715,14 @@ process_event_stop_test (struct execution_control_state *ecs) call check below as on some targets return trampolines look like subroutine calls (MIPS16 return thunks). */ if (gdbarch_in_solib_return_trampoline (gdbarch, - stop_pc, ecs->stop_func_name) + ecs->event_thread->suspend.stop_pc, + ecs->stop_func_name) && ecs->event_thread->control.step_over_calls != STEP_OVER_NONE) { /* Determine where this trampoline returns. */ - CORE_ADDR real_stop_pc; - - real_stop_pc = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc); + CORE_ADDR stop_pc = ecs->event_thread->suspend.stop_pc; + CORE_ADDR real_stop_pc + = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc); if (debug_infrun) fprintf_unfiltered (gdb_stdlog, @@ -6634,8 +6774,9 @@ process_event_stop_test (struct execution_control_state *ecs) && (!frame_id_eq (ecs->event_thread->control.step_stack_frame_id, outer_frame_id) || (ecs->event_thread->control.step_start_function - != find_pc_function (stop_pc))))) + != find_pc_function (ecs->event_thread->suspend.stop_pc))))) { + CORE_ADDR stop_pc = ecs->event_thread->suspend.stop_pc; CORE_ADDR real_stop_pc; if (debug_infrun) @@ -6741,7 +6882,8 @@ process_event_stop_test (struct execution_control_state *ecs) tmp_sal = find_pc_line (ecs->stop_func_start, 0); if (tmp_sal.line != 0 && !function_name_is_marked_for_skip (ecs->stop_func_name, - tmp_sal)) + tmp_sal) + && !inline_frame_is_marked_for_skip (true, ecs->event_thread)) { if (execution_direction == EXEC_REVERSE) handle_step_into_function_backward (gdbarch, ecs); @@ -6793,6 +6935,8 @@ process_event_stop_test (struct execution_control_state *ecs) if (execution_direction == EXEC_REVERSE && ecs->event_thread->control.step_over_calls != STEP_OVER_NONE) { + CORE_ADDR stop_pc = ecs->event_thread->suspend.stop_pc; + if (gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc) || (ecs->stop_func_start == 0 && in_solib_dynsym_resolve_code (stop_pc))) @@ -6820,7 +6964,7 @@ process_event_stop_test (struct execution_control_state *ecs) } } - stop_pc_sal = find_pc_line (stop_pc, 0); + stop_pc_sal = find_pc_line (ecs->event_thread->suspend.stop_pc, 0); /* NOTE: tausq/2004-05-24: This if block used to be done before all the trampoline processing logic, however, there are some trampolines @@ -6905,7 +7049,14 @@ process_event_stop_test (struct execution_control_state *ecs) if (call_sal.line == ecs->event_thread->current_line && call_sal.symtab == ecs->event_thread->current_symtab) - step_into_inline_frame (ecs->event_thread); + { + step_into_inline_frame (ecs->event_thread); + if (inline_frame_is_marked_for_skip (false, ecs->event_thread)) + { + keep_going (ecs); + return; + } + } end_stepping_range (ecs); return; @@ -6939,14 +7090,15 @@ process_event_stop_test (struct execution_control_state *ecs) fprintf_unfiltered (gdb_stdlog, "infrun: stepping through inlined function\n"); - if (ecs->event_thread->control.step_over_calls == STEP_OVER_ALL) + if (ecs->event_thread->control.step_over_calls == STEP_OVER_ALL + || inline_frame_is_marked_for_skip (false, ecs->event_thread)) keep_going (ecs); else end_stepping_range (ecs); return; } - if ((stop_pc == stop_pc_sal.pc) + if ((ecs->event_thread->suspend.stop_pc == stop_pc_sal.pc) && (ecs->event_thread->current_line != stop_pc_sal.line || ecs->event_thread->current_symtab != stop_pc_sal.symtab)) { @@ -6988,7 +7140,6 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) { if (!target_is_non_stop_p ()) { - struct thread_info *tp; struct thread_info *stepping_thread; /* If any thread is blocked on some internal breakpoint, and we @@ -7011,7 +7162,7 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) { fprintf_unfiltered (gdb_stdlog, "infrun: need to finish step-over of [%s]\n", - target_pid_to_str (ecs->event_thread->ptid)); + target_pid_to_str (ecs->event_thread->ptid).c_str ()); } keep_going (ecs); return 1; @@ -7026,7 +7177,7 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) fprintf_unfiltered (gdb_stdlog, "infrun: need to step [%s] over single-step " "breakpoint\n", - target_pid_to_str (ecs->ptid)); + target_pid_to_str (ecs->ptid).c_str ()); } keep_going (ecs); return 1; @@ -7041,7 +7192,7 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) { fprintf_unfiltered (gdb_stdlog, "infrun: thread [%s] still needs step-over\n", - target_pid_to_str (ecs->event_thread->ptid)); + target_pid_to_str (ecs->event_thread->ptid).c_str ()); } keep_going (ecs); return 1; @@ -7075,12 +7226,15 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) /* Look for the stepping/nexting thread. */ stepping_thread = NULL; - ALL_NON_EXITED_THREADS (tp) + for (thread_info *tp : all_non_exited_threads ()) { + switch_to_thread_no_regs (tp); + /* Ignore threads of processes the caller is not resuming. */ if (!sched_multi - && ptid_get_pid (tp->ptid) != ptid_get_pid (ecs->ptid)) + && (tp->inf->process_target () != ecs->target + || tp->inf->pid != ecs->ptid.pid ())) continue; /* When stepping over a breakpoint, we lock all threads @@ -7092,7 +7246,7 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) internal_error (__FILE__, __LINE__, "[%s] has inconsistent state: " "trap_expected=%d\n", - target_pid_to_str (tp->ptid), + target_pid_to_str (tp->ptid).c_str (), tp->control.trap_expected); } @@ -7128,6 +7282,8 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) return 1; } } + + switch_to_thread (ecs->event_thread); } return 0; @@ -7180,7 +7336,7 @@ keep_going_stepped_thread (struct thread_info *tp) reset_ecs (ecs, tp); switch_to_thread (tp); - stop_pc = regcache_read_pc (get_thread_regcache (tp)); + tp->suspend.stop_pc = regcache_read_pc (get_thread_regcache (tp)); frame = get_current_frame (); /* If the PC of the thread we were trying to single-step has @@ -7196,7 +7352,7 @@ keep_going_stepped_thread (struct thread_info *tp) This prevents us continuously moving the single-step breakpoint forward, one instruction at a time, overstepping. */ - if (stop_pc != tp->prev_pc) + if (tp->suspend.stop_pc != tp->prev_pc) { ptid_t resume_ptid; @@ -7204,7 +7360,7 @@ keep_going_stepped_thread (struct thread_info *tp) fprintf_unfiltered (gdb_stdlog, "infrun: expected thread advanced also (%s -> %s)\n", paddress (target_gdbarch (), tp->prev_pc), - paddress (target_gdbarch (), stop_pc)); + paddress (target_gdbarch (), tp->suspend.stop_pc)); /* Clear the info of the previous step-over, as it's no longer valid (if the thread was trying to step over a breakpoint, it @@ -7218,7 +7374,7 @@ keep_going_stepped_thread (struct thread_info *tp) insert_single_step_breakpoint (get_frame_arch (frame), get_frame_address_space (frame), - stop_pc); + tp->suspend.stop_pc); tp->resumed = 1; resume_ptid = internal_resume_ptid (tp->control.stepping_command); @@ -7259,7 +7415,8 @@ handle_step_into_function (struct gdbarch *gdbarch, { fill_in_stop_func (gdbarch, ecs); - compunit_symtab *cust = find_pc_compunit_symtab (stop_pc); + compunit_symtab *cust + = find_pc_compunit_symtab (ecs->event_thread->suspend.stop_pc); if (cust != NULL && compunit_language (cust) != language_asm) ecs->stop_func_start = gdbarch_skip_prologue_noexcept (gdbarch, ecs->stop_func_start); @@ -7299,7 +7456,7 @@ handle_step_into_function (struct gdbarch *gdbarch, ecs->stop_func_start); } - if (ecs->stop_func_start == stop_pc) + if (ecs->stop_func_start == ecs->event_thread->suspend.stop_pc) { /* We are already there: stop now. */ end_stepping_range (ecs); @@ -7338,15 +7495,15 @@ handle_step_into_function_backward (struct gdbarch *gdbarch, fill_in_stop_func (gdbarch, ecs); - cust = find_pc_compunit_symtab (stop_pc); + cust = find_pc_compunit_symtab (ecs->event_thread->suspend.stop_pc); if (cust != NULL && compunit_language (cust) != language_asm) ecs->stop_func_start = gdbarch_skip_prologue_noexcept (gdbarch, ecs->stop_func_start); - stop_func_sal = find_pc_line (stop_pc, 0); + stop_func_sal = find_pc_line (ecs->event_thread->suspend.stop_pc, 0); /* OK, we're just going to keep stepping here. */ - if (stop_func_sal.pc == stop_pc) + if (stop_func_sal.pc == ecs->event_thread->suspend.stop_pc) { /* We're there already. Just stop stepping now. */ end_stepping_range (ecs); @@ -7488,14 +7645,14 @@ insert_exception_resume_breakpoint (struct thread_info *tp, struct frame_info *frame, struct symbol *sym) { - TRY + try { struct block_symbol vsym; struct value *value; CORE_ADDR handler; struct breakpoint *bp; - vsym = lookup_symbol_search_name (SYMBOL_SEARCH_NAME (sym), + vsym = lookup_symbol_search_name (sym->search_name (), b, VAR_DOMAIN); value = read_var_value (vsym.symbol, vsym.block, frame); /* If the value was optimized out, revert to the old behavior. */ @@ -7519,11 +7676,10 @@ insert_exception_resume_breakpoint (struct thread_info *tp, inferior_thread ()->control.exception_resume_breakpoint = bp; } } - CATCH (e, RETURN_MASK_ERROR) + catch (const gdb_exception_error &e) { /* We want to ignore errors here. */ } - END_CATCH } /* A helper for check_exception_resume that sets an @@ -7582,7 +7738,7 @@ check_exception_resume (struct execution_control_state *ecs, if (!func) return; - TRY + try { const struct block *b; struct block_iterator iter; @@ -7619,10 +7775,9 @@ check_exception_resume (struct execution_control_state *ecs, } } } - CATCH (e, RETURN_MASK_ERROR) + catch (const gdb_exception_error &e) { } - END_CATCH } static void @@ -7646,7 +7801,7 @@ stop_waiting (struct execution_control_state *ecs) static void keep_going_pass_signal (struct execution_control_state *ecs) { - gdb_assert (ptid_equal (ecs->event_thread->ptid, inferior_ptid)); + gdb_assert (ecs->event_thread->ptid == inferior_ptid); gdb_assert (!ecs->event_thread->resumed); /* Save the pc before execution, to compare with pc after stop. */ @@ -7661,7 +7816,7 @@ keep_going_pass_signal (struct execution_control_state *ecs) fprintf_unfiltered (gdb_stdlog, "infrun: %s has trap_expected set, " "resuming to collect trap\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); /* We haven't yet gotten our trap, and either: intercepted a non-signal event (e.g., a fork); or took a signal which we @@ -7683,7 +7838,7 @@ keep_going_pass_signal (struct execution_control_state *ecs) fprintf_unfiltered (gdb_stdlog, "infrun: step-over already in progress: " "step-over for %s deferred\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); thread_step_over_chain_enqueue (tp); } else @@ -7692,7 +7847,7 @@ keep_going_pass_signal (struct execution_control_state *ecs) fprintf_unfiltered (gdb_stdlog, "infrun: step-over in progress: " "resume of %s deferred\n", - target_pid_to_str (tp->ptid)); + target_pid_to_str (tp->ptid).c_str ()); } } else @@ -7749,18 +7904,17 @@ keep_going_pass_signal (struct execution_control_state *ecs) stop_all_threads (); /* Stop stepping if inserting breakpoints fails. */ - TRY + try { insert_breakpoints (); } - CATCH (e, RETURN_MASK_ERROR) + catch (const gdb_exception_error &e) { exception_print (gdb_stderr, e); stop_waiting (ecs); clear_step_over_info (); return; } - END_CATCH ecs->event_thread->control.trap_expected = (remove_bp || remove_wps); @@ -7860,31 +8014,26 @@ 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)); + std::string pidstr = target_pid_to_str (ptid_t (inf->pid)); annotate_exited (exitstatus); if (exitstatus) { if (uiout->is_mi_like_p ()) uiout->field_string ("reason", async_reason_lookup (EXEC_ASYNC_EXITED)); - uiout->text ("[Inferior "); - uiout->text (plongest (inf->num)); - uiout->text (" ("); - uiout->text (pidstr); - uiout->text (") exited with code "); - uiout->field_fmt ("exit-code", "0%o", (unsigned int) exitstatus); - uiout->text ("]\n"); + std::string exit_code_str + = string_printf ("0%o", (unsigned int) exitstatus); + uiout->message ("[Inferior %s (%s) exited with code %pF]\n", + plongest (inf->num), pidstr.c_str (), + string_field ("exit-code", exit_code_str.c_str ())); } else { if (uiout->is_mi_like_p ()) uiout->field_string ("reason", async_reason_lookup (EXEC_ASYNC_EXITED_NORMALLY)); - uiout->text ("[Inferior "); - uiout->text (plongest (inf->num)); - uiout->text (" ("); - uiout->text (pidstr); - uiout->text (") exited normally]\n"); + uiout->message ("[Inferior %s (%s) exited normally]\n", + plongest (inf->num), pidstr.c_str ()); } } @@ -7916,13 +8065,13 @@ print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal) const char *name; uiout->text ("\nThread "); - uiout->field_fmt ("thread-id", "%s", print_thread_id (thr)); + uiout->field_string ("thread-id", print_thread_id (thr)); name = thr->name != NULL ? thr->name : target_thread_name (thr); if (name != NULL) { uiout->text (" \""); - uiout->field_fmt ("name", "%s", name); + uiout->field_string ("name", name); uiout->text ("\""); } } @@ -7981,7 +8130,8 @@ print_stop_location (struct target_waitstatus *ws) 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)) + && (tp->control.step_start_function + == find_pc_function (tp->suspend.stop_pc))) { /* Finished step, just print source line. */ source_flag = SRC_LINE; @@ -8020,13 +8170,12 @@ print_stop_location (struct target_waitstatus *ws) /* See infrun.h. */ void -print_stop_event (struct ui_out *uiout) +print_stop_event (struct ui_out *uiout, bool displays) { struct target_waitstatus last; - ptid_t last_ptid; struct thread_info *tp; - get_last_target_status (&last_ptid, &last); + get_last_target_status (nullptr, nullptr, &last); { scoped_restore save_uiout = make_scoped_restore (¤t_uiout, uiout); @@ -8034,16 +8183,17 @@ print_stop_event (struct ui_out *uiout) print_stop_location (&last); /* Display the auto-display expressions. */ - do_displays (); + if (displays) + do_displays (); } tp = inferior_thread (); if (tp->thread_fsm != NULL - && thread_fsm_finished_p (tp->thread_fsm)) + && tp->thread_fsm->finished_p ()) { struct return_value_info *rv; - rv = thread_fsm_return_value (tp->thread_fsm); + rv = tp->thread_fsm->return_value (); if (rv != NULL) print_return_value (uiout, rv); } @@ -8070,6 +8220,13 @@ maybe_remove_breakpoints (void) struct stop_context { + stop_context (); + ~stop_context (); + + DISABLE_COPY_AND_ASSIGN (stop_context); + + bool changed () const; + /* The stop ID. */ ULONGEST stop_id; @@ -8085,59 +8242,50 @@ struct stop_context int inf_num; }; -/* Returns a new stop context. If stopped for a thread event, this +/* Initializes a new stop context. If stopped for a thread event, this takes a strong reference to the thread. */ -static struct stop_context * -save_stop_context (void) +stop_context::stop_context () { - struct stop_context *sc = XNEW (struct stop_context); + stop_id = get_stop_id (); + ptid = inferior_ptid; + inf_num = current_inferior ()->num; - sc->stop_id = get_stop_id (); - sc->ptid = inferior_ptid; - sc->inf_num = current_inferior ()->num; - - if (!ptid_equal (inferior_ptid, null_ptid)) + if (inferior_ptid != null_ptid) { /* Take a strong reference so that the thread can't be deleted yet. */ - sc->thread = inferior_thread (); - sc->thread->incref (); + thread = inferior_thread (); + thread->incref (); } else - sc->thread = NULL; - - return sc; + thread = NULL; } /* Release a stop context previously created with save_stop_context. Releases the strong reference to the thread as well. */ -static void -release_stop_context_cleanup (void *arg) +stop_context::~stop_context () { - struct stop_context *sc = (struct stop_context *) arg; - - if (sc->thread != NULL) - sc->thread->decref (); - xfree (sc); + if (thread != NULL) + thread->decref (); } /* Return true if the current context no longer matches the saved stop context. */ -static int -stop_context_changed (struct stop_context *prev) -{ - if (!ptid_equal (prev->ptid, inferior_ptid)) - return 1; - if (prev->inf_num != current_inferior ()->num) - return 1; - if (prev->thread != NULL && prev->thread->state != THREAD_STOPPED) - return 1; - if (get_stop_id () != prev->stop_id) - return 1; - return 0; +bool +stop_context::changed () const +{ + if (ptid != inferior_ptid) + return true; + if (inf_num != current_inferior ()->num) + return true; + if (thread != NULL && thread->state != THREAD_STOPPED) + return true; + if (get_stop_id () != stop_id) + return true; + return false; } /* See infrun.h. */ @@ -8146,9 +8294,8 @@ int normal_stop (void) { struct target_waitstatus last; - ptid_t last_ptid; - get_last_target_status (&last_ptid, &last); + get_last_target_status (nullptr, nullptr, &last); new_stop_id (); @@ -8157,10 +8304,10 @@ normal_stop (void) frontend/user running state. A QUIT is an easy exception to see here, so do this before any filtered output. */ - gdb::optional maybe_finish_thread_state; + ptid_t finish_ptid = null_ptid; if (!non_stop) - maybe_finish_thread_state.emplace (minus_one_ptid); + finish_ptid = minus_one_ptid; else if (last.kind == TARGET_WAITKIND_SIGNALLED || last.kind == TARGET_WAITKIND_EXITED) { @@ -8170,10 +8317,17 @@ normal_stop (void) linux-fork.c automatically switches to another fork from within target_mourn_inferior. */ if (inferior_ptid != null_ptid) - maybe_finish_thread_state.emplace (ptid_t (inferior_ptid.pid ())); + finish_ptid = ptid_t (inferior_ptid.pid ()); } else if (last.kind != TARGET_WAITKIND_NO_RESUMED) - maybe_finish_thread_state.emplace (inferior_ptid); + finish_ptid = inferior_ptid; + + gdb::optional maybe_finish_thread_state; + if (finish_ptid != null_ptid) + { + maybe_finish_thread_state.emplace + (user_visible_resume_target (finish_ptid), finish_ptid); + } /* As we're presenting a stop, and potentially removing breakpoints, update the thread list so we can tell whether there are threads @@ -8215,7 +8369,7 @@ normal_stop (void) { target_terminal::ours_for_output (); printf_filtered (_("[Switching to %s]\n"), - target_pid_to_str (inferior_ptid)); + target_pid_to_str (inferior_ptid).c_str ()); annotate_thread_changed (); } previous_inferior_ptid = inferior_ptid; @@ -8280,37 +8434,30 @@ normal_stop (void) of stop_command's pre-hook not existing). */ if (stop_command != NULL) { - struct stop_context *saved_context = save_stop_context (); - struct cleanup *old_chain - = make_cleanup (release_stop_context_cleanup, saved_context); + stop_context saved_context; - TRY + try { execute_cmd_pre_hook (stop_command); } - CATCH (ex, RETURN_MASK_ALL) + catch (const gdb_exception &ex) { exception_fprintf (gdb_stderr, ex, "Error while running hook_stop:\n"); } - END_CATCH /* If the stop hook resumes the target, then there's no point in trying to notify about the previous stop; its context is gone. Likewise if the command switches thread or inferior -- the observers would print a stop for the wrong thread/inferior. */ - if (stop_context_changed (saved_context)) - { - do_cleanups (old_chain); - return 1; - } - do_cleanups (old_chain); + if (saved_context.changed ()) + return 1; } /* Notify observers about the stop. This is where the interpreters print the stop event. */ - if (!ptid_equal (inferior_ptid, null_ptid)) + if (inferior_ptid != null_ptid) gdb::observers::normal_stop.notify (inferior_thread ()->control.stop_bpstat, stop_print_frame); else @@ -8321,7 +8468,8 @@ normal_stop (void) if (target_has_execution) { if (last.kind != TARGET_WAITKIND_SIGNALLED - && last.kind != TARGET_WAITKIND_EXITED) + && last.kind != TARGET_WAITKIND_EXITED + && last.kind != TARGET_WAITKIND_NO_RESUMED) /* Delete the breakpoint we stopped at, if it wants to be deleted. Delete any breakpoint that is to be deleted at the next stop. */ breakpoint_auto_delete (inferior_thread ()->control.stop_bpstat); @@ -8411,7 +8559,7 @@ signal_catch_update (const unsigned int *info) for (i = 0; i < GDB_SIGNAL_LAST; ++i) signal_catch[i] = info[i] > 0; signal_cache_update (-1); - target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass); + target_pass_signals (signal_pass); } static void @@ -8444,11 +8592,9 @@ static void handle_command (const char *args, int from_tty) { int digits, wordlen; - int sigfirst, signum, siglast; + int sigfirst, siglast; enum gdb_signal oursig; int allsigs; - int nsigs; - unsigned char *sigs; if (args == NULL) { @@ -8457,9 +8603,8 @@ handle_command (const char *args, int from_tty) /* Allocate and zero an array of flags for which signals to handle. */ - nsigs = (int) GDB_SIGNAL_LAST; - sigs = (unsigned char *) alloca (nsigs); - memset (sigs, 0, nsigs); + const size_t nsigs = GDB_SIGNAL_LAST; + unsigned char sigs[nsigs] {}; /* Break the command line up into args. */ @@ -8539,9 +8684,7 @@ handle_command (const char *args, int from_tty) if (sigfirst > siglast) { /* Bet he didn't figure we'd think of this case... */ - signum = sigfirst; - sigfirst = siglast; - siglast = signum; + std::swap (sigfirst, siglast); } } else @@ -8561,7 +8704,7 @@ handle_command (const char *args, int from_tty) /* If any signal numbers or symbol names were found, set flags for which signals to apply actions to. */ - for (signum = sigfirst; signum >= 0 && signum <= siglast; signum++) + for (int signum = sigfirst; signum >= 0 && signum <= siglast; signum++) { switch ((enum gdb_signal) signum) { @@ -8576,10 +8719,7 @@ Are you sure you want to change it? "), sigs[signum] = 1; } else - { - printf_unfiltered (_("Not confirmed, unchanged.\n")); - gdb_flush (gdb_stdout); - } + printf_unfiltered (_("Not confirmed, unchanged.\n")); } break; case GDB_SIGNAL_0: @@ -8594,12 +8734,12 @@ Are you sure you want to change it? "), } } - for (signum = 0; signum < nsigs; signum++) + for (int signum = 0; signum < nsigs; signum++) if (sigs[signum]) { signal_cache_update (-1); - target_pass_signals ((int) GDB_SIGNAL_LAST, signal_pass); - target_program_signals ((int) GDB_SIGNAL_LAST, signal_program); + target_pass_signals (signal_pass); + target_program_signals (signal_program); if (from_tty) { @@ -8762,7 +8902,7 @@ siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var, void *ignore) { if (target_has_stack - && !ptid_equal (inferior_ptid, null_ptid) + && inferior_ptid != null_ptid && gdbarch_get_siginfo_type_p (gdbarch)) { struct type *type = gdbarch_get_siginfo_type (gdbarch); @@ -8780,70 +8920,105 @@ siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var, ends (either successfully, or after it hits a breakpoint or signal) if the program is to properly continue where it left off. */ -struct infcall_suspend_state +class infcall_suspend_state { - struct thread_suspend_state thread_suspend; +public: + /* Capture state from GDBARCH, TP, and REGCACHE that must be restored + once the inferior function call has finished. */ + infcall_suspend_state (struct gdbarch *gdbarch, + const struct thread_info *tp, + struct regcache *regcache) + : m_thread_suspend (tp->suspend), + m_registers (new readonly_detached_regcache (*regcache)) + { + gdb::unique_xmalloc_ptr siginfo_data; - /* Other fields: */ - CORE_ADDR stop_pc; - readonly_detached_regcache *registers; + if (gdbarch_get_siginfo_type_p (gdbarch)) + { + struct type *type = gdbarch_get_siginfo_type (gdbarch); + size_t len = TYPE_LENGTH (type); + + siginfo_data.reset ((gdb_byte *) xmalloc (len)); + + if (target_read (current_top_target (), TARGET_OBJECT_SIGNAL_INFO, NULL, + siginfo_data.get (), 0, len) != len) + { + /* Errors ignored. */ + siginfo_data.reset (nullptr); + } + } + + if (siginfo_data) + { + m_siginfo_gdbarch = gdbarch; + m_siginfo_data = std::move (siginfo_data); + } + } + + /* Return a pointer to the stored register state. */ + + readonly_detached_regcache *registers () const + { + return m_registers.get (); + } + + /* Restores the stored state into GDBARCH, TP, and REGCACHE. */ + + void restore (struct gdbarch *gdbarch, + struct thread_info *tp, + struct regcache *regcache) const + { + tp->suspend = m_thread_suspend; + + if (m_siginfo_gdbarch == gdbarch) + { + struct type *type = gdbarch_get_siginfo_type (gdbarch); + + /* Errors ignored. */ + target_write (current_top_target (), TARGET_OBJECT_SIGNAL_INFO, NULL, + m_siginfo_data.get (), 0, TYPE_LENGTH (type)); + } + + /* The inferior can be gone if the user types "print exit(0)" + (and perhaps other times). */ + if (target_has_execution) + /* NB: The register write goes through to the target. */ + regcache->restore (registers ()); + } + +private: + /* How the current thread stopped before the inferior function call was + executed. */ + struct thread_suspend_state m_thread_suspend; + + /* The registers before the inferior function call was executed. */ + std::unique_ptr m_registers; /* Format of SIGINFO_DATA or NULL if it is not present. */ - struct gdbarch *siginfo_gdbarch; + struct gdbarch *m_siginfo_gdbarch = nullptr; /* The inferior format depends on SIGINFO_GDBARCH and it has a length of TYPE_LENGTH (gdbarch_get_siginfo_type ()). For different gdbarch the content would be invalid. */ - gdb_byte *siginfo_data; + gdb::unique_xmalloc_ptr m_siginfo_data; }; -struct infcall_suspend_state * -save_infcall_suspend_state (void) +infcall_suspend_state_up +save_infcall_suspend_state () { - struct infcall_suspend_state *inf_state; struct thread_info *tp = inferior_thread (); struct regcache *regcache = get_current_regcache (); struct gdbarch *gdbarch = regcache->arch (); - gdb_byte *siginfo_data = NULL; - - if (gdbarch_get_siginfo_type_p (gdbarch)) - { - struct type *type = gdbarch_get_siginfo_type (gdbarch); - size_t len = TYPE_LENGTH (type); - struct cleanup *back_to; - - siginfo_data = (gdb_byte *) xmalloc (len); - back_to = make_cleanup (xfree, siginfo_data); - - if (target_read (current_top_target (), TARGET_OBJECT_SIGNAL_INFO, NULL, - siginfo_data, 0, len) == len) - discard_cleanups (back_to); - else - { - /* Errors ignored. */ - do_cleanups (back_to); - siginfo_data = NULL; - } - } - - inf_state = XCNEW (struct infcall_suspend_state); - - if (siginfo_data) - { - inf_state->siginfo_gdbarch = gdbarch; - inf_state->siginfo_data = siginfo_data; - } - inf_state->thread_suspend = tp->suspend; + infcall_suspend_state_up inf_state + (new struct infcall_suspend_state (gdbarch, tp, regcache)); - /* run_inferior_call will not use the signal due to its `proceed' call with - GDB_SIGNAL_0 anyway. */ + /* Having saved the current state, adjust the thread state, discarding + any stop signal information. The stop signal is not useful when + starting an inferior function call, and run_inferior_call will not use + the signal due to its `proceed' call with GDB_SIGNAL_0. */ tp->suspend.stop_signal = GDB_SIGNAL_0; - inf_state->stop_pc = stop_pc; - - inf_state->registers = new readonly_detached_regcache (*regcache); - return inf_state; } @@ -8856,53 +9031,20 @@ restore_infcall_suspend_state (struct infcall_suspend_state *inf_state) struct regcache *regcache = get_current_regcache (); struct gdbarch *gdbarch = regcache->arch (); - tp->suspend = inf_state->thread_suspend; - - stop_pc = inf_state->stop_pc; - - if (inf_state->siginfo_gdbarch == gdbarch) - { - struct type *type = gdbarch_get_siginfo_type (gdbarch); - - /* Errors ignored. */ - target_write (current_top_target (), TARGET_OBJECT_SIGNAL_INFO, NULL, - inf_state->siginfo_data, 0, TYPE_LENGTH (type)); - } - - /* The inferior can be gone if the user types "print exit(0)" - (and perhaps other times). */ - if (target_has_execution) - /* NB: The register write goes through to the target. */ - regcache->restore (inf_state->registers); - + inf_state->restore (gdbarch, tp, regcache); discard_infcall_suspend_state (inf_state); } -static void -do_restore_infcall_suspend_state_cleanup (void *state) -{ - restore_infcall_suspend_state ((struct infcall_suspend_state *) state); -} - -struct cleanup * -make_cleanup_restore_infcall_suspend_state - (struct infcall_suspend_state *inf_state) -{ - return make_cleanup (do_restore_infcall_suspend_state_cleanup, inf_state); -} - void discard_infcall_suspend_state (struct infcall_suspend_state *inf_state) { - delete inf_state->registers; - xfree (inf_state->siginfo_data); - xfree (inf_state); + delete inf_state; } readonly_detached_regcache * get_infcall_suspend_state_regcache (struct infcall_suspend_state *inf_state) { - return inf_state->registers; + return inf_state->registers (); } /* infcall_control_state contains state regarding gdb's control of the @@ -8915,21 +9057,20 @@ struct infcall_control_state struct inferior_control_state inferior_control; /* Other fields: */ - enum stop_stack_kind stop_stack_dummy; - int stopped_by_random_signal; + enum stop_stack_kind stop_stack_dummy = STOP_NONE; + int stopped_by_random_signal = 0; /* ID if the selected frame when the inferior function call was made. */ - struct frame_id selected_frame_id; + struct frame_id selected_frame_id {}; }; /* Save all of the information associated with the inferior<==>gdb connection. */ -struct infcall_control_state * -save_infcall_control_state (void) +infcall_control_state_up +save_infcall_control_state () { - struct infcall_control_state *inf_status = - XNEW (struct infcall_control_state); + infcall_control_state_up inf_status (new struct infcall_control_state); struct thread_info *tp = inferior_thread (); struct inferior *inf = current_inferior (); @@ -9000,11 +9141,11 @@ restore_infcall_control_state (struct infcall_control_state *inf_status) /* The point of the try/catch is that if the stack is clobbered, walking the stack might encounter a garbage pointer and error() trying to dereference it. */ - TRY + try { restore_selected_frame (inf_status->selected_frame_id); } - CATCH (ex, RETURN_MASK_ERROR) + catch (const gdb_exception_error &ex) { exception_fprintf (gdb_stderr, ex, "Unable to restore previously selected frame:\n"); @@ -9012,23 +9153,9 @@ restore_infcall_control_state (struct infcall_control_state *inf_status) innermost frame. */ select_frame (get_current_frame ()); } - END_CATCH } - xfree (inf_status); -} - -static void -do_restore_infcall_control_state_cleanup (void *sts) -{ - restore_infcall_control_state ((struct infcall_control_state *) sts); -} - -struct cleanup * -make_cleanup_restore_infcall_control_state - (struct infcall_control_state *inf_status) -{ - return make_cleanup (do_restore_infcall_control_state_cleanup, inf_status); + delete inf_status; } void @@ -9045,7 +9172,7 @@ discard_infcall_control_state (struct infcall_control_state *inf_status) /* See save_infcall_control_state for info on stop_bpstat. */ bpstat_clear (&inf_status->thread_control.stop_bpstat); - xfree (inf_status); + delete inf_status; } /* See infrun.h. */ @@ -9137,8 +9264,6 @@ infrun_async_inferior_event_handler (gdb_client_data data) void _initialize_infrun (void) { - int i; - int numsigs; struct cmd_list_element *c; /* Register extra event sources in the event loop. */ @@ -9220,13 +9345,7 @@ leave it stopped or free to run as needed."), &setlist, &showlist); - numsigs = (int) GDB_SIGNAL_LAST; - signal_stop = XNEWVEC (unsigned char, numsigs); - signal_print = XNEWVEC (unsigned char, numsigs); - signal_program = XNEWVEC (unsigned char, numsigs); - signal_catch = XNEWVEC (unsigned char, numsigs); - signal_pass = XNEWVEC (unsigned char, numsigs); - for (i = 0; i < numsigs; i++) + for (size_t i = 0; i < GDB_SIGNAL_LAST; i++) { signal_stop[i] = 1; signal_print[i] = 1;