gdb: add interp::on_user_selected_context_changed method
[binutils-gdb.git] / gdb / infrun.c
index 8507796cc313eb6f2d44ab8123e93895667eea2c..d4334302a9963f6ffa6413c697f5334251fa68c9 100644 (file)
@@ -1,7 +1,7 @@
 /* Target-struct-independent code to start (run) and stop an inferior
    process.
 
-   Copyright (C) 1986-2022 Free Software Foundation, Inc.
+   Copyright (C) 1986-2023 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -34,6 +34,7 @@
 #include "annotate.h"
 #include "symfile.h"
 #include "top.h"
+#include "ui.h"
 #include "inf-loop.h"
 #include "regcache.h"
 #include "value.h"
@@ -73,6 +74,9 @@
 #include "test-target.h"
 #include "gdbsupport/common-debug.h"
 #include "gdbsupport/buildargv.h"
+#include "extension.h"
+#include "disasm.h"
+#include "interps.h"
 
 /* Prototypes for local functions */
 
@@ -149,10 +153,29 @@ show_step_stop_if_no_debug (struct ui_file *file, int from_tty,
 }
 
 /* proceed and normal_stop use this to notify the user when the
-   inferior stopped in a different thread than it had been running
-   in.  */
+   inferior stopped in a different thread than it had been running in.
+   It can also be used to find for which thread normal_stop last
+   reported a stop.  */
+static thread_info_ref previous_thread;
 
-static ptid_t previous_inferior_ptid;
+/* See infrun.h.  */
+
+void
+update_previous_thread ()
+{
+  if (inferior_ptid == null_ptid)
+    previous_thread = nullptr;
+  else
+    previous_thread = thread_info_ref::new_reference (inferior_thread ());
+}
+
+/* See infrun.h.  */
+
+thread_info *
+get_previous_thread ()
+{
+  return previous_thread.get ();
+}
 
 /* If set (default for legacy reasons), when following a fork, GDB
    will detach from one of the fork branches, child or parent.
@@ -259,7 +282,7 @@ set_observer_mode (const char *args, int from_tty,
      going out we leave it that way.  */
   if (observer_mode)
     {
-      pagination_enabled = 0;
+      pagination_enabled = false;
       non_stop = non_stop_1 = true;
     }
 
@@ -388,7 +411,7 @@ static const char follow_fork_mode_parent[] = "parent";
 static const char *const follow_fork_mode_kind_names[] = {
   follow_fork_mode_child,
   follow_fork_mode_parent,
-  NULL
+  nullptr
 };
 
 static const char *follow_fork_mode_string = follow_fork_mode_parent;
@@ -478,7 +501,7 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
          child_inf->attach_flag = parent_inf->attach_flag;
          copy_terminal_info (child_inf, parent_inf);
          child_inf->gdbarch = parent_inf->gdbarch;
-         copy_inferior_target_desc_info (child_inf, parent_inf);
+         child_inf->tdesc_info = parent_inf->tdesc_info;
 
          child_inf->symfile_flags = SYMFILE_NO_READ;
 
@@ -495,15 +518,15 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
                 with the shared region.  Keep track of the
                 parent.  */
              child_inf->vfork_parent = parent_inf;
-             child_inf->pending_detach = 0;
+             child_inf->pending_detach = false;
              parent_inf->vfork_child = child_inf;
-             parent_inf->pending_detach = 0;
+             parent_inf->pending_detach = false;
            }
          else
            {
              child_inf->aspace = new address_space ();
              child_inf->pspace = new program_space (child_inf->aspace);
-             child_inf->removable = 1;
+             child_inf->removable = true;
              clone_program_space (child_inf->pspace, parent_inf->pspace);
            }
        }
@@ -546,7 +569,7 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
       child_inf->attach_flag = parent_inf->attach_flag;
       copy_terminal_info (child_inf, parent_inf);
       child_inf->gdbarch = parent_inf->gdbarch;
-      copy_inferior_target_desc_info (child_inf, parent_inf);
+      child_inf->tdesc_info = parent_inf->tdesc_info;
 
       if (has_vforked)
        {
@@ -585,7 +608,7 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
        {
          child_inf->aspace = new address_space ();
          child_inf->pspace = new program_space (child_inf->aspace);
-         child_inf->removable = 1;
+         child_inf->removable = true;
          child_inf->symfile_flags = SYMFILE_NO_READ;
          clone_program_space (child_inf->pspace, parent_inf->pspace);
        }
@@ -603,6 +626,8 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
   target_follow_fork (child_inf, child_ptid, fork_kind, follow_child,
                      detach_fork);
 
+  gdb::observers::inferior_forked.notify (parent_inf, child_inf, fork_kind);
+
   /* target_follow_fork must leave the parent as the current inferior.  If we
      want to follow the child, we make it the current one below.  */
   gdb_assert (current_inferior () == parent_inf);
@@ -625,7 +650,7 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
 
      The former case will have pending_follow cleared, the later will have
      pending_follow set.  */
-  thread_info *parent_thread = find_thread_ptid (parent_inf, parent_ptid);
+  thread_info *parent_thread = parent_inf->find_thread (parent_ptid);
   gdb_assert (parent_thread != nullptr);
   parent_thread->pending_follow.set_spurious ();
 
@@ -644,10 +669,10 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
 
       if (has_vforked)
        {
-         gdb_assert (child_inf->vfork_parent == NULL);
-         gdb_assert (parent_inf->vfork_child == NULL);
+         gdb_assert (child_inf->vfork_parent == nullptr);
+         gdb_assert (parent_inf->vfork_child == nullptr);
          child_inf->vfork_parent = parent_inf;
-         child_inf->pending_detach = 0;
+         child_inf->pending_detach = false;
          parent_inf->vfork_child = child_inf;
          parent_inf->pending_detach = detach_fork;
        }
@@ -673,7 +698,7 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
   if (child_inf != nullptr)
     {
       /* If FOLLOW_CHILD, we leave CHILD_INF as the current inferior
-         (do not restore the parent as the current inferior).  */
+        (do not restore the parent as the current inferior).  */
       gdb::optional<scoped_restore_current_thread> maybe_restore;
 
       if (!follow_child)
@@ -686,6 +711,15 @@ holding the child stopped.  Try \"set detach-on-fork\" or \
   return false;
 }
 
+/* Set the last target status as TP having stopped.  */
+
+static void
+set_last_target_status_stopped (thread_info *tp)
+{
+  set_last_target_status (tp->inf->process_target (), tp->ptid,
+                         target_waitstatus {}.set_stopped (GDB_SIGNAL_0));
+}
+
 /* Tell the target to follow the fork we're stopped at.  Returns true
    if the inferior should be resumed; false, if the target for some
    reason decided it's best not to resume.  */
@@ -700,42 +734,86 @@ follow_fork ()
      followed fork child thread should have a copy of most of the
      parent thread structure's run control related fields, not just these.
      Initialized to avoid "may be used uninitialized" warnings from gcc.  */
-  struct breakpoint *step_resume_breakpoint = NULL;
-  struct breakpoint *exception_resume_breakpoint = NULL;
+  struct breakpoint *step_resume_breakpoint = nullptr;
+  struct breakpoint *exception_resume_breakpoint = nullptr;
   CORE_ADDR step_range_start = 0;
   CORE_ADDR step_range_end = 0;
   int current_line = 0;
-  symtab *current_symtab = NULL;
+  symtab *current_symtab = nullptr;
   struct frame_id step_frame_id = { 0 };
 
   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_target, &wait_ptid, &wait_status);
+      thread_info *cur_thr = inferior_thread ();
 
-      /* If not stopped at a fork event, then there's nothing else to
-        do.  */
-      if (wait_status.kind () != TARGET_WAITKIND_FORKED
-         && wait_status.kind () != TARGET_WAITKIND_VFORKED)
-       return 1;
+      ptid_t resume_ptid
+       = user_visible_resume_ptid (cur_thr->control.stepping_command);
+      process_stratum_target *resume_target
+       = user_visible_resume_target (resume_ptid);
 
-      /* Check if we switched over from WAIT_PTID, since the event was
-        reported.  */
-      if (wait_ptid != minus_one_ptid
-         && (current_inferior ()->process_target () != wait_target
-             || inferior_ptid != wait_ptid))
+      /* Check if there's a thread that we're about to resume, other
+        than the current, with an unfollowed fork/vfork.  If so,
+        switch back to it, to tell the target to follow it (in either
+        direction).  We'll afterwards refuse to resume, and inform
+        the user what happened.  */
+      for (thread_info *tp : all_non_exited_threads (resume_target,
+                                                    resume_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_target, wait_ptid);
-         switch_to_thread (wait_thread);
-         should_resume = false;
+         if (tp == cur_thr)
+           continue;
+
+         /* follow_fork_inferior clears tp->pending_follow, and below
+            we'll need the value after the follow_fork_inferior
+            call.  */
+         target_waitkind kind = tp->pending_follow.kind ();
+
+         if (kind != TARGET_WAITKIND_SPURIOUS)
+           {
+             infrun_debug_printf ("need to follow-fork [%s] first",
+                                  tp->ptid.to_string ().c_str ());
+
+             switch_to_thread (tp);
+
+             /* Set up inferior(s) as specified by the caller, and
+                tell the target to do whatever is necessary to follow
+                either parent or child.  */
+             if (follow_child)
+               {
+                 /* The thread that started the execution command
+                    won't exist in the child.  Abort the command and
+                    immediately stop in this thread, in the child,
+                    inside fork.  */
+                 should_resume = false;
+               }
+             else
+               {
+                 /* Following the parent, so let the thread fork its
+                    child freely, it won't influence the current
+                    execution command.  */
+                 if (follow_fork_inferior (follow_child, detach_fork))
+                   {
+                     /* Target refused to follow, or there's some
+                        other reason we shouldn't resume.  */
+                     switch_to_thread (cur_thr);
+                     set_last_target_status_stopped (cur_thr);
+                     return false;
+                   }
+
+                 /* If we're following a vfork, when we need to leave
+                    the just-forked thread as selected, as we need to
+                    solo-resume it to collect the VFORK_DONE event.
+                    If we're following a fork, however, switch back
+                    to the original thread that we continue stepping
+                    it, etc.  */
+                 if (kind != TARGET_WAITKIND_VFORKED)
+                   {
+                     gdb_assert (kind == TARGET_WAITKIND_FORKED);
+                     switch_to_thread (cur_thr);
+                   }
+               }
+
+             break;
+           }
        }
     }
 
