x86: allow opcode templates to be templated
[deliverable/binutils-gdb.git] / gdb / infrun.c
index 3e846f8e6802dfc07c52643d3b10deeba59c6c17..2a319295d361eef94b42014a6fc9e6e0f9e7a284 100644 (file)
@@ -1540,7 +1540,7 @@ get_displaced_step_closure_by_addr (CORE_ADDR addr)
   /* If checking the mode of displaced instruction in copy area.  */
   if (displaced->step_thread != nullptr
       && displaced->step_copy == addr)
-    return displaced->step_closure;
+    return displaced->step_closure.get ();
 
   return NULL;
 }
@@ -1556,8 +1556,7 @@ infrun_inferior_exit (struct inferior *inf)
    doesn't support it, GDB will instead use the traditional
    hold-and-step approach.  If AUTO (which is the default), GDB will
    decide which technique to use to step over breakpoints depending on
-   which of all-stop or non-stop mode is active --- displaced stepping
-   in non-stop mode; hold-and-step in all-stop mode.  */
+   whether the target works in a non-stop way (see use_displaced_stepping).  */
 
 static enum auto_boolean can_use_displaced_stepping = AUTO_BOOLEAN_AUTO;
 
@@ -1577,39 +1576,67 @@ show_can_use_displaced_stepping (struct ui_file *file, int from_tty,
                        "to step over breakpoints is %s.\n"), value);
 }
 
+/* Return true if the gdbarch implements the required methods to use
+   displaced stepping.  */
+
+static bool
+gdbarch_supports_displaced_stepping (gdbarch *arch)
+{
+  /* Only check for the presence of step_copy_insn.  Other required methods
+     are checked by the gdbarch validation.  */
+  return gdbarch_displaced_step_copy_insn_p (arch);
+}
+
 /* Return non-zero if displaced stepping can/should be used to step
    over breakpoints of thread TP.  */
 
-static int
-use_displaced_stepping (struct thread_info *tp)
+static bool
+use_displaced_stepping (thread_info *tp)
 {
-  struct regcache *regcache = get_thread_regcache (tp);
-  struct gdbarch *gdbarch = regcache->arch ();
+  /* If the user disabled it explicitly, don't use displaced stepping.  */
+  if (can_use_displaced_stepping == AUTO_BOOLEAN_FALSE)
+    return false;
+
+  /* If "auto", only use displaced stepping if the target operates in a non-stop
+     way.  */
+  if (can_use_displaced_stepping == AUTO_BOOLEAN_AUTO
+      && !target_is_non_stop_p ())
+    return false;
+
+  gdbarch *gdbarch = get_thread_regcache (tp)->arch ();
+
+  /* If the architecture doesn't implement displaced stepping, don't use
+     it.  */
+  if (!gdbarch_supports_displaced_stepping (gdbarch))
+    return false;
+
+  /* If recording, don't use displaced stepping.  */
+  if (find_record_target () != nullptr)
+    return false;
+
   displaced_step_inferior_state *displaced_state
     = get_displaced_stepping_state (tp->inf);
 
-  return (((can_use_displaced_stepping == AUTO_BOOLEAN_AUTO
-           && target_is_non_stop_p ())
-          || can_use_displaced_stepping == AUTO_BOOLEAN_TRUE)
-         && gdbarch_displaced_step_copy_insn_p (gdbarch)
-         && find_record_target () == NULL
-         && !displaced_state->failed_before);
+  /* If displaced stepping failed before for this inferior, don't bother trying
+     again.  */
+  if (displaced_state->failed_before)
+    return false;
+
+  return true;
 }
 
-/* Clean out any stray displaced stepping state.  */
+/* Simple function wrapper around displaced_step_inferior_state::reset.  */
+
 static void
-displaced_step_clear (struct displaced_step_inferior_state *displaced)
+displaced_step_reset (displaced_step_inferior_state *displaced)
 {
-  /* Indicate that there is no cleanup pending.  */
-  displaced->step_thread = nullptr;
-
-  delete displaced->step_closure;
-  displaced->step_closure = NULL;
+  displaced->reset ();
 }
 
