gdb: add interp::on_user_selected_context_changed method
[binutils-gdb.git] / gdb / infrun.c
index 79e1a6abd2aa57232d2193d03a5f587ca9db75b8..d4334302a9963f6ffa6413c697f5334251fa68c9 100644 (file)
@@ -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"
@@ -74,6 +75,8 @@
 #include "gdbsupport/common-debug.h"
 #include "gdbsupport/buildargv.h"
 #include "extension.h"
+#include "disasm.h"
+#include "interps.h"
 
 /* Prototypes for local functions */
 
@@ -623,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);
@@ -645,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 ();
 
@@ -693,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)
@@ -875,7 +880,7 @@ follow_fork ()
            /* If we followed the child, switch to it...  */
            if (follow_child)
              {
-               tp = find_thread_ptid (parent_targ, child);
+               tp = parent_targ->find_thread (child);
                switch_to_thread (tp);
 
                /* ... and preserve the stepping state, in case the
@@ -946,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
@@ -1292,7 +1297,8 @@ follow_exec (ptid_t ptid, const char *exec_file_target)
      previous incarnation of this process.  */
   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)
     {
@@ -1303,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 ();
-
-      swap_terminal_info (new_inferior, inf);
-      exit_inferior_silent (inf);
+      following_inferior = add_inferior_with_spaces ();
 
-      new_inferior->pid = pid;
-      target_follow_exec (new_inferior, ptid, exec_file_target);
+      swap_terminal_info (following_inferior, execing_inferior);
+      exit_inferior_silent (execing_inferior);
 
-      /* 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
@@ -1323,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
@@ -1344,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 ();
 
@@ -1621,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
@@ -1637,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
@@ -1724,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
@@ -1807,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);
 
@@ -1845,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;
 }
 
@@ -1895,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;
 
@@ -1917,7 +1973,7 @@ 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
@@ -1938,6 +1994,7 @@ struct execution_control_state
 
   struct target_waitstatus ws;
   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;
@@ -2495,7 +2552,8 @@ resume_1 (enum gdb_signal sig)
                 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;
            }
@@ -2710,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
@@ -3089,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
@@ -3728,7 +3769,7 @@ 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);
+      tp = inf->find_thread (ptid);
       gdb_assert (tp != nullptr);
       if (!tp->has_pending_waitstatus ())
        tp = nullptr;
@@ -4166,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 ();
     }
 }
@@ -4320,9 +4361,13 @@ fetch_inferior_event ()
 
     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);
@@ -4822,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);
@@ -5078,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
@@ -5099,7 +5149,7 @@ handle_one (const wait_one_event &event)
     }
   else
     {
-      thread_info *t = find_thread_ptid (event.target, event.ptid);
+      thread_info *t = event.target->find_thread (event.ptid);
       if (t == nullptr)
        t = add_thread (event.target, event.ptid);
 
@@ -5122,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.  */
@@ -5137,7 +5187,6 @@ handle_one (const wait_one_event &event)
        }
       else
        {
-         enum gdb_signal sig;
          struct regcache *regcache;
 
          infrun_debug_printf
@@ -5148,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.  */
@@ -5504,7 +5550,7 @@ 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 == nullptr)
        ecs->event_thread = add_thread (ecs->target, ecs->ptid);
@@ -5653,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
@@ -5682,7 +5728,7 @@ handle_inferior_event (struct execution_control_state *ecs)
          /* 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
        {
@@ -5709,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);
@@ -5753,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 ();
@@ -5766,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);
@@ -5840,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.  */
@@ -5878,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.  */
@@ -5993,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;
     }
@@ -6118,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 ();
 
@@ -6219,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
@@ -6642,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 ();
        }
 
@@ -6964,9 +7036,9 @@ process_event_stop_test (struct execution_control_state *ecs)
        = ecs->event_thread->control.step_resume_breakpoint;
 
       if (sr_bp != nullptr
-         && sr_bp->loc->permanent
+         && 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);
@@ -7411,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
@@ -7518,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.
@@ -8138,6 +8228,9 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
          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 ();
@@ -8145,8 +8238,7 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
          /* set_momentary_breakpoint_at_pc invalidates FRAME.  */
          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)
@@ -8176,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
@@ -8433,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)
 {
@@ -8774,7 +8856,7 @@ normal_stop ()
   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
@@ -8875,7 +8957,7 @@ normal_stop ()
     {
       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");
@@ -8891,12 +8973,10 @@ normal_stop ()
 
   /* 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 (nullptr, 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 ())