@@ -799,21 +877,16 @@ follow_fork ()
          }
        else
          {
-           /* This makes sure we don't try to apply the "Switched
-              over from WAIT_PID" logic above.  */
-           nullify_last_target_wait_ptid ();
-
            /* If we followed the child, switch to it...  */
            if (follow_child)
              {
-               thread_info *child_thr = find_thread_ptid (parent_targ, child);
-               switch_to_thread (child_thr);
+               tp = parent_targ->find_thread (child);
+               switch_to_thread (tp);
 
                /* ... and preserve the stepping state, in case the
                   user was stepping over the fork call.  */
                if (should_resume)
                  {
-                   tp = inferior_thread ();
                    tp->control.step_resume_breakpoint
                      = step_resume_breakpoint;
                    tp->control.step_range_start = step_range_start;
@@ -852,6 +925,8 @@ follow_fork ()
       break;
     }
 
+  if (!should_resume)
+    set_last_target_status_stopped (tp);
   return should_resume;
 }
 
@@ -876,14 +951,14 @@ follow_inferior_reset_breakpoints (void)
   if (tp->control.step_resume_breakpoint)
     {
       breakpoint_re_set_thread (tp->control.step_resume_breakpoint);
-      tp->control.step_resume_breakpoint->loc->enabled = 1;
+      tp->control.step_resume_breakpoint->first_loc ().enabled = 1;
     }
 
   /* Treat exception_resume breakpoints like step_resume breakpoints.  */
   if (tp->control.exception_resume_breakpoint)
     {
       breakpoint_re_set_thread (tp->control.exception_resume_breakpoint);
-      tp->control.exception_resume_breakpoint->loc->enabled = 1;
+      tp->control.exception_resume_breakpoint->first_loc ().enabled = 1;
     }
 
   /* Reinsert all breakpoints in the child.  The user may have set
@@ -930,8 +1005,8 @@ handle_vfork_child_exec_or_exit (int exec)
       /* This exec or exit marks the end of the shared memory region
         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;
+      inf->vfork_parent->vfork_child = nullptr;
+      inf->vfork_parent = nullptr;
 
       /* If the user wanted to detach from the parent, now is the
         time.  */
@@ -942,7 +1017,7 @@ handle_vfork_child_exec_or_exit (int exec)
 
          /* follow-fork child, detach-on-fork on.  */
 
-         vfork_parent->pending_detach = 0;
+         vfork_parent->pending_detach = false;
 
          scoped_restore_current_pspace_and_thread restore_thread;
 
@@ -964,8 +1039,8 @@ handle_vfork_child_exec_or_exit (int exec)
 
          pspace = inf->pspace;
          aspace = inf->aspace;
-         inf->aspace = NULL;
-         inf->pspace = NULL;
+         inf->aspace = nullptr;
+         inf->pspace = nullptr;
 
          if (print_inferior_events)
            {
@@ -998,7 +1073,7 @@ handle_vfork_child_exec_or_exit (int exec)
             child a new address space.  */
          inf->pspace = new program_space (maybe_new_address_space ());
          inf->aspace = inf->pspace->aspace;
-         inf->removable = 1;
+         inf->removable = true;
          set_current_program_space (inf->pspace);
 
          resume_parent = vfork_parent;
@@ -1023,7 +1098,7 @@ handle_vfork_child_exec_or_exit (int exec)
          inf->pspace = new program_space (maybe_new_address_space ());
          inf->aspace = inf->pspace->aspace;
          set_current_program_space (inf->pspace);
-         inf->removable = 1;
+         inf->removable = true;
          inf->symfile_flags = SYMFILE_NO_READ;
          clone_program_space (inf->pspace, vfork_parent->pspace);
 
@@ -1104,7 +1179,7 @@ static const char *const follow_exec_mode_names[] =
 {
   follow_exec_mode_new,
   follow_exec_mode_same,
-  NULL,
+  nullptr,
 };
 
 static const char *follow_exec_mode_string = follow_exec_mode_same;
@@ -1178,9 +1253,9 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
      breakpoint or similar, it's gone now.  We cannot truly
      step-to-next statement through an exec().  */
   thread_info *th = inferior_thread ();
-  th->control.step_resume_breakpoint = NULL;
-  th->control.exception_resume_breakpoint = NULL;
-  th->control.single_step_breakpoints = NULL;
+  th->control.step_resume_breakpoint = nullptr;
+  th->control.exception_resume_breakpoint = nullptr;
+  th->control.single_step_breakpoints = nullptr;
   th->control.step_range_start = 0;
   th->control.step_range_end = 0;
 
@@ -1203,13 +1278,13 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
   breakpoint_init_inferior (inf_execd);
 
   gdb::unique_xmalloc_ptr<char> exec_file_host
-    = exec_file_find (exec_file_target, NULL);
+    = exec_file_find (exec_file_target, nullptr);
 
   /* If we were unable to map the executable target pathname onto a host
      pathname, tell the user that.  Otherwise GDB's subsequent behavior
      is confusing.  Maybe it would even be better to stop at this point
      so that the user can specify a file manually before continuing.  */
-  if (exec_file_host == NULL)
+  if (exec_file_host == nullptr)
     warning (_("Could not load symbols for executable %s.\n"
               "Do you need \"set sysroot\"?"),
             exec_file_target);
@@ -1220,9 +1295,10 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
   /* Also, loading a symbol file below may trigger symbol lookups, and
      we don't want those to be satisfied by the libraries of the
      previous incarnation of this process.  */
-  no_shared_libraries (NULL, 0);
+  no_shared_libraries (nullptr, 0);
 
-  struct inferior *inf = current_inferior ();
+  inferior *execing_inferior = current_inferior ();
+  inferior *following_inferior;
 
   if (follow_exec_mode_string == follow_exec_mode_new)
     {
@@ -1233,19 +1309,19 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
         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.  */
-      inferior *new_inferior = add_inferior_with_spaces ();
+      following_inferior = add_inferior_with_spaces ();
 
-      swap_terminal_info (new_inferior, inf);
-      exit_inferior_silent (inf);
+      swap_terminal_info (following_inferior, execing_inferior);
+      exit_inferior_silent (execing_inferior);
 
-      new_inferior->pid = pid;
-      target_follow_exec (new_inferior, ptid, exec_file_target);
-
-      /* We continue with the new inferior.  */
-      inf = new_inferior;
+      following_inferior->pid = pid;
     }
   else
     {
+      /* follow-exec-mode is "same", we continue execution in the execing
+        inferior.  */
+      following_inferior = execing_inferior;
+
       /* The old description may no longer be fit for the new image.
         E.g, a 64-bit process exec'ed a 32-bit process.  Clear the
         old description; we'll read a new one below.  No need to do
@@ -1253,18 +1329,20 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
         around (its description is later cleared/refetched on
         restart).  */
       target_clear_description ();
-      target_follow_exec (inf, ptid, exec_file_target);
     }
 
-  gdb_assert (current_inferior () == inf);
-  gdb_assert (current_program_space == inf->pspace);
+  target_follow_exec (following_inferior, ptid, exec_file_target);
+
+  gdb_assert (current_inferior () == following_inferior);
+  gdb_assert (current_program_space == following_inferior->pspace);
 
   /* Attempt to open the exec file.  SYMFILE_DEFER_BP_RESET is used
      because the proper displacement for a PIE (Position Independent
      Executable) main symbol file will only be computed by
      solib_create_inferior_hook below.  breakpoint_re_set would fail
      to insert the breakpoints with the zero displacement.  */
-  try_open_exec_file (exec_file_host.get (), inf, SYMFILE_DEFER_BP_RESET);
+  try_open_exec_file (exec_file_host.get (), following_inferior,
+                     SYMFILE_DEFER_BP_RESET);
 
   /* If the target can specify a description, read it.  Must do this
      after flipping to the new executable (because the target supplied
@@ -1274,7 +1352,7 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
      registers.  */
   target_find_description ();
 
-  gdb::observers::inferior_execd.notify (inf);
+  gdb::observers::inferior_execd.notify (execing_inferior, following_inferior);
 
   breakpoint_re_set ();
 
@@ -1380,7 +1458,7 @@ static void
 clear_step_over_info (void)
 {
   infrun_debug_printf ("clearing step over info");
-  step_over_info.aspace = NULL;
+  step_over_info.aspace = nullptr;
   step_over_info.address = 0;
   step_over_info.nonsteppable_watchpoint_p = 0;
   step_over_info.thread = -1;
@@ -1392,7 +1470,7 @@ int
 stepping_past_instruction_at (struct address_space *aspace,
                              CORE_ADDR address)
 {
-  return (step_over_info.aspace != NULL
+  return (step_over_info.aspace != nullptr
          && breakpoint_address_match (aspace, address,
                                       step_over_info.aspace,
                                       step_over_info.address));
@@ -1420,7 +1498,7 @@ stepping_past_nonsteppable_watchpoint (void)
 static bool
 step_over_info_valid_p (void)
 {
-  return (step_over_info.aspace != NULL
+  return (step_over_info.aspace != nullptr
          || stepping_past_nonsteppable_watchpoint ());
 }
 
@@ -1516,7 +1594,7 @@ step_over_info_valid_p (void)
 static bool
 displaced_step_in_progress_thread (thread_info *thread)
 {
-  gdb_assert (thread != NULL);
+  gdb_assert (thread != nullptr);
 
   return thread->displaced_step_state.in_progress ();
 }
@@ -1551,15 +1629,15 @@ infrun_inferior_exit (struct inferior *inf)
 }
 
 static void
-infrun_inferior_execd (inferior *inf)
+infrun_inferior_execd (inferior *exec_inf, inferior *follow_inf)
 {
   /* If some threads where was doing a displaced step in this inferior at the
      moment of the exec, they no longer exist.  Even if the exec'ing thread
      doing a displaced step, we don't want to to any fixup nor restore displaced
      stepping buffer bytes.  */
-  inf->displaced_step_state.reset ();
+  follow_inf->displaced_step_state.reset ();
 
-  for (thread_info *thread : inf->threads ())
+  for (thread_info *thread : follow_inf->threads ())
     thread->displaced_step_state.reset ();
 
   /* Since an in-line step is done with everything else stopped, if there was
@@ -1567,7 +1645,7 @@ infrun_inferior_execd (inferior *inf)
      thread.  */
   clear_step_over_info ();
 
-  inf->thread_waiting_for_vfork_done = nullptr;
+  follow_inf->thread_waiting_for_vfork_done = nullptr;
 }
 
 /* If ON, and the architecture supports it, GDB will use displaced
@@ -1654,24 +1732,6 @@ displaced_step_reset (displaced_step_thread_state *displaced)
 
 using displaced_step_reset_cleanup = FORWARD_SCOPE_EXIT (displaced_step_reset);
 
-/* See infrun.h.  */
-
-std::string
-displaced_step_dump_bytes (const gdb_byte *buf, size_t len)
-{
-  std::string ret;
-
-  for (size_t i = 0; i < len; i++)
-    {
-      if (i == 0)
-       ret += string_printf ("%02x", buf[i]);
-      else
-       ret += string_printf (" %02x", buf[i]);
-    }
-
-  return ret;
-}
-
 /* Prepare to single-step, using displaced stepping.
 
    Note that we cannot use displaced stepping when we have a signal to
@@ -1737,6 +1797,30 @@ displaced_step_prepare_throw (thread_info *tp)
   CORE_ADDR original_pc = regcache_read_pc (regcache);
   CORE_ADDR displaced_pc;
 
+  /* Display the instruction we are going to displaced step.  */
+  if (debug_displaced)
+    {
+      string_file tmp_stream;
+      int dislen = gdb_print_insn (gdbarch, original_pc, &tmp_stream,
+                                  nullptr);
+
+      if (dislen > 0)
+       {
+         gdb::byte_vector insn_buf (dislen);
+         read_memory (original_pc, insn_buf.data (), insn_buf.size ());
+
+         std::string insn_bytes = bytes_to_string (insn_buf);
+
+         displaced_debug_printf ("original insn %s: %s \t %s",
+                                 paddress (gdbarch, original_pc),
+                                 insn_bytes.c_str (),
+                                 tmp_stream.string ().c_str ());
+       }
+      else
+       displaced_debug_printf ("original insn %s: invalid length: %d",
+                               paddress (gdbarch, original_pc), dislen);
+    }
+
   displaced_step_prepare_status status
     = gdbarch_displaced_step_prepare (gdbarch, tp, displaced_pc);
 
@@ -1775,6 +1859,47 @@ displaced_step_prepare_throw (thread_info *tp)
                          paddress (gdbarch, original_pc),
                          paddress (gdbarch, displaced_pc));
 
+  /* Display the new displaced instruction(s).  */
+  if (debug_displaced)
+    {
+      string_file tmp_stream;
+      CORE_ADDR addr = displaced_pc;
+
+      /* If displaced stepping is going to use h/w single step then we know
+        that the replacement instruction can only be a single instruction,
+        in that case set the end address at the next byte.
+
+        Otherwise the displaced stepping copy instruction routine could
+        have generated multiple instructions, and all we know is that they
+        must fit within the LEN bytes of the buffer.  */
+      CORE_ADDR end
+       = addr + (gdbarch_displaced_step_hw_singlestep (gdbarch)
+                 ? 1 : gdbarch_displaced_step_buffer_length (gdbarch));
+
+      while (addr < end)
+       {
+         int dislen = gdb_print_insn (gdbarch, addr, &tmp_stream, nullptr);
+         if (dislen <= 0)
+           {
+             displaced_debug_printf
+               ("replacement insn %s: invalid length: %d",
+                paddress (gdbarch, addr), dislen);
+             break;
+           }
+
+         gdb::byte_vector insn_buf (dislen);
+         read_memory (addr, insn_buf.data (), insn_buf.size ());
+
+         std::string insn_bytes = bytes_to_string (insn_buf);
+         std::string insn_str = tmp_stream.release ();
+         displaced_debug_printf ("replacement insn %s: %s \t %s",
+                                 paddress (gdbarch, addr),
+                                 insn_bytes.c_str (),
+                                 insn_str.c_str ());
+         addr += dislen;
+       }
+    }
+
   return DISPLACED_STEP_PREPARE_STATUS_OK;
 }
 
@@ -1825,7 +1950,8 @@ displaced_step_prepare (thread_info *thread)
    DISPLACED_STEP_FINISH_STATUS_OK as well.  */
 
 static displaced_step_finish_status
-displaced_step_finish (thread_info *event_thread, enum gdb_signal signal)
+displaced_step_finish (thread_info *event_thread,
+                      const target_waitstatus &event_status)
 {
   displaced_step_thread_state *displaced = &event_thread->displaced_step_state;
 
@@ -1847,62 +1973,40 @@ displaced_step_finish (thread_info *event_thread, enum gdb_signal signal)
   /* Do the fixup, and release the resources acquired to do the displaced
      step. */
   return gdbarch_displaced_step_finish (displaced->get_original_gdbarch (),
-                                       event_thread, signal);
+                                       event_thread, event_status);
 }
 
 /* Data to be passed around while handling an event.  This data is
    discarded between events.  */
 struct execution_control_state
 {
-  execution_control_state ()
-  {
-    this->reset ();
-  }
-
-  void reset ()
+  explicit execution_control_state (thread_info *thr = nullptr)
+    : ptid (thr == nullptr ? null_ptid : thr->ptid),
+      event_thread (thr)
   {
-    this->target = nullptr;
-    this->ptid = null_ptid;
-    this->event_thread = nullptr;
-    ws = target_waitstatus ();
-    stop_func_filled_in = 0;
-    stop_func_start = 0;
-    stop_func_end = 0;
-    stop_func_name = nullptr;
-    wait_some_more = 0;
-    hit_singlestep_breakpoint = 0;
   }
 
-  process_stratum_target *target;
+  process_stratum_target *target = nullptr;
   ptid_t ptid;
   /* The thread that got the event, if this was a thread event; NULL
      otherwise.  */
   struct thread_info *event_thread;
 
   struct target_waitstatus ws;
-  int stop_func_filled_in;
-  CORE_ADDR stop_func_start;
-  CORE_ADDR stop_func_end;
-  const char *stop_func_name;
-  int wait_some_more;
+  int stop_func_filled_in = 0;
+  CORE_ADDR stop_func_alt_start = 0;
+  CORE_ADDR stop_func_start = 0;
+  CORE_ADDR stop_func_end = 0;
+  const char *stop_func_name = nullptr;
+  int wait_some_more = 0;
 
   /* True if the event thread hit the single-step breakpoint of
      another thread.  Thus the event doesn't cause a stop, the thread
      needs to be single-stepped past the single-step breakpoint before
      we can switch back to the original stepping thread.  */
-  int hit_singlestep_breakpoint;
+  int hit_singlestep_breakpoint = 0;
 };
 
-/* Clear ECS and set it to point at TP.  */
-
-static void
-reset_ecs (struct execution_control_state *ecs, struct thread_info *tp)
-{
-  ecs->reset ();
-  ecs->event_thread = tp;
-  ecs->ptid = tp->ptid;
-}
-
 static void keep_going_pass_signal (struct execution_control_state *ecs);
 static void prepare_to_wait (struct execution_control_state *ecs);
 static bool keep_going_stepped_thread (struct thread_info *tp);
@@ -1955,8 +2059,6 @@ start_step_over (void)
 
   for (thread_info *tp : range)
     {
-      struct execution_control_state ecss;
-      struct execution_control_state *ecs = &ecss;
       step_over_what step_what;
       int must_be_in_line;
 
@@ -2027,10 +2129,10 @@ start_step_over (void)
        continue;
 
       switch_to_thread (tp);
-      reset_ecs (ecs, tp);
-      keep_going_pass_signal (ecs);
+      execution_control_state ecs (tp);
+      keep_going_pass_signal (&ecs);
 
-      if (!ecs->wait_some_more)
+      if (!ecs.wait_some_more)
        error (_("Command aborted."));
 
       /* If the thread's step over could not be initiated because no buffers
@@ -2101,7 +2203,7 @@ static const char *const scheduler_enums[] = {
   schedlock_on,
   schedlock_step,
   schedlock_replay,
-  NULL
+  nullptr
 };
 static const char *scheduler_mode = schedlock_replay;
 static void
@@ -2195,10 +2297,33 @@ process_stratum_target *
 user_visible_resume_target (ptid_t resume_ptid)
 {
   return (resume_ptid == minus_one_ptid && sched_multi
-         ? NULL
+         ? nullptr
          : current_inferior ()->process_target ());
 }
 
+/* Find a thread from the inferiors that we'll resume that is waiting
+   for a vfork-done event.  */
+
+static thread_info *
+find_thread_waiting_for_vfork_done ()
+{
+  gdb_assert (!target_is_non_stop_p ());
+
+  if (sched_multi)
+    {
+      for (inferior *inf : all_non_exited_inferiors ())
+       if (inf->thread_waiting_for_vfork_done != nullptr)
+         return inf->thread_waiting_for_vfork_done;
+    }
+  else
+    {
+      inferior *cur_inf = current_inferior ();
+      if (cur_inf->thread_waiting_for_vfork_done != nullptr)
+       return cur_inf->thread_waiting_for_vfork_done;
+    }
+  return nullptr;
+}
+
 /* 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
@@ -2239,14 +2364,18 @@ internal_resume_ptid (int user_step)
      Since we don't have that flexibility (we can only pass one ptid), just
      resume the first thread waiting for a vfork-done event we find (e.g. thread
      2.1).  */
-  if (sched_multi)
+  thread_info *thr = find_thread_waiting_for_vfork_done ();
+  if (thr != nullptr)
     {
-      for (inferior *inf : all_non_exited_inferiors ())
-       if (inf->thread_waiting_for_vfork_done != nullptr)
-         return inf->thread_waiting_for_vfork_done->ptid;
+      /* If we have a thread that is waiting for a vfork-done event,
+        then we should have switched to it earlier.  Calling
+        target_resume with thread scope is only possible when the
+        current thread matches the thread scope.  */
+      gdb_assert (thr->ptid == inferior_ptid);
+      gdb_assert (thr->inf->process_target ()
+                 == inferior_thread ()->inf->process_target ());
+      return thr->ptid;
     }
-  else if (current_inferior ()->thread_waiting_for_vfork_done != nullptr)
-    return current_inferior ()->thread_waiting_for_vfork_done->ptid;
 
   return user_visible_resume_ptid (user_step);
 }
@@ -2417,13 +2546,14 @@ resume_1 (enum gdb_signal sig)
          clear_step_over_info ();
          tp->control.trap_expected = 0;
 
-         if (tp->control.step_resume_breakpoint == NULL)
+         if (tp->control.step_resume_breakpoint == nullptr)
            {
              /* Set a "high-priority" step-resume, as we don't want
                 user breakpoints at PC to trigger (again) when this
                 hits.  */
              insert_hp_step_resume_breakpoint_at_frame (get_current_frame ());
-             gdb_assert (tp->control.step_resume_breakpoint->loc->permanent);
+             gdb_assert (tp->control.step_resume_breakpoint->first_loc ()
+                         .permanent);
 
              tp->step_after_step_resume_breakpoint = step;
            }
@@ -2559,7 +2689,7 @@ resume_1 (enum gdb_signal sig)
         a step-resume breakpoint set on the earlier handler.  We cannot
         set another step-resume breakpoint; just continue on until the
         original breakpoint is hit.  */
-      if (tp->control.step_resume_breakpoint == NULL)
+      if (tp->control.step_resume_breakpoint == nullptr)
        {
          insert_hp_step_resume_breakpoint_at_frame (get_current_frame ());
          tp->step_after_step_resume_breakpoint = 1;
@@ -2638,23 +2768,6 @@ resume_1 (enum gdb_signal sig)
        step = false;
     }
 
-  if (debug_displaced
-      && tp->control.trap_expected
-      && use_displaced_stepping (tp)
-      && !step_over_info_valid_p ())
-    {
-      struct regcache *resume_regcache = get_thread_regcache (tp);
-      struct gdbarch *resume_gdbarch = resume_regcache->arch ();
-      CORE_ADDR actual_pc = regcache_read_pc (resume_regcache);
-      gdb_byte buf[4];
-
-      read_memory (actual_pc, buf, sizeof (buf));
-      displaced_debug_printf ("run %s: %s",
-                             paddress (resume_gdbarch, actual_pc),
-                             displaced_step_dump_bytes
-                               (buf, sizeof (buf)).c_str ());
-    }
-
   if (tp->control.may_range_step)
     {
       /* If we're resuming a thread with the PC out of the step
@@ -2768,7 +2881,7 @@ clear_proceed_status_thread (struct thread_info *tp)
   tp->control.step_frame_id = null_frame_id;
   tp->control.step_stack_frame_id = null_frame_id;
   tp->control.step_over_calls = STEP_OVER_UNDEBUGGABLE;
-  tp->control.step_start_function = NULL;
+  tp->control.step_start_function = nullptr;
   tp->stop_requested = 0;
 
   tp->control.stop_step = 0;
@@ -3017,7 +3130,7 @@ scoped_disable_commit_resumed::reset ()
   if (m_prev_enable_commit_resumed)
     {
       /* This is the outermost instance, re-enable
-         COMMIT_RESUMED_STATE on the targets where it's possible.  */
+        COMMIT_RESUMED_STATE on the targets where it's possible.  */
       maybe_set_commit_resumed_all_targets ();
     }
   else
@@ -3161,8 +3274,6 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
   struct regcache *regcache;
   struct gdbarch *gdbarch;
   CORE_ADDR pc;
-  struct execution_control_state ecss;
-  struct execution_control_state *ecs = &ecss;
 
   /* If we're stopped at a fork/vfork, follow the branch set by the
      "set follow-fork-mode" command; otherwise, we'll just proceed
@@ -3177,7 +3288,7 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
     }
 
   /* We'll update this if & when we switch to a new thread.  */
-  previous_inferior_ptid = inferior_ptid;
+  update_previous_thread ();
 
   regcache = get_current_regcache ();
   gdbarch = regcache->arch ();
@@ -3374,10 +3485,10 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
            infrun_debug_printf ("resuming %s",
                                 tp->ptid.to_string ().c_str ());
 
-           reset_ecs (ecs, tp);
+           execution_control_state ecs (tp);
            switch_to_thread (tp);
-           keep_going_pass_signal (ecs);
-           if (!ecs->wait_some_more)
+           keep_going_pass_signal (&ecs);
+           if (!ecs.wait_some_more)
              error (_("Command aborted."));
          }
       }