-/* A cleanup that wraps displaced_step_clear.  */
-using displaced_step_clear_cleanup
-  = FORWARD_SCOPE_EXIT (displaced_step_clear);
+/* A cleanup that wraps displaced_step_reset.  We use this instead of, say,
+   SCOPE_EXIT, because it needs to be discardable with "cleanup.release ()".  */
+
+using displaced_step_reset_cleanup = FORWARD_SCOPE_EXIT (displaced_step_reset);
 
 /* Dump LEN bytes at BUF in hex to FILE, followed by a newline.  */
 void
@@ -1648,12 +1675,11 @@ displaced_step_prepare_throw (thread_info *tp)
   const address_space *aspace = regcache->aspace ();
   CORE_ADDR original, copy;
   ULONGEST len;
-  struct displaced_step_closure *closure;
   int status;
 
   /* We should never reach this function if the architecture does not
      support displaced stepping.  */
-  gdb_assert (gdbarch_displaced_step_copy_insn_p (gdbarch));
+  gdb_assert (gdbarch_supports_displaced_stepping (gdbarch));
 
   /* Nor if the thread isn't meant to step over a breakpoint.  */
   gdb_assert (tp->control.trap_expected);
@@ -1691,7 +1717,7 @@ displaced_step_prepare_throw (thread_info *tp)
                            target_pid_to_str (tp->ptid).c_str ());
     }
 
-  displaced_step_clear (displaced);
+  displaced_step_reset (displaced);
 
   scoped_restore_current_thread restore_thread;
 
@@ -1740,9 +1766,9 @@ displaced_step_prepare_throw (thread_info *tp)
                                 len);
     };
 
