Convert dprintf to vtable ops
[binutils-gdb.git] / gdb / displaced-stepping.h
index 928bfc0ccc97a58a4ca530388d86a68a0d244fa4..de40ae2f3d8740c06132cb326f780dded2f1c7d2 100644 (file)
@@ -1,6 +1,6 @@
 /* Displaced stepping related things.
 
-   Copyright (C) 2020 Free Software Foundation, Inc.
+   Copyright (C) 2020-2022 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #ifndef DISPLACED_STEPPING_H
 #define DISPLACED_STEPPING_H
 
+#include "gdbsupport/array-view.h"
 #include "gdbsupport/byte-vector.h"
 
+struct gdbarch;
 struct thread_info;
 
 /* True if we are debugging displaced stepping.  */
@@ -31,12 +33,7 @@ extern bool debug_displaced;
 /* Print a "displaced" debug statement.  */
 
 #define displaced_debug_printf(fmt, ...) \
-  do \
-    { \
-      if (debug_displaced) \
-       debug_prefixed_printf ("displaced", __func__, fmt, ##__VA_ARGS__); \
-    } \
-  while (0)
+  debug_prefixed_printf_cond (debug_displaced, "displaced",fmt, ##__VA_ARGS__)
 
 enum displaced_step_prepare_status
 {
@@ -62,7 +59,8 @@ enum displaced_step_finish_status
   DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED,
 };
 
-/* Base class for displaced stepping closures (the arch-specific data).  */
+/* Data returned by a gdbarch displaced_step_copy_insn method, to be passed to
+   the matching displaced_step_fixup method.  */
 
 struct displaced_step_copy_insn_closure
 {
@@ -80,6 +78,9 @@ struct buf_displaced_step_copy_insn_closure : displaced_step_copy_insn_closure
   : buf (buf_size)
   {}
 
+  /* The content of this buffer is up to the user of the class, but typically
+     original instruction bytes, used during fixup to determine what needs to
+     be fixed up.  */
   gdb::byte_vector buf;
 };
 
@@ -95,37 +96,115 @@ struct displaced_step_inferior_state
   /* Put this object back in its original state.  */
   void reset ()
   {
-    failed_before = 0;
-    step_thread = nullptr;
-    step_gdbarch = nullptr;
-    step_closure.reset ();
-    step_original = 0;
-    step_copy = 0;
-    step_saved_copy.clear ();
+    failed_before = false;
+    in_progress_count = 0;
+    unavailable = false;
   }
 
   /* True if preparing a displaced step ever failed.  If so, we won't
      try displaced stepping for this inferior again.  */
-  int failed_before;
+  bool failed_before;
 
-  /* If this is not nullptr, this is the thread carrying out a
-     displaced single-step in process PID.  This thread's state will
-     require fixing up once it has completed its step.  */
-  thread_info *step_thread;
+  /* Number of displaced steps in progress for this inferior.  */
+  unsigned int in_progress_count;
 
-  /* The architecture the thread had when we stepped it.  */
-  gdbarch *step_gdbarch;
+  /* If true, this tells GDB that it's not worth asking the gdbarch displaced
+     stepping implementation to prepare a displaced step, because it would
+     return UNAVAILABLE.  This is set and reset by the gdbarch in the
+     displaced_step_prepare and displaced_step_finish methods.  */
+  bool unavailable;
+};
+
+/* Per-thread displaced stepping state.  */
+
+struct displaced_step_thread_state
+{
+  /* Return true if this thread is currently executing a displaced step.  */
+  bool in_progress () const
+  {
+    return m_original_gdbarch != nullptr;
+  }
+
+  /* Return the gdbarch of the thread prior to the step.  */
+  gdbarch *get_original_gdbarch () const
+  {
+    return m_original_gdbarch;
+  }
+
+  /* Mark this thread as currently executing a displaced step.
+
+     ORIGINAL_GDBARCH is the current gdbarch of the thread (before the step
+     is executed).  */
+  void set (gdbarch *original_gdbarch)
+  {
+    m_original_gdbarch = original_gdbarch;
+  }
+
+  /* Mark this thread as no longer executing a displaced step.  */
+  void reset ()
+  {
+    m_original_gdbarch = nullptr;
+  }
+
+private:
+  gdbarch *m_original_gdbarch = nullptr;
+};
+
+/* Control access to multiple displaced stepping buffers at fixed addresses.  */
+
+struct displaced_step_buffers
+{
+  explicit displaced_step_buffers (gdb::array_view<CORE_ADDR> buffer_addrs)
+  {
+    gdb_assert (buffer_addrs.size () > 0);
+
+    m_buffers.reserve (buffer_addrs.size ());
+
+    for (CORE_ADDR buffer_addr : buffer_addrs)
+      m_buffers.emplace_back (buffer_addr);
+  }
+
+  displaced_step_prepare_status prepare (thread_info *thread,
+                                        CORE_ADDR &displaced_pc);
+
+  displaced_step_finish_status finish (gdbarch *arch, thread_info *thread,
+                                      gdb_signal sig);
+
+  const displaced_step_copy_insn_closure *
+    copy_insn_closure_by_addr (CORE_ADDR addr);
+
+  void restore_in_ptid (ptid_t ptid);
+
+private:
+
+  /* State of a single buffer.  */
+
+  struct displaced_step_buffer
+  {
+    explicit displaced_step_buffer (CORE_ADDR addr)
+      : addr (addr)
+    {}
+
+    /* Address of the buffer.  */
+    const CORE_ADDR addr;
+
+    /* The original PC of the instruction currently being stepped.  */
+    CORE_ADDR original_pc = 0;
+
+    /* If set, the thread currently using the buffer.  If unset, the buffer is not
+       used.  */
+    thread_info *current_thread = nullptr;
 
-  /* The closure provided gdbarch_displaced_step_copy_insn, to be used
-     for post-step cleanup.  */
-  displaced_step_copy_insn_closure_up step_closure;
+    /* Saved copy of the bytes in the displaced buffer, to be restored once the
+       buffer is no longer used.  */
+    gdb::byte_vector saved_copy;
 
-  /* The address of the original instruction, and the copy we
-     made.  */
-  CORE_ADDR step_original, step_copy;
+    /* Closure obtained from gdbarch_displaced_step_copy_insn, to be passed to
+       gdbarch_displaced_step_fixup_insn.  */
+    displaced_step_copy_insn_closure_up copy_insn_closure;
+  };
 
-  /* Saved contents of copy area.  */
-  gdb::byte_vector step_saved_copy;
+  std::vector<displaced_step_buffer> m_buffers;
 };
 
 #endif /* DISPLACED_STEPPING_H */