@@ -3390,10 +3501,10 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
                  && cur_thr->inf->thread_waiting_for_vfork_done != nullptr))
       {
        /* The thread wasn't started, and isn't queued, run it now.  */
-       reset_ecs (ecs, cur_thr);
+       execution_control_state ecs (cur_thr);
        switch_to_thread (cur_thr);
-       keep_going_pass_signal (ecs);
-       if (!ecs->wait_some_more)
+       keep_going_pass_signal (&ecs);
+       if (!ecs.wait_some_more)
          error (_("Command aborted."));
       }
 
@@ -3460,7 +3571,7 @@ init_wait_for_inferior (void)
 
   nullify_last_target_wait_ptid ();
 
-  previous_inferior_ptid = inferior_ptid;
+  update_previous_thread ();
 }
 
 \f
@@ -3536,14 +3647,6 @@ infrun_thread_stop_requested (ptid_t ptid)
     }
 }
 
-static void
-infrun_thread_thread_exit (struct thread_info *tp, int silent)
-{
-  if (target_last_proc_target == tp->inf->process_target ()
-      && target_last_wait_ptid == tp->ptid)
-    nullify_last_target_wait_ptid ();
-}
-
 /* Delete the step resume, single-step and longjmp/exception resume
    breakpoints of TP.  */
 