-  closure = gdbarch_displaced_step_copy_insn (gdbarch,
-                                             original, copy, regcache);
-  if (closure == NULL)
+  displaced->step_closure
+    = gdbarch_displaced_step_copy_insn (gdbarch, original, copy, regcache);
+  if (displaced->step_closure == NULL)
     {
       /* The architecture doesn't know how or want to displaced step
         this instruction or instruction sequence.  Fallback to
@@ -1754,12 +1780,11 @@ displaced_step_prepare_throw (thread_info *tp)
      succeeds.  */
   displaced->step_thread = tp;
   displaced->step_gdbarch = gdbarch;
-  displaced->step_closure = closure;
   displaced->step_original = original;
   displaced->step_copy = copy;
 
   {
-    displaced_step_clear_cleanup cleanup (displaced);
+    displaced_step_reset_cleanup cleanup (displaced);
 
     /* Resume execution at the copy.  */
     regcache_write_pc (regcache, copy);
@@ -1862,7 +1887,7 @@ displaced_step_fixup (thread_info *event_thread, enum gdb_signal signal)
   if (displaced->step_thread != event_thread)
     return 0;
 
-  displaced_step_clear_cleanup cleanup (displaced);
+  displaced_step_reset_cleanup cleanup (displaced);
 
   displaced_step_restore (displaced, displaced->step_thread->ptid);
 
@@ -1879,7 +1904,7 @@ displaced_step_fixup (thread_info *event_thread, enum gdb_signal signal)
     {
       /* Fix up the resulting state.  */
       gdbarch_displaced_step_fixup (displaced->step_gdbarch,
-                                    displaced->step_closure,
+                                    displaced->step_closure.get (),
                                     displaced->step_original,
                                     displaced->step_copy,
                                     get_thread_regcache (displaced->step_thread));
@@ -2472,8 +2497,8 @@ resume_1 (enum gdb_signal sig)
          pc = regcache_read_pc (get_thread_regcache (tp));
 
          displaced = get_displaced_stepping_state (tp->inf);
-         step = gdbarch_displaced_step_hw_singlestep (gdbarch,
-                                                      displaced->step_closure);
+         step = gdbarch_displaced_step_hw_singlestep
+           (gdbarch, displaced->step_closure.get ());
        }
     }
 
@@ -3460,6 +3485,12 @@ do_target_wait_1 (inferior *inf, ptid_t ptid,
   ptid_t event_ptid;
   struct thread_info *tp;
 
+  /* We know that we are looking for an event in the target of inferior
+     INF, but we don't know which thread the event might come from.  As
+     such we want to make sure that INFERIOR_PTID is reset so that none of
+     the wait code relies on it - doing so is always a mistake.  */
+  switch_to_inferior_no_thread (inf);
+
   /* First check if there is a resumed thread with a wait status
      pending.  */
   if (ptid == minus_one_ptid || ptid.is_pid ())
@@ -3655,8 +3686,6 @@ do_target_wait (ptid_t wait_ptid, execution_control_state *ecs, int options)
 
   auto do_wait = [&] (inferior *inf)
   {
-    switch_to_inferior_no_thread (inf);
-
     ecs->ptid = do_target_wait_1 (inf, wait_ptid, &ecs->ws, options);
     ecs->target = inf->process_target ();
     return (ecs->ws.kind != TARGET_WAITKIND_IGNORE);
@@ -4073,11 +4102,15 @@ fetch_inferior_event (void *client_data)
     printf_unfiltered (_("completed.\n"));
 }
 
-/* Record the frame and location we're currently stepping through.  */
+/* See infrun.h.  */
+
 void
-set_step_info (struct frame_info *frame, struct symtab_and_line sal)
+set_step_info (thread_info *tp, struct frame_info *frame,
+              struct symtab_and_line sal)
 {
-  struct thread_info *tp = inferior_thread ();
+  /* This can be removed once this function no longer implicitly relies on the
+     inferior_ptid value.  */
+  gdb_assert (inferior_ptid == tp->ptid);
 
   tp->control.step_frame_id = get_frame_id (frame);
   tp->control.step_stack_frame_id = get_stack_frame_id (frame);
@@ -5305,6 +5338,15 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
            struct regcache *child_regcache;
            CORE_ADDR parent_pc;
 
+           if (ecs->ws.kind == TARGET_WAITKIND_FORKED)
+             {
+               struct displaced_step_inferior_state *displaced
+                 = get_displaced_stepping_state (parent_inf);
+
+               /* Restore scratch pad for child process.  */
+               displaced_step_restore (displaced, ecs->ws.value.related_pid);
+             }
+
            /* GDB has got TARGET_WAITKIND_FORKED or TARGET_WAITKIND_VFORKED,
               indicating that the displaced stepping of syscall instruction
               has been done.  Perform cleanup for parent process here.  Note
@@ -5315,15 +5357,6 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
               that needs it.  */
            start_step_over ();
 
-           if (ecs->ws.kind == TARGET_WAITKIND_FORKED)
-             {
-               struct displaced_step_inferior_state *displaced
-                 = get_displaced_stepping_state (parent_inf);
-
-               /* Restore scratch pad for child process.  */
-               displaced_step_restore (displaced, ecs->ws.value.related_pid);
-             }
-
            /* Since the vfork/fork syscall instruction was executed in the scratchpad,
               the child's PC is also within the scratchpad.  Set the child's PC
               to the parent's PC value, which has already been fixed up.
@@ -7171,7 +7204,7 @@ process_event_stop_test (struct execution_control_state *ecs)
   ecs->event_thread->control.step_range_start = stop_pc_sal.pc;
   ecs->event_thread->control.step_range_end = stop_pc_sal.end;
   ecs->event_thread->control.may_range_step = 1;
-  set_step_info (frame, stop_pc_sal);
+  set_step_info (ecs->event_thread, frame, stop_pc_sal);
 
   if (debug_infrun)
      fprintf_unfiltered (gdb_stdlog, "infrun: keep going\n");
This page took 0.027182 seconds and 4 git commands to generate.