@@ -3666,13 +3769,13 @@ do_target_wait_1 (inferior *inf, ptid_t ptid,
                           ptid.to_string ().c_str ());
 
       /* We have a specific thread to check.  */
-      tp = find_thread_ptid (inf, ptid);
-      gdb_assert (tp != NULL);
+      tp = inf->find_thread (ptid);
+      gdb_assert (tp != nullptr);
       if (!tp->has_pending_waitstatus ())
-       tp = NULL;
+       tp = nullptr;
     }
 
-  if (tp != NULL
+  if (tp != nullptr
       && (tp->stop_reason () == TARGET_STOPPED_BY_SW_BREAKPOINT
          || tp->stop_reason () == TARGET_STOPPED_BY_HW_BREAKPOINT))
     {
@@ -3713,7 +3816,7 @@ do_target_wait_1 (inferior *inf, ptid_t ptid,
        }
     }
 
-  if (tp != NULL)
+  if (tp != nullptr)
     {
       infrun_debug_printf ("Using pending wait status %s for %s.",
                           tp->pending_waitstatus ().to_string ().c_str (),
@@ -4001,8 +4104,7 @@ wait_for_inferior (inferior *inf)
 
   while (1)
     {
-      struct execution_control_state ecss;
-      struct execution_control_state *ecs = &ecss;
+      execution_control_state ecs;
 
       overlay_cache_invalid = 1;
 
@@ -4012,16 +4114,16 @@ wait_for_inferior (inferior *inf)
         don't get any event.  */
       target_dcache_invalidate ();
 
-      ecs->ptid = do_target_wait_1 (inf, minus_one_ptid, &ecs->ws, 0);
-      ecs->target = inf->process_target ();
+      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 (minus_one_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);
+      handle_inferior_event (&ecs);
 
-      if (!ecs->wait_some_more)
+      if (!ecs.wait_some_more)
        break;
     }
 
@@ -4105,7 +4207,7 @@ check_curr_ui_sync_execution_done (void)
       && !gdb_in_secondary_prompt_p (ui))
     {
       target_terminal::ours ();
-      gdb::observers::sync_execution_done.notify ();
+      top_level_interpreter ()->on_sync_execution_done ();
       ui->register_file_handler ();
     }
 }
@@ -4133,6 +4235,44 @@ all_uis_on_sync_execution_starting (void)
     }
 }
 
+/* A quit_handler callback installed while we're handling inferior
+   events.  */
+
+static void
+infrun_quit_handler ()
+{
+  if (target_terminal::is_ours ())
+    {
+      /* Do nothing.
+
+        default_quit_handler would throw a quit in this case, but if
+        we're handling an event while we have the terminal, it means
+        the target is running a background execution command, and
+        thus when users press Ctrl-C, they're wanting to interrupt
+        whatever command they were executing in the command line.
+        E.g.:
+
+         (gdb) c&
+         (gdb) foo bar whatever<ctrl-c>
+
+        That Ctrl-C should clear the input line, not interrupt event
+        handling if it happens that the user types Ctrl-C at just the
+        "wrong" time!
+
+        It's as-if background event handling was handled by a
+        separate background thread.
+
+        To be clear, the Ctrl-C is not lost -- it will be processed
+        by the next QUIT call once we're out of fetch_inferior_event
+        again.  */
+    }
+  else
+    {
+      if (check_quit_flag ())
+       target_pass_ctrlc ();
+    }
+}
+
 /* Asynchronous version of wait_for_inferior.  It is called by the
    event loop whenever a change of state is detected on the file
    descriptor corresponding to the target.  It can be called more than
@@ -4147,8 +4287,7 @@ fetch_inferior_event ()
 {
   INFRUN_SCOPED_DEBUG_ENTER_EXIT;
 
-  struct execution_control_state ecss;
-  struct execution_control_state *ecs = &ecss;
+  execution_control_state ecs;
   int cmd_done = 0;
 
   /* Events are always processed with the main UI as current UI.  This
@@ -4162,6 +4301,21 @@ fetch_inferior_event ()
   scoped_restore save_pagination
     = make_scoped_restore (&pagination_enabled, false);
 
+  /* Install a quit handler that does nothing if we have the terminal
+     (meaning the target is running a background execution command),
+     so that Ctrl-C never interrupts GDB before the event is fully
+     handled.  */
+  scoped_restore restore_quit_handler
+    = make_scoped_restore (&quit_handler, infrun_quit_handler);
+
+  /* Make sure a SIGINT does not interrupt an extension language while
+     we're handling an event.  That could interrupt a Python unwinder
+     or a Python observer or some such.  A Ctrl-C should either be
+     forwarded to the inferior if the inferior has the terminal, or,
+     if GDB has the terminal, should interrupt the command the user is
+     typing in the CLI.  */
+  scoped_disable_cooperative_sigint_handling restore_coop_sigint;
+
   /* End up with readline processing input, if necessary.  */
   {
     SCOPE_EXIT { reinstall_readline_callback_handler_cleanup (); };
@@ -4198,27 +4352,31 @@ fetch_inferior_event ()
        the event.  */
     scoped_disable_commit_resumed disable_commit_resumed ("handling event");
 
-    if (!do_target_wait (ecs, TARGET_WNOHANG))
+    if (!do_target_wait (&ecs, TARGET_WNOHANG))
       {
        infrun_debug_printf ("do_target_wait returned no event");
        disable_commit_resumed.reset_and_commit ();
        return;
       }
 
-    gdb_assert (ecs->ws.kind () != TARGET_WAITKIND_IGNORE);
+    gdb_assert (ecs.ws.kind () != TARGET_WAITKIND_IGNORE);
 
-    /* Switch to the target that generated the event, so we can do
-       target calls.  */
-    switch_to_target_no_thread (ecs->target);
+    /* Switch to the inferior that generated the event, so we can do
+       target calls.  If the event was not associated to a ptid,  */
+    if (ecs.ptid != null_ptid
+       && ecs.ptid != minus_one_ptid)
+      switch_to_inferior_no_thread (find_inferior_ptid (ecs.target, ecs.ptid));
+    else
+      switch_to_target_no_thread (ecs.target);
 
     if (debug_infrun)
-      print_target_wait_results (minus_one_ptid, ecs->ptid, ecs->ws);
+      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 (ecs->target, finish_ptid);
+    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 scoped_restore_current_thread above to apply
        still for the thread which has thrown the exception.  */
@@ -4228,13 +4386,13 @@ fetch_inferior_event ()
       = make_scope_exit (delete_just_stopped_threads_infrun_breakpoints);
 
     /* Now figure out what to do with the result of the result.  */
-    handle_inferior_event (ecs);
+    handle_inferior_event (&ecs);
 
-    if (!ecs->wait_some_more)
+    if (!ecs.wait_some_more)
       {
-       struct inferior *inf = find_inferior_ptid (ecs->target, ecs->ptid);
+       struct inferior *inf = find_inferior_ptid (ecs.target, ecs.ptid);
        bool should_stop = true;
-       struct thread_info *thr = ecs->event_thread;
+       struct thread_info *thr = ecs.event_thread;
 
        delete_just_stopped_threads_infrun_breakpoints ();
 
@@ -4243,16 +4401,16 @@ fetch_inferior_event ()
 
        if (!should_stop)
          {
-           keep_going (ecs);
+           keep_going (&ecs);
          }
        else
          {
            bool should_notify_stop = true;
-           int proceeded = 0;
+           bool proceeded = false;
 
            stop_all_threads_if_all_stop_mode ();
 
-           clean_up_just_stopped_threads_fsms (ecs);
+           clean_up_just_stopped_threads_fsms (&ecs);
 
            if (thr != nullptr && thr->thread_fsm () != nullptr)
              should_notify_stop
@@ -4261,7 +4419,7 @@ fetch_inferior_event ()
            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)
+               if (inf == nullptr || inf->control.stop_soon == NO_STOP_QUIETLY)
                  proceeded = normal_stop ();
              }
 
@@ -4281,7 +4439,7 @@ fetch_inferior_event ()
               selected.".  */
            if (!non_stop
                && cmd_done
-               && ecs->ws.kind () != TARGET_WAITKIND_NO_RESUMED)
+               && ecs.ws.kind () != TARGET_WAITKIND_NO_RESUMED)
              restore_thread.dont_restore ();
          }
       }
@@ -4560,7 +4718,7 @@ static bool
 stepped_in_from (frame_info_ptr frame, struct frame_id step_frame_id)
 {
   for (frame = get_prev_frame (frame);
-       frame != NULL;
+       frame != nullptr;
        frame = get_prev_frame (frame))
     {
       if (get_frame_id (frame) == step_frame_id)
@@ -4587,9 +4745,9 @@ inline_frame_is_marked_for_skip (bool prev_frame, struct thread_info *tp)
   if (prev_frame)
     frame = get_prev_frame (frame);
 
-  for (; frame != NULL; frame = get_prev_frame (frame))
+  for (; frame != nullptr; frame = get_prev_frame (frame))
     {
-      const char *fn = NULL;
+      const char *fn = nullptr;
       symtab_and_line sal;
       struct symbol *sym;
 
@@ -4601,7 +4759,7 @@ inline_frame_is_marked_for_skip (bool prev_frame, struct thread_info *tp)
       sal = find_frame_sal (frame);
       sym = get_frame_function (frame);
 
-      if (sym != NULL)
+      if (sym != nullptr)
        fn = sym->print_name ();
 
       if (sal.line != 0
@@ -4709,6 +4867,11 @@ fill_in_stop_func (struct gdbarch *gdbarch,
          ecs->stop_func_start
            += gdbarch_deprecated_function_start_offset (gdbarch);
 
+         /* PowerPC functions have a Local Entry Point (LEP) and a Global
+            Entry Point (GEP).  There is only one Entry Point (GEP = LEP) for
+            other architectures.  */
+         ecs->stop_func_alt_start = ecs->stop_func_start;
+
          if (gdbarch_skip_entrypoint_p (gdbarch))
            ecs->stop_func_start
              = gdbarch_skip_entrypoint (gdbarch, ecs->stop_func_start);
@@ -4726,7 +4889,7 @@ get_inferior_stop_soon (execution_control_state *ecs)
 {
   struct inferior *inf = find_inferior_ptid (ecs->target, ecs->ptid);
 
-  gdb_assert (inf != NULL);
+  gdb_assert (inf != nullptr);
   return inf->control.stop_soon;
 }
 
@@ -4764,7 +4927,7 @@ wait_one ()
       for (inferior *inf : all_inferiors ())
        {
          process_stratum_target *target = inf->process_target ();
-         if (target == NULL
+         if (target == nullptr
              || !target->is_async_p ()
              || !target->threads_executing)
            continue;
@@ -4795,7 +4958,7 @@ wait_one ()
       for (inferior *inf : all_inferiors ())
        {
          process_stratum_target *target = inf->process_target ();
-         if (target == NULL
+         if (target == nullptr
              || !target->is_async_p ()
              || !target->threads_executing)
            continue;
@@ -4811,12 +4974,12 @@ wait_one ()
          /* No waitable targets left.  All must be stopped.  */
          target_waitstatus ws;
          ws.set_no_resumed ();
-         return {NULL, minus_one_ptid, std::move (ws)};
+         return {nullptr, minus_one_ptid, std::move (ws)};
        }
 
       QUIT;
 
-      int numfds = interruptible_select (nfds, &readfds, 0, NULL, 0);
+      int numfds = interruptible_select (nfds, &readfds, 0, nullptr, 0);
       if (numfds < 0)
        {
          if (errno == EINTR)
@@ -4965,7 +5128,7 @@ handle_one (const wait_one_event &event)
        }
       else
        {
-         t = find_thread_ptid (event.target, event.ptid);
+         t = event.target->find_thread (event.ptid);
          /* Check if this is the first time we see this thread.
             Don't bother adding if it individually exited.  */
          if (t == nullptr
@@ -4986,8 +5149,8 @@ handle_one (const wait_one_event &event)
     }
   else
     {
-      thread_info *t = find_thread_ptid (event.target, event.ptid);
-      if (t == NULL)
+      thread_info *t = event.target->find_thread (event.ptid);
+      if (t == nullptr)
        t = add_thread (event.target, event.ptid);
 
       t->stop_requested = 0;
@@ -5009,7 +5172,7 @@ handle_one (const wait_one_event &event)
          /* We caught the event that we intended to catch, so
             there's no event to save as pending.  */
 
-         if (displaced_step_finish (t, GDB_SIGNAL_0)
+         if (displaced_step_finish (t, event.ws)
              == DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED)
            {
              /* Add it back to the step-over queue.  */
@@ -5024,7 +5187,6 @@ handle_one (const wait_one_event &event)
        }
       else
        {
-         enum gdb_signal sig;
          struct regcache *regcache;
 
          infrun_debug_printf
@@ -5035,10 +5197,7 @@ handle_one (const wait_one_event &event)
          /* Record for later.  */
          save_waitstatus (t, event.ws);
 
-         sig = (event.ws.kind () == TARGET_WAITKIND_STOPPED
-                ? event.ws.sig () : GDB_SIGNAL_0);
-
-         if (displaced_step_finish (t, sig)
+         if (displaced_step_finish (t, event.ws)
              == DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED)
            {
              /* Add it back to the step-over queue.  */
@@ -5391,9 +5550,9 @@ handle_inferior_event (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->target, ecs->ptid);
+      ecs->event_thread = ecs->target->find_thread (ecs->ptid);
       /* If it's a new thread, add it to the thread database.  */
-      if (ecs->event_thread == NULL)
+      if (ecs->event_thread == nullptr)
        ecs->event_thread = add_thread (ecs->target, ecs->ptid);
 
       /* Disable range stepping.  If the next step request could use a
@@ -5540,7 +5699,7 @@ handle_inferior_event (struct execution_control_state *ecs)
           need to have access to the just-exited thread.  That is the
           case of GNU/Linux's "checkpoint" support, for example.
           Call the switch_to_xxx routine as appropriate.  */
-       thread_info *thr = find_thread_ptid (ecs->target, ecs->ptid);
+       thread_info *thr = ecs->target->find_thread (ecs->ptid);
        if (thr != nullptr)
          switch_to_thread (thr);
        else
@@ -5563,13 +5722,13 @@ handle_inferior_event (struct execution_control_state *ecs)
                                   (LONGEST) ecs->ws.exit_status ());
 
          /* Also record this in the inferior itself.  */
-         current_inferior ()->has_exit_code = 1;
+         current_inferior ()->has_exit_code = true;
          current_inferior ()->exit_code = (LONGEST) ecs->ws.exit_status ();
 
          /* Support the --return-child-result option.  */
          return_child_result_value = ecs->ws.exit_status ();
 
-         gdb::observers::exited.notify (ecs->ws.exit_status ());
+         interps_notify_exited (ecs->ws.exit_status ());
        }
       else
        {
@@ -5596,7 +5755,7 @@ handle_inferior_event (struct execution_control_state *ecs)
                                   "signal number.");
            }
 
-         gdb::observers::signal_exited.notify (ecs->ws.sig ());
+         interps_notify_signal_exited (ecs->ws.sig ());
        }
 
       gdb_flush (gdb_stdout);
@@ -5640,7 +5799,7 @@ handle_inferior_event (struct execution_control_state *ecs)
               has been done.  Perform cleanup for parent process here.  Note
               that this operation also cleans up the child process for vfork,
               because their pages are shared.  */
-           displaced_step_finish (ecs->event_thread, GDB_SIGNAL_TRAP);
+           displaced_step_finish (ecs->event_thread, ecs->ws);
            /* Start a new step-over in another thread if there's one
               that needs it.  */
            start_step_over ();
@@ -5653,7 +5812,7 @@ handle_inferior_event (struct execution_control_state *ecs)
               list yet at this point.  */
 
            child_regcache
-             = get_thread_arch_aspace_regcache (parent_inf->process_target (),
+             = get_thread_arch_aspace_regcache (parent_inf,
                                                 ecs->ws.child_ptid (),
                                                 gdbarch,
                                                 parent_inf->aspace);
@@ -5727,7 +5886,7 @@ handle_inferior_event (struct execution_control_state *ecs)
          /* 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 (targ, ecs->ws.child_ptid ());
+         thread_info *child = targ->find_thread (ecs->ws.child_ptid ());
 
          /* At this point, the parent is marked running, and the
             child is marked stopped.  */
@@ -5765,7 +5924,7 @@ handle_inferior_event (struct execution_control_state *ecs)
          if (should_resume)
            {
              /* Never call switch_back_to_stepped_thread if we are waiting for
-                vfork-done (waiting for an external vfork child to exec or
+                vfork-done (waiting for an external vfork child to exec or
                 exit).  We will resume only the vforking thread for the purpose
                 of collecting the vfork-done event, and we will restart any
                 step once the critical shared address space window is done.  */
@@ -5880,7 +6039,7 @@ handle_inferior_event (struct execution_control_state *ecs)
       if (handle_stop_requested (ecs))
        return;
 
-      gdb::observers::no_history.notify ();
+      interps_notify_no_history ();
       stop_waiting (ecs);
       return;
     }
@@ -5977,14 +6136,11 @@ restart_threads (struct thread_info *event_thread, inferior *inf)
        }
       else
        {
-         struct execution_control_state ecss;
-         struct execution_control_state *ecs = &ecss;
-
          infrun_debug_printf ("restart threads: [%s] continuing",
                               tp->ptid.to_string ().c_str ());
-         reset_ecs (ecs, tp);
+         execution_control_state ecs (tp);
          switch_to_thread (tp);
-         keep_going_pass_signal (ecs);
+         keep_going_pass_signal (&ecs);
        }
     }
 }
@@ -6008,7 +6164,7 @@ resumed_thread_with_pending_status (struct thread_info *tp,
 static int
 finish_step_over (struct execution_control_state *ecs)
 {
-  displaced_step_finish (ecs->event_thread, ecs->event_thread->stop_signal ());
+  displaced_step_finish (ecs->event_thread, ecs->ws);
 
   bool had_step_over_info = step_over_info_valid_p ();
 
@@ -6064,8 +6220,8 @@ finish_step_over (struct execution_control_state *ecs)
        return 0;
 
       pending = iterate_over_threads (resumed_thread_with_pending_status,
-                                     NULL);
-      if (pending != NULL)
+                                     nullptr);
+      if (pending != nullptr)
        {
          struct thread_info *tp = ecs->event_thread;
          struct regcache *regcache;
@@ -6109,6 +6265,32 @@ finish_step_over (struct execution_control_state *ecs)
   return 0;
 }
 
+/* See infrun.h.  */
+
+void
+notify_signal_received (gdb_signal sig)
+{
+  interps_notify_signal_received (sig);
+  gdb::observers::signal_received.notify (sig);
+}
+
+/* See infrun.h.  */
+
+void
+notify_normal_stop (bpstat *bs, int print_frame)
+{
+  interps_notify_normal_stop (bs, print_frame);
+  gdb::observers::normal_stop.notify (bs, print_frame);
+}
+
+/* See infrun.h.  */
+
+void notify_user_selected_context_changed (user_selected_what selection)
+{
+  interps_notify_user_selected_context_changed (selection);
+  gdb::observers::user_selected_context_changed.notify (selection);
+}
+
 /* Come here when the program has stopped with a signal.  */
 
 static void
@@ -6532,7 +6714,7 @@ handle_signal_stop (struct execution_control_state *ecs)
        {
          /* The signal table tells us to print about this signal.  */
          target_terminal::ours_for_output ();
-         gdb::observers::signal_received.notify (ecs->event_thread->stop_signal ());
+         notify_signal_received (ecs->event_thread->stop_signal ());
          target_terminal::inferior ();
        }
 
@@ -6542,7 +6724,7 @@ handle_signal_stop (struct execution_control_state *ecs)
 
       if (ecs->event_thread->prev_pc == ecs->event_thread->stop_pc ()
          && ecs->event_thread->control.trap_expected
-         && ecs->event_thread->control.step_resume_breakpoint == NULL)
+         && ecs->event_thread->control.step_resume_breakpoint == nullptr)
        {
          /* We were just starting a new sequence, attempting to
             single-step off of a breakpoint and expecting a SIGTRAP.
@@ -6574,7 +6756,7 @@ handle_signal_stop (struct execution_control_state *ecs)
              || ecs->event_thread->control.step_range_end == 1)
          && (get_stack_frame_id (frame)
              == ecs->event_thread->control.step_stack_frame_id)
-         && ecs->event_thread->control.step_resume_breakpoint == NULL)
+         && ecs->event_thread->control.step_resume_breakpoint == nullptr)
        {
          /* The inferior is about to take a signal that will take it
             out of the single step range.  Set a breakpoint at the
@@ -6719,7 +6901,7 @@ process_event_stop_test (struct execution_control_state *ecs)
        infrun_debug_printf ("BPSTAT_WHAT_CLEAR_LONGJMP_RESUME");
 
        gdb_assert (ecs->event_thread->control.exception_resume_breakpoint
-                   != NULL);
+                   != nullptr);
        delete_exception_resume_breakpoint (ecs->event_thread);
 
        if (what.is_longjmp)
@@ -6853,10 +7035,10 @@ process_event_stop_test (struct execution_control_state *ecs)
       struct breakpoint *sr_bp
        = ecs->event_thread->control.step_resume_breakpoint;
 
-      if (sr_bp != NULL
-         && sr_bp->loc->permanent
+      if (sr_bp != nullptr
+         && sr_bp->first_loc ().permanent
          && sr_bp->type == bp_hp_step_resume
-         && sr_bp->loc->address == ecs->event_thread->prev_pc)
+         && sr_bp->first_loc ().address == ecs->event_thread->prev_pc)
        {
          infrun_debug_printf ("stepped permanent breakpoint, stopped in handler");
          delete_step_resume_breakpoint (ecs->event_thread);
@@ -6956,9 +7138,10 @@ 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 (ecs->event_thread->stop_pc ())
-      && !in_solib_dynsym_resolve_code (
-         ecs->event_thread->control.step_start_function->value_block ()
-             ->entry_pc ()))
+      && (ecs->event_thread->control.step_start_function == nullptr
+         || !in_solib_dynsym_resolve_code (
+              ecs->event_thread->control.step_start_function->value_block ()
+               ->entry_pc ())))
     {
       CORE_ADDR pc_after_resolver =
        gdbarch_skip_solib_resolver (gdbarch, ecs->event_thread->stop_pc ());
@@ -7268,7 +7451,7 @@ process_event_stop_test (struct execution_control_state *ecs)
      the trampoline processing logic, however, there are some trampolines 
      that have no names, so we should do trampoline handling first.  */
   if (ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE
-      && ecs->stop_func_name == NULL
+      && ecs->stop_func_name == nullptr
       && stop_pc_sal.line == 0)
     {
       infrun_debug_printf ("stepped into undebuggable function");
@@ -7300,6 +7483,24 @@ process_event_stop_test (struct execution_control_state *ecs)
        }
     }
 
+  if (execution_direction == EXEC_REVERSE
+      && ecs->event_thread->control.proceed_to_finish
+      && ecs->event_thread->stop_pc () >= ecs->stop_func_alt_start
+      && ecs->event_thread->stop_pc () < ecs->stop_func_start)
+    {
+      /* We are executing the reverse-finish command.
+        If the system supports multiple entry points and we are finishing a
+        function in reverse.   If we are between the entry points singe-step
+        back to the alternate entry point.  If we are at the alternate entry
+        point -- just   need to back up by one more single-step, which
+        should take us back to the function call.  */
+      ecs->event_thread->control.step_range_start
+       = ecs->event_thread->control.step_range_end = 1;
+      keep_going (ecs);
+      return;
+
+    }
+
   if (ecs->event_thread->control.step_range_end == 1)
     {
       /* It is stepi or nexti.  We always want to stop stepping after
@@ -7407,7 +7608,7 @@ process_event_stop_test (struct execution_control_state *ecs)
          return;
        }
       else if (get_frame_id (get_current_frame ())
-               == ecs->event_thread->control.step_frame_id)
+              == ecs->event_thread->control.step_frame_id)
        {
          /* We are not at the start of a statement, and we have not changed
             frame.
@@ -7659,8 +7860,7 @@ restart_after_all_stop_detach (process_stratum_target *proc_target)
       if (thr->state != THREAD_RUNNING)
        continue;
 
-      execution_control_state ecs;
-      reset_ecs (&ecs, thr);
+      execution_control_state ecs (thr);
       switch_to_thread (thr);
       keep_going (&ecs);
       return;
@@ -7675,8 +7875,6 @@ static bool
 keep_going_stepped_thread (struct thread_info *tp)
 {
   frame_info_ptr frame;
-  struct execution_control_state ecss;
-  struct execution_control_state *ecs = &ecss;
 
   /* If the stepping thread exited, then don't try to switch back and
      resume it, which could fail in several different ways depending
@@ -7707,7 +7905,7 @@ keep_going_stepped_thread (struct thread_info *tp)
 
   infrun_debug_printf ("resuming previously stepped thread");
 
-  reset_ecs (ecs, tp);
+  execution_control_state ecs (tp);
   switch_to_thread (tp);
 
   tp->set_stop_pc (regcache_read_pc (get_thread_regcache (tp)));
@@ -7756,7 +7954,7 @@ keep_going_stepped_thread (struct thread_info *tp)
     {
       infrun_debug_printf ("expected thread still hasn't advanced");
 
-      keep_going_pass_signal (ecs);
+      keep_going_pass_signal (&ecs);
     }
 
   return true;
@@ -7770,7 +7968,7 @@ static bool
 currently_stepping (struct thread_info *tp)
 {
   return ((tp->control.step_range_end
-          && tp->control.step_resume_breakpoint == NULL)
+          && tp->control.step_resume_breakpoint == nullptr)
          || tp->control.trap_expected
          || tp->stepped_breakpoint
          || bpstat_should_step ());
@@ -7788,7 +7986,7 @@ handle_step_into_function (struct gdbarch *gdbarch,
 
   compunit_symtab *cust
     = find_pc_compunit_symtab (ecs->event_thread->stop_pc ());
-  if (cust != NULL && compunit_language (cust) != language_asm)
+  if (cust != nullptr && cust->language () != language_asm)
     ecs->stop_func_start
       = gdbarch_skip_prologue_noexcept (gdbarch, ecs->stop_func_start);
 
@@ -7867,7 +8065,7 @@ handle_step_into_function_backward (struct gdbarch *gdbarch,
   fill_in_stop_func (gdbarch, ecs);
 
   cust = find_pc_compunit_symtab (ecs->event_thread->stop_pc ());
-  if (cust != NULL && compunit_language (cust) != language_asm)
+  if (cust != nullptr && cust->language () != language_asm)
     ecs->stop_func_start
       = gdbarch_skip_prologue_noexcept (gdbarch, ecs->stop_func_start);
 
@@ -7903,7 +8101,7 @@ insert_step_resume_breakpoint_at_sal_1 (struct gdbarch *gdbarch,
   /* There should never be more than one step-resume or longjmp-resume
      breakpoint per thread, so we should never be setting a new
      step_resume_breakpoint when one is already active.  */
-  gdb_assert (inferior_thread ()->control.step_resume_breakpoint == NULL);
+  gdb_assert (inferior_thread ()->control.step_resume_breakpoint == nullptr);
   gdb_assert (sr_type == bp_step_resume || sr_type == bp_hp_step_resume);
 
   infrun_debug_printf ("inserting step-resume breakpoint at %s",
@@ -7933,7 +8131,7 @@ insert_step_resume_breakpoint_at_sal (struct gdbarch *gdbarch,
 static void
 insert_hp_step_resume_breakpoint_at_frame (frame_info_ptr return_frame)
 {
-  gdb_assert (return_frame != NULL);
+  gdb_assert (return_frame != nullptr);
 
   struct gdbarch *gdbarch = get_frame_arch (return_frame);
 
@@ -7991,7 +8189,7 @@ insert_longjmp_resume_breakpoint (struct gdbarch *gdbarch, CORE_ADDR pc)
   /* There should never be more than one longjmp-resume breakpoint per
      thread, so we should never be setting a new
      longjmp_resume_breakpoint when one is already active.  */
-  gdb_assert (inferior_thread ()->control.exception_resume_breakpoint == NULL);
+  gdb_assert (inferior_thread ()->control.exception_resume_breakpoint == nullptr);
 
   infrun_debug_printf ("inserting longjmp-resume breakpoint at %s",
                       paddress (gdbarch, pc));
@@ -8023,22 +8221,24 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
                                        b, VAR_DOMAIN);
       value = read_var_value (vsym.symbol, vsym.block, frame);
       /* If the value was optimized out, revert to the old behavior.  */
-      if (! value_optimized_out (value))
+      if (! value->optimized_out ())
        {
          handler = value_as_address (value);
 
          infrun_debug_printf ("exception resume at %lx",
                               (unsigned long) handler);
 
+         /* set_momentary_breakpoint_at_pc creates a thread-specific
+            breakpoint for the current inferior thread.  */
+         gdb_assert (tp == inferior_thread ());
          bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
                                               handler,
                                               bp_exception_resume).release ();
 
          /* set_momentary_breakpoint_at_pc invalidates FRAME.  */
-         frame = NULL;
+         frame = nullptr;
 
-         bp->thread = tp->global_num;
-         inferior_thread ()->control.exception_resume_breakpoint = bp;
+         tp->control.exception_resume_breakpoint = bp;
        }
     }
   catch (const gdb_exception_error &e)
@@ -8068,10 +8268,12 @@ insert_exception_resume_from_probe (struct thread_info *tp,
   infrun_debug_printf ("exception resume at %s",
                       paddress (probe->objfile->arch (), handler));
 
+  /* set_momentary_breakpoint_at_pc creates a thread-specific breakpoint
+     for the current inferior thread.  */
+  gdb_assert (tp == inferior_thread ());
   bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
                                       handler, bp_exception_resume).release ();
-  bp->thread = tp->global_num;
-  inferior_thread ()->control.exception_resume_breakpoint = bp;
+  tp->control.exception_resume_breakpoint = bp;
 }
 
 /* This is called when an exception has been intercepted.  Check to
@@ -8103,8 +8305,6 @@ check_exception_resume (struct execution_control_state *ecs,
   try
     {
       const struct block *b;
-      struct block_iterator iter;
-      struct symbol *sym;
       int argno = 0;
 
       /* The exception breakpoint is a thread-specific breakpoint on
@@ -8122,7 +8322,7 @@ check_exception_resume (struct execution_control_state *ecs,
         handler.  */
 
       b = func->value_block ();
-      ALL_BLOCK_SYMBOLS (b, iter, sym)
+      for (struct symbol *sym : block_iterator_range (b))
        {
          if (!sym->is_argument ())
            continue;
@@ -8240,7 +8440,7 @@ keep_going_pass_signal (struct execution_control_state *ecs)
                              ecs->event_thread->global_num);
        }
       else if (remove_wps)
-       set_step_over_info (NULL, 0, remove_wps, -1);
+       set_step_over_info (nullptr, 0, remove_wps, -1);
 
       /* If we now need to do an in-line step-over, we need to stop
         all other threads.  Note this must be done before
@@ -8327,18 +8527,6 @@ end_stepping_range (struct execution_control_state *ecs)
    the interpreters, through observers.  Interpreters then call these
    with whatever uiout is right.  */
 
-void
-print_end_stepping_range_reason (struct ui_out *uiout)
-{
-  /* For CLI-like interpreters, print nothing.  */
-
-  if (uiout->is_mi_like_p ())
-    {
-      uiout->field_string ("reason",
-                          async_reason_lookup (EXEC_ASYNC_END_STEPPING_RANGE));
-    }
-}
-
 void
 print_signal_exited_reason (struct ui_out *uiout, enum gdb_signal siggnal)
 {
@@ -8392,6 +8580,8 @@ print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal)
 {
   struct thread_info *thr = inferior_thread ();
 
+  infrun_debug_printf ("signal = %s", gdb_signal_to_string (siggnal));
+
   annotate_signal ();
 
   if (uiout->is_mi_like_p ())
@@ -8402,7 +8592,7 @@ print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal)
       uiout->field_string ("thread-id", print_thread_id (thr));
 
       const char *name = thread_name (thr);
-      if (name != NULL)
+      if (name != nullptr)
        {
          uiout->text (" \"");
          uiout->field_string ("name", name);
@@ -8440,7 +8630,10 @@ print_signal_received_reason (struct ui_out *uiout, enum gdb_signal siggnal)
 void
 print_no_history_reason (struct ui_out *uiout)
 {
-  uiout->text ("\nNo more reverse-execution history.\n");
+  if (uiout->is_mi_like_p ())
+    uiout->field_string ("reason", async_reason_lookup (EXEC_ASYNC_NO_HISTORY));
+  else
+    uiout->text ("\nNo more reverse-execution history.\n");
 }
 
 /* Print current location without a level number, if we have changed
@@ -8500,7 +8693,7 @@ print_stop_location (const target_waitstatus &ws)
      LOCATION: Print only location
      SRC_AND_LOC: Print location and source line.  */
   if (do_frame_printing)
-    print_stack_frame (get_selected_frame (NULL), 0, source_flag, 1);
+    print_stack_frame (get_selected_frame (nullptr), 0, source_flag, 1);
 }
 
 /* See infrun.h.  */
@@ -8604,7 +8797,7 @@ stop_context::changed () const
     return true;
   if (inf_num != current_inferior ()->num)
     return true;
-  if (thread != NULL && thread->state != THREAD_STOPPED)
+  if (thread != nullptr && thread->state != THREAD_STOPPED)
     return true;
   if (get_stop_id () != stop_id)
     return true;
@@ -8613,8 +8806,8 @@ stop_context::changed () const
 
 /* See infrun.h.  */
 
-int
-normal_stop (void)
+bool
+normal_stop ()
 {
   struct target_waitstatus last;
 
@@ -8663,7 +8856,7 @@ normal_stop (void)
   update_thread_list ();
 
   if (last.kind () == TARGET_WAITKIND_STOPPED && stopped_by_random_signal)
-    gdb::observers::signal_received.notify (inferior_thread ()->stop_signal ());
+    notify_signal_received (inferior_thread ()->stop_signal ());
 
   /* As with the notification of thread events, we want to delay
      notifying the user that we've switched thread context until
@@ -8681,21 +8874,24 @@ normal_stop (void)
      the current thread back to the thread the user had selected right
      after this event is handled, so we're not really switching, only
      informing of a stop.  */
-  if (!non_stop
-      && previous_inferior_ptid != inferior_ptid
-      && target_has_execution ()
-      && last.kind () != TARGET_WAITKIND_SIGNALLED
-      && last.kind () != TARGET_WAITKIND_EXITED
-      && last.kind () != TARGET_WAITKIND_NO_RESUMED)
+  if (!non_stop)
     {
-      SWITCH_THRU_ALL_UIS ()
+      if ((last.kind () != TARGET_WAITKIND_SIGNALLED
+          && last.kind () != TARGET_WAITKIND_EXITED
+          && last.kind () != TARGET_WAITKIND_NO_RESUMED)
+         && target_has_execution ()
+         && previous_thread != inferior_thread ())
        {
-         target_terminal::ours_for_output ();
-         gdb_printf (_("[Switching to %s]\n"),
-                     target_pid_to_str (inferior_ptid).c_str ());
-         annotate_thread_changed ();
+         SWITCH_THRU_ALL_UIS ()
+           {
+             target_terminal::ours_for_output ();
+             gdb_printf (_("[Switching to %s]\n"),
+                         target_pid_to_str (inferior_ptid).c_str ());
+             annotate_thread_changed ();
+           }
        }
-      previous_inferior_ptid = inferior_ptid;
+
+      update_previous_thread ();
     }
 
   if (last.kind () == TARGET_WAITKIND_NO_RESUMED)
@@ -8761,7 +8957,7 @@ normal_stop (void)
     {
       execute_cmd_pre_hook (stop_command);
     }
-  catch (const gdb_exception &ex)
+  catch (const gdb_exception_error &ex)
     {
       exception_fprintf (gdb_stderr, ex,
                         "Error while running hook_stop:\n");
@@ -8773,16 +8969,14 @@ normal_stop (void)
      the observers would print a stop for the wrong
      thread/inferior.  */
   if (saved_context.changed ())
-    return 1;
+    return true;
 
   /* Notify observers about the stop.  This is where the interpreters
      print the stop event.  */
-  if (inferior_ptid != null_ptid)
-    gdb::observers::normal_stop.notify (inferior_thread ()->control.stop_bpstat,
-                                       stop_print_frame);
-  else
-    gdb::observers::normal_stop.notify (NULL, stop_print_frame);
-
+  notify_normal_stop ((inferior_ptid != null_ptid
+                      ? inferior_thread ()->control.stop_bpstat
+                      : nullptr),
+                     stop_print_frame);
   annotate_stopped ();
 
   if (target_has_execution ())
@@ -8795,7 +8989,7 @@ normal_stop (void)
        breakpoint_auto_delete (inferior_thread ()->control.stop_bpstat);
     }
 
-  return 0;
+  return false;
 }
 \f
 int
@@ -8911,7 +9105,7 @@ handle_command (const char *args, int from_tty)
   enum gdb_signal oursig;
   int allsigs;
 
-  if (args == NULL)
+  if (args == nullptr)
     {
       error_no_arg (_("signal to handle"));
     }
@@ -9087,7 +9281,7 @@ handle_completer (struct cmd_list_element *ignore,
       "noignore",
       "noprint",
       "nopass",
-      NULL,
+      nullptr,
     };
 
   signal_completer (ignore, tracker, text, word);
@@ -9171,12 +9365,12 @@ siginfo_value_read (struct value *v)
   transferred =
     target_read (current_inferior ()->top_target (),
                 TARGET_OBJECT_SIGNAL_INFO,
-                NULL,
-                value_contents_all_raw (v).data (),
-                value_offset (v),
-                value_type (v)->length ());
+                nullptr,
+                v->contents_all_raw ().data (),
+                v->offset (),
+                v->type ()->length ());
 
-  if (transferred != value_type (v)->length ())
+  if (transferred != v->type ()->length ())
     error (_("Unable to read siginfo"));
 }
 
@@ -9194,12 +9388,12 @@ siginfo_value_write (struct value *v, struct value *fromval)
 
   transferred = target_write (current_inferior ()->top_target (),
                              TARGET_OBJECT_SIGNAL_INFO,
-                             NULL,
-                             value_contents_all_raw (fromval).data (),
-                             value_offset (v),
-                             value_type (fromval)->length ());
+                             nullptr,
+                             fromval->contents_all_raw ().data (),
+                             v->offset (),
+                             fromval->type ()->length ());
 
-  if (transferred != value_type (fromval)->length ())
+  if (transferred != fromval->type ()->length ())
     error (_("Unable to write siginfo"));
 }
 
@@ -9223,10 +9417,10 @@ siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var,
     {
       struct type *type = gdbarch_get_siginfo_type (gdbarch);
 
-      return allocate_computed_value (type, &siginfo_value_funcs, NULL);
+      return value::allocate_computed (type, &siginfo_value_funcs, nullptr);
     }
 
-  return allocate_value (builtin_type (gdbarch)->builtin_void);
+  return value::allocate (builtin_type (gdbarch)->builtin_void);
 }
 
 \f
@@ -9258,7 +9452,7 @@ public:
        siginfo_data.reset ((gdb_byte *) xmalloc (len));
 
        if (target_read (current_inferior ()->top_target (),
-                        TARGET_OBJECT_SIGNAL_INFO, NULL,
+                        TARGET_OBJECT_SIGNAL_INFO, nullptr,
                         siginfo_data.get (), 0, len) != len)
          {
            /* Errors ignored.  */
@@ -9294,7 +9488,7 @@ public:
 
        /* Errors ignored.  */
        target_write (current_inferior ()->top_target (),
-                     TARGET_OBJECT_SIGNAL_INFO, NULL,
+                     TARGET_OBJECT_SIGNAL_INFO, nullptr,
                      m_siginfo_data.get (), 0, type->length ());
       }
 
@@ -9398,8 +9592,8 @@ save_infcall_control_state ()
   inf_status->thread_control = tp->control;
   inf_status->inferior_control = inf->control;
 
-  tp->control.step_resume_breakpoint = NULL;
-  tp->control.exception_resume_breakpoint = NULL;
+  tp->control.step_resume_breakpoint = nullptr;
+  tp->control.exception_resume_breakpoint = nullptr;
 
   /* Save original bpstat chain to INF_STATUS; replace it in TP with copy of
      chain.  If caller's caller is walking the chain, they'll be happier if we
@@ -9489,7 +9683,7 @@ static const char *exec_direction = exec_forward;
 static const char *const exec_direction_names[] = {
   exec_forward,
   exec_reverse,
-  NULL
+  nullptr
 };
 
 static void
@@ -9540,7 +9734,7 @@ show_schedule_multiple (struct ui_file *file, int from_tty,
 static const struct internalvar_funcs siginfo_funcs =
 {
   siginfo_make_value,
-  NULL,
+  nullptr,
 };
 
 /* Callback for infrun's target events source.  This is marked when a
@@ -9636,7 +9830,7 @@ _initialize_infrun ()
 
   /* Register extra event sources in the event loop.  */
   infrun_async_inferior_event_token
-    = create_async_event_handler (infrun_async_inferior_event_handler, NULL,
+    = create_async_event_handler (infrun_async_inferior_event_handler, nullptr,
                                  "infrun");
 
   cmd_list_element *info_signals_cmd
@@ -9682,7 +9876,7 @@ of the program stops."), &cmdlist);
      _("Set inferior debugging."),
      _("Show inferior debugging."),
      _("When non-zero, inferior specific debugging is enabled."),
-     NULL, show_debug_infrun, &setdebuglist, &showdebuglist);
+     nullptr, show_debug_infrun, &setdebuglist, &showdebuglist);
 
   add_setshow_boolean_cmd ("non-stop", no_class,
                           &non_stop_1, _("\
@@ -9785,7 +9979,7 @@ A fork or vfork creates a new process.  follow-fork-mode can be:\n\
   child   - the new process is debugged after a fork\n\
 The unfollowed process will continue to run.\n\
 By default, the debugger will follow the parent process."),
-                       NULL,
+                       nullptr,
                        show_follow_fork_mode_string,
                        &setlist, &showlist);
 
@@ -9809,7 +10003,7 @@ the inferior.  Restarting the inferior after the exec call restarts\n\
 the executable the process was running after the exec call.\n\
 \n\
 By default, the debugger will use the same inferior."),
-                       NULL,
+                       nullptr,
                        show_follow_exec_mode_string,
                        &setlist, &showlist);
 
@@ -9836,7 +10030,7 @@ threads of all processes.  When off (which is the default), execution\n\
 commands only resume the threads of the current process.  The set of\n\
 threads that are resumed is further refined by the scheduler-locking\n\
 mode (see help set scheduler-locking)."),
-                          NULL,
+                          nullptr,
                           show_schedule_multiple,
                           &setlist, &showlist);
 
@@ -9846,7 +10040,7 @@ Show mode of the step operation."), _("\
 When set, doing a step over a function without debug line information\n\
 will stop at the first instruction of that function. Otherwise, the\n\
 function is skipped and the step command stops at a different source line."),
-                          NULL,
+                          nullptr,
                           show_step_stop_if_no_debug,
                           &setlist, &showlist);
 
@@ -9860,7 +10054,7 @@ stepping to step over breakpoints, even if such is supported by the target\n\
 architecture.  If auto (which is the default), gdb will use displaced stepping\n\
 if the target architecture supports it and non-stop mode is active, but will not\n\
 use it in all-stop mode (see help set non-stop)."),
-                               NULL,
+                               nullptr,
                                show_can_use_displaced_stepping,
                                &setlist, &showlist);
 
@@ -9878,7 +10072,7 @@ Options are 'forward' or 'reverse'."),
 Set whether gdb will detach the child of a fork."), _("\
 Show whether gdb will detach the child of a fork."), _("\
 Tells gdb whether to detach the child of a fork."),
-                          NULL, NULL, &setlist, &showlist);
+                          nullptr, nullptr, &setlist, &showlist);
 
   /* Set/show disable address space randomization mode.  */
 
@@ -9901,7 +10095,6 @@ enabled by default on some platforms."),
                                              "infrun");
   gdb::observers::thread_stop_requested.attach (infrun_thread_stop_requested,
                                                "infrun");
-  gdb::observers::thread_exit.attach (infrun_thread_thread_exit, "infrun");
   gdb::observers::inferior_exit.attach (infrun_inferior_exit, "infrun");
   gdb::observers::inferior_execd.attach (infrun_inferior_execd, "infrun");
 
@@ -9909,7 +10102,7 @@ enabled by default on some platforms."),
      value with a void typed value, and when we get here, gdbarch
      isn't initialized yet.  At this point, we're quite sure there
      isn't another convenience variable of the same name.  */
-  create_internalvar_type_lazy ("_siginfo", &siginfo_funcs, NULL);
+  create_internalvar_type_lazy ("_siginfo", &siginfo_funcs, nullptr);
 
   add_setshow_boolean_cmd ("observer", no_class,
                           &observer_mode_1, _("\