debuginfod-support.c \
dictionary.c \
disasm.c \
+ displaced-stepping.c \
dummy-frame.c \
dwarf2/abbrev.c \
dwarf2/attribute.c \
#include "defs.h"
#include "arch-utils.h"
#include "frame.h"
+#include "gdbarch.h"
#include "gdbcore.h"
#include "regcache.h"
#include "osabi.h"
#include "i386-linux-tdep.h"
#include "linux-tdep.h"
#include "gdbsupport/x86-xstate.h"
+#include "inferior.h"
#include "amd64-tdep.h"
#include "solib-svr4.h"
}
}
+struct amd64_linux_per_inferior
+{
+ amd64_linux_per_inferior (CORE_ADDR disp_step_buffer_addr)
+ : disp_step_buf_mgr (disp_step_buffer_addr)
+ {}
+
+ single_displaced_buffer_manager disp_step_buf_mgr;
+};
+
+static const inferior_key<amd64_linux_per_inferior>
+ amd64_linux_per_inferior_data;
+
+/* Get the per-inferior AMD64/Linux data for INF. */
+
+static amd64_linux_per_inferior *
+get_amd64_linux_per_inferior (inferior *inf, gdbarch *arch)
+{
+ amd64_linux_per_inferior *per_inf = amd64_linux_per_inferior_data.get (inf);
+
+ if (per_inf == nullptr)
+ {
+ /* Figure out where the displaced step buffer is. */
+ CORE_ADDR disp_step_buffer_addr = linux_displaced_step_location (arch);
+
+ per_inf = amd64_linux_per_inferior_data.emplace (inf, disp_step_buffer_addr);
+ }
+
+ return per_inf;
+}
+
+/* Implementation of the gdbarch_displaced_step_prepare method. */
+
+static displaced_step_prepare_status
+amd64_linux_displaced_step_prepare (gdbarch *arch, thread_info *thread)
+{
+ amd64_linux_per_inferior *per_inferior
+ = get_amd64_linux_per_inferior (thread->inf, arch);
+
+ return per_inferior->disp_step_buf_mgr.prepare (thread);
+}
+
+/* Implementation of the gdbarch_displaced_step_finish method. */
+
+static displaced_step_finish_status
+amd64_linux_displaced_step_finish (gdbarch *arch, thread_info *thread,
+ gdb_signal sig)
+{
+ amd64_linux_per_inferior *per_inferior
+ = get_amd64_linux_per_inferior (thread->inf, arch);
+
+ return per_inferior->disp_step_buf_mgr.finish (arch, thread, sig);
+}
+
static void
amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch)
{
set_gdbarch_displaced_step_copy_insn (gdbarch,
amd64_displaced_step_copy_insn);
set_gdbarch_displaced_step_fixup (gdbarch, amd64_displaced_step_fixup);
- set_gdbarch_displaced_step_location (gdbarch,
- linux_displaced_step_location);
+ set_gdbarch_displaced_step_prepare (gdbarch, amd64_linux_displaced_step_prepare);
+ set_gdbarch_displaced_step_finish (gdbarch, amd64_linux_displaced_step_finish);
set_gdbarch_process_record (gdbarch, i386_process_record);
set_gdbarch_process_record_signal (gdbarch, amd64_linux_record_signal);
gdb::byte_vector insn_buf;
};
+typedef std::unique_ptr<amd64_displaced_step_copy_insn_closure>
+ amd64_displaced_step_copy_insn_closure_up;
+
/* WARNING: Keep onebyte_has_modrm, twobyte_has_modrm in sync with
../opcodes/i386-dis.c (until libopcodes exports them, or an alternative,
at which point delete these in favor of libopcodes' versions). */
--- /dev/null
+#include "defs.h"
+
+#include "displaced-stepping.h"
+
+#include "gdbarch.h"
+#include "gdbthread.h"
+#include "target.h"
+#include "inferior.h"
+#include "gdbcore.h"
+
+displaced_step_copy_insn_closure::~displaced_step_copy_insn_closure() = default;
+
+displaced_step_prepare_status
+single_displaced_buffer_manager::prepare (thread_info *thread)
+{
+ /* Is a thread currently using the buffer? */
+ if (m_current_thread != nullptr)
+ {
+ /* If so, it better not be this thread. */
+ gdb_assert (thread != m_current_thread);
+ return DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE;
+ }
+
+ gdbarch *arch = thread->arch ();
+ struct regcache *regcache = thread->regcache ();
+ ULONGEST len = gdbarch_max_insn_length (arch);
+ m_original_pc = regcache_read_pc (regcache);
+
+ /* Save the original contents of the displaced stepping buffer. */
+ m_saved_copy.resize (len);
+
+ int status = target_read_memory (m_buffer_addr, m_saved_copy.data (), len);
+ if (status != 0)
+ throw_error (MEMORY_ERROR,
+ _("Error accessing memory address %s (%s) for "
+ "displaced-stepping scratch space."),
+ paddress (arch, m_buffer_addr), safe_strerror (status));
+
+ if (debug_displaced)
+ {
+ fprintf_unfiltered (gdb_stdlog, "displaced: saved %s: ",
+ paddress (arch, m_buffer_addr));
+ displaced_step_dump_bytes (gdb_stdlog, m_saved_copy.data (), len);
+ };
+
+ m_copy_insn_closure = gdbarch_displaced_step_copy_insn (arch,
+ m_original_pc,
+ m_buffer_addr,
+ regcache);
+ if (m_copy_insn_closure == nullptr)
+ {
+ /* The architecture doesn't know how or want to displaced step
+ this instruction or instruction sequence. Fallback to
+ stepping over the breakpoint in-line. */
+ return DISPLACED_STEP_PREPARE_STATUS_ERROR;
+ }
+
+ try
+ {
+ /* Resume execution at the copy. */
+ regcache_write_pc (regcache, m_buffer_addr);
+ }
+ catch (...)
+ {
+ /* Failed to write the PC. Release the architecture's displaced
+ stepping resources and the thread's displaced stepping state. */
+ m_copy_insn_closure.reset ();
+
+ return DISPLACED_STEP_PREPARE_STATUS_ERROR;
+ }
+
+ /* This marks the buffer as being in use. */
+ m_current_thread = thread;
+
+ return DISPLACED_STEP_PREPARE_STATUS_OK;
+}
+
+static void
+write_memory_ptid (ptid_t ptid, CORE_ADDR memaddr,
+ const gdb_byte *myaddr, int len)
+{
+ scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
+
+ inferior_ptid = ptid;
+ write_memory (memaddr, myaddr, len);
+}
+
+static bool
+displaced_step_instruction_executed_successfully (gdbarch *arch, gdb_signal signal)
+{
+ if (signal != GDB_SIGNAL_TRAP)
+ return false;
+
+ if (target_stopped_by_watchpoint ())
+ {
+ // FIXME: Not sure about this condition.
+ if (gdbarch_have_nonsteppable_watchpoint (arch)
+ || target_have_steppable_watchpoint)
+ return false;
+ }
+
+ return true;
+}
+
+displaced_step_finish_status
+single_displaced_buffer_manager::finish (gdbarch *arch, thread_info *thread,
+ gdb_signal sig)
+{
+ displaced_step_finish_status status;
+
+ gdb_assert (thread == m_current_thread);
+
+ ULONGEST len = gdbarch_max_insn_length (arch);
+
+ write_memory_ptid (thread->ptid, m_buffer_addr,
+ m_saved_copy.data (), len);
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog, "displaced: restored %s %s\n",
+ target_pid_to_str (thread->ptid).c_str (),
+ paddress (arch, m_buffer_addr));
+
+ regcache *rc = get_thread_regcache (thread);
+
+ bool instruction_executed_successfully
+ = displaced_step_instruction_executed_successfully (arch, sig);
+
+
+ if (instruction_executed_successfully)
+ {
+ gdbarch_displaced_step_fixup (arch, m_copy_insn_closure.get (), m_original_pc,
+ m_buffer_addr, rc);
+ status = DISPLACED_STEP_FINISH_STATUS_OK;
+ }
+ else
+ {
+ /* Since the instruction didn't complete, all we can do is relocate the
+ PC. */
+ CORE_ADDR pc = regcache_read_pc (rc);
+ pc = m_original_pc + (pc - m_buffer_addr);
+ regcache_write_pc (rc, pc);
+ status = DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED;
+ }
+
+ m_copy_insn_closure.reset ();
+ m_current_thread = nullptr;
+
+ return status;
+}
--- /dev/null
+#ifndef DISPLACED_STEPPING_H
+#define DISPLACED_STEPPING_H
+
+#include "gdbsupport/byte-vector.h"
+
+struct gdbarch;
+struct thread_info;
+
+enum displaced_step_prepare_status
+{
+ /* A displaced stepping buffer was successfully allocated and prepared. */
+ DISPLACED_STEP_PREPARE_STATUS_OK,
+
+ /* Something bad happened. */
+ DISPLACED_STEP_PREPARE_STATUS_ERROR,
+
+ /* Not enough resources are available at this time, try again later. */
+ DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE,
+};
+
+enum displaced_step_finish_status
+{
+ /* The instruction was stepped and fixed up. */
+ DISPLACED_STEP_FINISH_STATUS_OK,
+
+ /* The instruction was not stepped. */
+ DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED,
+};
+
+/* 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
+{
+ virtual ~displaced_step_copy_insn_closure () = 0;
+};
+
+typedef std::unique_ptr<displaced_step_copy_insn_closure>
+ displaced_step_copy_insn_closure_up;
+
+/* A simple displaced step closure that contains only a byte buffer. */
+
+struct buf_displaced_step_copy_insn_closure : displaced_step_copy_insn_closure
+{
+ buf_displaced_step_copy_insn_closure (int buf_size)
+ : buf (buf_size)
+ {}
+
+ gdb::byte_vector buf;
+};
+
+/* Per-inferior displaced stepping state. */
+
+struct displaced_step_inferior_state
+{
+ displaced_step_inferior_state ()
+ {
+ reset ();
+ }
+
+ /* Put this object back in its original state. */
+ void reset ()
+ {
+ failed_before = false;
+ }
+
+ /* True if preparing a displaced step ever failed. If so, we won't
+ try displaced stepping for this inferior again. */
+ bool failed_before;
+};
+
+/* 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;
+};
+
+/* Manage access to a single displaced stepping buffer, without any
+ sharing. */
+
+struct single_displaced_buffer_manager
+{
+ single_displaced_buffer_manager (CORE_ADDR buffer_addr)
+ : m_buffer_addr (buffer_addr)
+ {}
+
+ displaced_step_prepare_status prepare (thread_info *thread);
+
+ displaced_step_finish_status finish (gdbarch *arch, thread_info *thread,
+ gdb_signal sig);
+
+private:
+
+ CORE_ADDR m_original_pc;
+ CORE_ADDR m_buffer_addr;
+
+ /* If set, the thread currently using the buffer. */
+ thread_info *m_current_thread = nullptr;
+
+ gdb::byte_vector m_saved_copy;
+ displaced_step_copy_insn_closure_up m_copy_insn_closure;
+};
+
+
+#endif /* DISPLACED_STEPPING_H */
gdbarch_displaced_step_copy_insn_ftype *displaced_step_copy_insn;
gdbarch_displaced_step_hw_singlestep_ftype *displaced_step_hw_singlestep;
gdbarch_displaced_step_fixup_ftype *displaced_step_fixup;
- gdbarch_displaced_step_location_ftype *displaced_step_location;
+ gdbarch_displaced_step_prepare_ftype *displaced_step_prepare;
+ gdbarch_displaced_step_finish_ftype *displaced_step_finish;
gdbarch_relocate_instruction_ftype *relocate_instruction;
gdbarch_overlay_update_ftype *overlay_update;
gdbarch_core_read_description_ftype *core_read_description;
gdbarch->skip_permanent_breakpoint = default_skip_permanent_breakpoint;
gdbarch->displaced_step_hw_singlestep = default_displaced_step_hw_singlestep;
gdbarch->displaced_step_fixup = NULL;
- gdbarch->displaced_step_location = NULL;
+ gdbarch->displaced_step_prepare = NULL;
+ gdbarch->displaced_step_finish = NULL;
gdbarch->relocate_instruction = NULL;
gdbarch->has_shared_address_space = default_has_shared_address_space;
gdbarch->fast_tracepoint_valid_at = default_fast_tracepoint_valid_at;
/* Skip verify of displaced_step_copy_insn, has predicate. */
/* Skip verify of displaced_step_hw_singlestep, invalid_p == 0 */
/* Skip verify of displaced_step_fixup, has predicate. */
- if ((! gdbarch->displaced_step_location) != (! gdbarch->displaced_step_copy_insn))
- log.puts ("\n\tdisplaced_step_location");
+ if ((! gdbarch->displaced_step_prepare) != (! gdbarch->displaced_step_copy_insn))
+ log.puts ("\n\tdisplaced_step_prepare");
+ if ((! gdbarch->displaced_step_finish) != (! gdbarch->displaced_step_copy_insn))
+ log.puts ("\n\tdisplaced_step_finish");
/* Skip verify of relocate_instruction, has predicate. */
/* Skip verify of overlay_update, has predicate. */
/* Skip verify of core_read_description, has predicate. */
fprintf_unfiltered (file,
"gdbarch_dump: displaced_step_copy_insn = <%s>\n",
host_address_to_string (gdbarch->displaced_step_copy_insn));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: displaced_step_finish = <%s>\n",
+ host_address_to_string (gdbarch->displaced_step_finish));
fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_displaced_step_fixup_p() = %d\n",
gdbarch_displaced_step_fixup_p (gdbarch));
"gdbarch_dump: displaced_step_hw_singlestep = <%s>\n",
host_address_to_string (gdbarch->displaced_step_hw_singlestep));
fprintf_unfiltered (file,
- "gdbarch_dump: displaced_step_location = <%s>\n",
- host_address_to_string (gdbarch->displaced_step_location));
+ "gdbarch_dump: displaced_step_prepare = <%s>\n",
+ host_address_to_string (gdbarch->displaced_step_prepare));
fprintf_unfiltered (file,
"gdbarch_dump: double_bit = %s\n",
plongest (gdbarch->double_bit));
gdbarch->displaced_step_fixup = displaced_step_fixup;
}
-CORE_ADDR
-gdbarch_displaced_step_location (struct gdbarch *gdbarch)
+displaced_step_prepare_status
+gdbarch_displaced_step_prepare (struct gdbarch *gdbarch, thread_info *thread)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->displaced_step_prepare != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_displaced_step_prepare called\n");
+ return gdbarch->displaced_step_prepare (gdbarch, thread);
+}
+
+void
+set_gdbarch_displaced_step_prepare (struct gdbarch *gdbarch,
+ gdbarch_displaced_step_prepare_ftype displaced_step_prepare)
+{
+ gdbarch->displaced_step_prepare = displaced_step_prepare;
+}
+
+displaced_step_finish_status
+gdbarch_displaced_step_finish (struct gdbarch *gdbarch, thread_info *thread, gdb_signal sig)
{
gdb_assert (gdbarch != NULL);
- gdb_assert (gdbarch->displaced_step_location != NULL);
+ gdb_assert (gdbarch->displaced_step_finish != NULL);
if (gdbarch_debug >= 2)
- fprintf_unfiltered (gdb_stdlog, "gdbarch_displaced_step_location called\n");
- return gdbarch->displaced_step_location (gdbarch);
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_displaced_step_finish called\n");
+ return gdbarch->displaced_step_finish (gdbarch, thread, sig);
}
void
-set_gdbarch_displaced_step_location (struct gdbarch *gdbarch,
- gdbarch_displaced_step_location_ftype displaced_step_location)
+set_gdbarch_displaced_step_finish (struct gdbarch *gdbarch,
+ gdbarch_displaced_step_finish_ftype displaced_step_finish)
{
- gdbarch->displaced_step_location = displaced_step_location;
+ gdbarch->displaced_step_finish = displaced_step_finish;
}
int
#include "gdb_obstack.h"
#include "infrun.h"
#include "osabi.h"
+#include "displaced-stepping.h"
struct floatformat;
struct ui_file;
time.
For a general explanation of displaced stepping and how GDB uses it,
- see the comments in infrun.c. */
+ see the comments in infrun.c.
+ m;CORE_ADDR;displaced_step_location;thread_info *;thread;;NULL;;(! gdbarch->displaced_step_location) != (! gdbarch->displaced_step_copy_insn)
+ m;CORE_ADDR;displaced_step_release_location;CORE_ADDR;addr;;NULL;;(! gdbarch->displaced_step_location) != (! gdbarch->displaced_step_copy_insn) */
+
+typedef displaced_step_prepare_status (gdbarch_displaced_step_prepare_ftype) (struct gdbarch *gdbarch, thread_info *thread);
+extern displaced_step_prepare_status gdbarch_displaced_step_prepare (struct gdbarch *gdbarch, thread_info *thread);
+extern void set_gdbarch_displaced_step_prepare (struct gdbarch *gdbarch, gdbarch_displaced_step_prepare_ftype *displaced_step_prepare);
-typedef CORE_ADDR (gdbarch_displaced_step_location_ftype) (struct gdbarch *gdbarch);
-extern CORE_ADDR gdbarch_displaced_step_location (struct gdbarch *gdbarch);
-extern void set_gdbarch_displaced_step_location (struct gdbarch *gdbarch, gdbarch_displaced_step_location_ftype *displaced_step_location);
+typedef displaced_step_finish_status (gdbarch_displaced_step_finish_ftype) (struct gdbarch *gdbarch, thread_info *thread, gdb_signal sig);
+extern displaced_step_finish_status gdbarch_displaced_step_finish (struct gdbarch *gdbarch, thread_info *thread, gdb_signal sig);
+extern void set_gdbarch_displaced_step_finish (struct gdbarch *gdbarch, gdbarch_displaced_step_finish_ftype *displaced_step_finish);
/* Relocate an instruction to execute at a different address. OLDLOC
is the address in the inferior memory where the instruction to
#
# For a general explanation of displaced stepping and how GDB uses it,
# see the comments in infrun.c.
-m;CORE_ADDR;displaced_step_location;void;;;NULL;;(! gdbarch->displaced_step_location) != (! gdbarch->displaced_step_copy_insn)
+#m;CORE_ADDR;displaced_step_location;thread_info *;thread;;NULL;;(! gdbarch->displaced_step_location) != (! gdbarch->displaced_step_copy_insn)
+#m;CORE_ADDR;displaced_step_release_location;CORE_ADDR;addr;;NULL;;(! gdbarch->displaced_step_location) != (! gdbarch->displaced_step_copy_insn)
+m;displaced_step_prepare_status;displaced_step_prepare;thread_info *thread;thread;;NULL;;(! gdbarch->displaced_step_prepare) != (! gdbarch->displaced_step_copy_insn)
+m;displaced_step_finish_status;displaced_step_finish;thread_info *thread, gdb_signal sig;thread, sig;;NULL;;(! gdbarch->displaced_step_finish) != (! gdbarch->displaced_step_copy_insn)
# Relocate an instruction to execute at a different address. OLDLOC
# is the address in the inferior memory where the instruction to
#include "gdb_obstack.h"
#include "infrun.h"
#include "osabi.h"
+#include "displaced-stepping.h"
struct floatformat;
struct ui_file;
#include "gdbsupport/refcounted-object.h"
#include "gdbsupport/common-gdbthread.h"
#include "gdbsupport/forward-scope-exit.h"
+#include "displaced-stepping.h"
struct inferior;
struct process_stratum_target;
/* Mark this thread as running and notify observers. */
void set_running (bool running);
+ struct regcache *regcache ();
+ struct gdbarch *arch ();
+
struct thread_info *next = NULL;
ptid_t ptid; /* "Actual process id";
In fact, this may be overloaded with
fields point to self. */
struct thread_info *step_over_prev = NULL;
struct thread_info *step_over_next = NULL;
+
+ displaced_step_thread_state displaced_step_state;
};
/* A gdb::ref_ptr pointer to a thread_info. */
extern void global_thread_step_over_chain_enqueue (struct thread_info *tp);
+/* Remove TP from step-over chain LIST_P. */
+
+extern void thread_step_over_chain_remove (thread_info **list_p,
+ thread_info *tp);
+
/* Remove TP from the global pending step-over chain. */
-extern void global_thread_step_over_chain_remove (struct thread_info *tp);
+extern void global_thread_step_over_chain_remove (thread_info *tp);
-/* Return the next thread in the global step-over chain. NULL
- if TP is the last entry in the chain. */
+/* Return the next thread in the step-over chain whose head is CHAIN_HEAD.
+ Return NULL if TP is the last entry in the chain. */
-extern struct thread_info *global_thread_step_over_chain_next (struct thread_info *tp);
+extern thread_info *thread_step_over_chain_next (thread_info *chain_head,
+ thread_info *tp);
+
+/* Return the next thread in the global step-over chain. Return NULL if TP is
+ the last entry in the chain. */
+
+extern thread_info *global_thread_step_over_chain_next (thread_info *tp);
/* Return true if TP is in any step-over chain. */
extern int thread_is_in_step_over_chain (struct thread_info *tp);
+/* Return the length of the the step over chain TP is in. */
+
+extern int thread_step_over_chain_length (thread_info *tp);
+
/* Cancel any ongoing execution command. */
extern void thread_cancel_execution_command (struct thread_info *thr);
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
+#include "displaced-stepping.h"
#include "gdbcore.h"
#include "frame.h"
#include "value.h"
return closure_;
}
+static displaced_step_prepare_status
+i386_displaced_step_prepare (gdbarch *arch, thread_info *thread)
+{
+ gdb_assert (false);
+ return DISPLACED_STEP_PREPARE_STATUS_OK;
+}
+
+static displaced_step_finish_status
+i386_displaced_step_finish (gdbarch *arch, thread_info *thread, gdb_signal sig)
+{
+ gdb_assert (false);
+ return DISPLACED_STEP_FINISH_STATUS_OK;
+}
+
static void
i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
set_gdbarch_displaced_step_copy_insn (gdbarch,
i386_linux_displaced_step_copy_insn);
set_gdbarch_displaced_step_fixup (gdbarch, i386_displaced_step_fixup);
- set_gdbarch_displaced_step_location (gdbarch,
- linux_displaced_step_location);
+ set_gdbarch_displaced_step_prepare (gdbarch, i386_displaced_step_prepare);
+ set_gdbarch_displaced_step_finish (gdbarch, i386_displaced_step_finish);
/* Functions for 'catch syscall'. */
set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_I386);
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
+#include "displaced-stepping.h"
#include "gdbsupport/common-defs.h"
#include "gdbsupport/common-utils.h"
#include "infrun.h"
#include "top.h"
#include "inf-loop.h"
#include "regcache.h"
+#include "utils.h"
#include "value.h"
#include "observable.h"
#include "language.h"
displaced step operation on it. See displaced_step_prepare and
displaced_step_fixup for details. */
-/* Default destructor for displaced_step_copy_insn_closure. */
-
-displaced_step_copy_insn_closure::~displaced_step_copy_insn_closure () = default;
-
-/* Get the displaced stepping state of process PID. */
+/* Get the displaced stepping state of inferior INF. */
static displaced_step_inferior_state *
get_displaced_stepping_state (inferior *inf)
return &inf->displaced_step_state;
}
-/* Returns true if any inferior has a thread doing a displaced
- step. */
+/* Get the displaced stepping state of thread THREAD. */
-static bool
-displaced_step_in_progress_any_inferior ()
+static displaced_step_thread_state *
+get_displaced_stepping_state (thread_info *thread)
{
- for (inferior *i : all_inferiors ())
- {
- if (i->displaced_step_state.step_thread != nullptr)
- return true;
- }
-
- return false;
+ return &thread->displaced_step_state;
}
-/* Return true if thread represented by PTID is doing a displaced
- step. */
+/* Return true if the given thread is doing a displaced step. */
-static int
-displaced_step_in_progress_thread (thread_info *thread)
+static bool
+displaced_step_in_progress (thread_info *thread)
{
gdb_assert (thread != NULL);
- return get_displaced_stepping_state (thread->inf)->step_thread == thread;
+ return get_displaced_stepping_state (thread)->in_progress ();
}
-/* Return true if process PID has a thread doing a displaced step. */
+/* Return true if any thread of this inferior is doing a displaced step. */
-static int
+static bool
displaced_step_in_progress (inferior *inf)
{
- return get_displaced_stepping_state (inf)->step_thread != nullptr;
+ for (thread_info *thread : inf->non_exited_threads ())
+ {
+ if (displaced_step_in_progress (thread))
+ return true;
+ }
+
+ return false;
+}
+
+/* Return true if any thread is doing a displaced step. */
+
+static bool
+displaced_step_in_progress_any_thread ()
+{
+ for (thread_info *thread : all_non_exited_threads ())
+ {
+ if (displaced_step_in_progress (thread))
+ return true;
+ }
+
+ return false;
}
/* If inferior is in displaced stepping, and ADDR equals to starting address
struct displaced_step_copy_insn_closure *
get_displaced_step_copy_insn_closure_by_addr (CORE_ADDR addr)
{
- displaced_step_inferior_state *displaced
- = get_displaced_stepping_state (current_inferior ());
-
- /* If checking the mode of displaced instruction in copy area. */
- if (displaced->step_thread != nullptr
- && displaced->step_copy == addr)
- return displaced->step_closure.get ();
-
+// FIXME: implement me (only needed on ARM).
+// displaced_step_inferior_state *displaced
+// = get_displaced_stepping_state (current_inferior ());
+//
+// /* If checking the mode of displaced instruction in copy area. */
+// if (displaced->step_thread != nullptr
+// && displaced->step_copy == addr)
+// return displaced->step_closure.get ();
+//
return NULL;
}
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. */
+ /* Only check for the presence of copy_insn. Other required methods
+ are checked by the gdbarch validation to be provided if copy_insn is
+ provided. */
return gdbarch_displaced_step_copy_insn_p (arch);
}
return true;
}
-/* Simple function wrapper around displaced_step_inferior_state::reset. */
+/* Simple function wrapper around displaced_step_thread_state::reset. */
static void
-displaced_step_reset (displaced_step_inferior_state *displaced)
+displaced_step_reset (displaced_step_thread_state *displaced)
{
displaced->reset ();
}
stepped now; 0 if displaced stepping this thread got queued; or -1
if this instruction can't be displaced stepped. */
-static int
+static displaced_step_prepare_status
displaced_step_prepare_throw (thread_info *tp)
{
regcache *regcache = get_thread_regcache (tp);
struct gdbarch *gdbarch = regcache->arch ();
- const address_space *aspace = regcache->aspace ();
- CORE_ADDR original, copy;
- ULONGEST len;
- int status;
+ displaced_step_thread_state *thread_disp_step_state
+ = get_displaced_stepping_state (tp);
/* We should never reach this function if the architecture does not
support displaced stepping. */
jump/branch). */
tp->control.may_range_step = 0;
- /* We have to displaced step one thread at a time, as we only have
- access to a single scratch space per inferior. */
+ /* We are about to start a displaced step for this thread, if one is already
+ in progress, we goofed up somewhere. */
+ gdb_assert (!thread_disp_step_state->in_progress ());
- displaced_step_inferior_state *displaced
- = get_displaced_stepping_state (tp->inf);
+ scoped_restore_current_thread restore_thread;
- if (displaced->step_thread != nullptr)
- {
- /* Already waiting for a displaced step to finish. Defer this
- request and place in queue. */
+ switch_to_thread (tp);
+
+ CORE_ADDR original_pc = regcache_read_pc (regcache);
+
+ displaced_step_prepare_status status =
+ gdbarch_displaced_step_prepare (gdbarch, tp);
+ if (status == DISPLACED_STEP_PREPARE_STATUS_ERROR)
+ {
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
- "displaced: deferring step of %s\n",
+ "displaced: failed to prepare (%s)",
target_pid_to_str (tp->ptid).c_str ());
- global_thread_step_over_chain_enqueue (tp);
- return 0;
+ return DISPLACED_STEP_PREPARE_STATUS_ERROR;
}
- else
+ else if (status == DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE)
{
+ /* Not enough displaced stepping resources available, defer this
+ request by placing it the queue. */
+
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
- "displaced: stepping %s now\n",
+ "displaced: not enough resources available, "
+ "deferring step of %s\n",
target_pid_to_str (tp->ptid).c_str ());
- }
- displaced_step_reset (displaced);
-
- scoped_restore_current_thread restore_thread;
-
- switch_to_thread (tp);
-
- original = regcache_read_pc (regcache);
-
- copy = gdbarch_displaced_step_location (gdbarch);
- len = gdbarch_max_insn_length (gdbarch);
-
- if (breakpoint_in_range_p (aspace, copy, len))
- {
- /* There's a breakpoint set in the scratch pad location range
- (which is usually around the entry point). We'd either
- install it before resuming, which would overwrite/corrupt the
- scratch pad, or if it was already inserted, this displaced
- step would overwrite it. The latter is OK in the sense that
- we already assume that no thread is going to execute the code
- in the scratch pad range (after initial startup) anyway, but
- the former is unacceptable. Simply punt and fallback to
- stepping over this breakpoint in-line. */
- if (debug_displaced)
- {
- fprintf_unfiltered (gdb_stdlog,
- "displaced: breakpoint set in scratch pad. "
- "Stepping over breakpoint in-line instead.\n");
- }
-
- return -1;
- }
-
- /* Save the original contents of the copy area. */
- displaced->step_saved_copy.resize (len);
- status = target_read_memory (copy, displaced->step_saved_copy.data (), len);
- if (status != 0)
- throw_error (MEMORY_ERROR,
- _("Error accessing memory address %s (%s) for "
- "displaced-stepping scratch space."),
- paddress (gdbarch, copy), safe_strerror (status));
- if (debug_displaced)
- {
- fprintf_unfiltered (gdb_stdlog, "displaced: saved %s: ",
- paddress (gdbarch, copy));
- displaced_step_dump_bytes (gdb_stdlog,
- displaced->step_saved_copy.data (),
- len);
- };
+ global_thread_step_over_chain_enqueue (tp);
- 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
- stepping over the breakpoint in-line. */
- return -1;
- }
+ return DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE;
+ }
+
+ gdb_assert (status == DISPLACED_STEP_PREPARE_STATUS_OK);
+
+// FIXME: Should probably replicated in the arch implementation now.
+//
+// if (breakpoint_in_range_p (aspace, copy, len))
+// {
+// /* There's a breakpoint set in the scratch pad location range
+// (which is usually around the entry point). We'd either
+// install it before resuming, which would overwrite/corrupt the
+// scratch pad, or if it was already inserted, this displaced
+// step would overwrite it. The latter is OK in the sense that
+// we already assume that no thread is going to execute the code
+// in the scratch pad range (after initial startup) anyway, but
+// the former is unacceptable. Simply punt and fallback to
+// stepping over this breakpoint in-line. */
+// if (debug_displaced)
+// {
+// fprintf_unfiltered (gdb_stdlog,
+// "displaced: breakpoint set in scratch pad. "
+// "Stepping over breakpoint in-line instead.\n");
+// }
+//
+// gdb_assert (false);
+// gdbarch_displaced_step_release_location (gdbarch, copy);
+//
+// return -1;
+// }
/* Save the information we need to fix things up if the step
succeeds. */
- displaced->step_thread = tp;
- displaced->step_gdbarch = gdbarch;
- displaced->step_original = original;
- displaced->step_copy = copy;
-
- {
- displaced_step_reset_cleanup cleanup (displaced);
-
- /* Resume execution at the copy. */
- regcache_write_pc (regcache, copy);
+ thread_disp_step_state->set (gdbarch);
- cleanup.release ();
- }
+ // FIXME: get it from _prepare?
+ CORE_ADDR displaced_pc = 0;
if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: displaced pc to %s\n",
- paddress (gdbarch, copy));
+ fprintf_unfiltered (gdb_stdlog,
+ "displaced: prepared successfully thread=%s, "
+ "original_pc=%s, displaced_pc=%s\n",
+ target_pid_to_str (tp->ptid).c_str (),
+ paddress (gdbarch, original_pc),
+ paddress (gdbarch, displaced_pc));
- return 1;
+ return DISPLACED_STEP_PREPARE_STATUS_OK;
}
/* Wrapper for displaced_step_prepare_throw that disabled further
attempts at displaced stepping if we get a memory error. */
-static int
+static displaced_step_prepare_status
displaced_step_prepare (thread_info *thread)
{
- int prepared = -1;
+ displaced_step_prepare_status status
+ = DISPLACED_STEP_PREPARE_STATUS_ERROR;
try
{
- prepared = displaced_step_prepare_throw (thread);
+ status = displaced_step_prepare_throw (thread);
}
catch (const gdb_exception_error &ex)
{
displaced_state->failed_before = 1;
}
- return prepared;
-}
-
-static void
-write_memory_ptid (ptid_t ptid, CORE_ADDR memaddr,
- const gdb_byte *myaddr, int len)
-{
- scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
-
- inferior_ptid = ptid;
- write_memory (memaddr, myaddr, len);
-}
-
-/* Restore the contents of the copy area for thread PTID. */
-
-static void
-displaced_step_restore (struct displaced_step_inferior_state *displaced,
- ptid_t ptid)
-{
- ULONGEST len = gdbarch_max_insn_length (displaced->step_gdbarch);
-
- write_memory_ptid (ptid, displaced->step_copy,
- displaced->step_saved_copy.data (), len);
- if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: restored %s %s\n",
- target_pid_to_str (ptid).c_str (),
- paddress (displaced->step_gdbarch,
- displaced->step_copy));
+ return status;
}
/* If we displaced stepped an instruction successfully, adjust
-1. If the thread wasn't displaced stepping, return 0. */
static int
-displaced_step_fixup (thread_info *event_thread, enum gdb_signal signal)
+displaced_step_finish (thread_info *event_thread, enum gdb_signal signal)
{
- struct displaced_step_inferior_state *displaced
- = get_displaced_stepping_state (event_thread->inf);
- int ret;
+ displaced_step_thread_state *displaced
+ = get_displaced_stepping_state (event_thread);
- /* Was this event for the thread we displaced? */
- if (displaced->step_thread != event_thread)
+ /* Was this thread performing a displaced step? */
+ if (!displaced->in_progress ())
return 0;
+ displaced_step_reset_cleanup cleanup (displaced);
+
/* Fixup may need to read memory/registers. Switch to the thread
that we're fixing up. Also, target_stopped_by_watchpoint checks
the current thread, and displaced_step_restore performs ptid-dependent
memory accesses using current_inferior() and current_top_target(). */
switch_to_thread (event_thread);
- displaced_step_reset_cleanup cleanup (displaced);
-
- displaced_step_restore (displaced, displaced->step_thread->ptid);
+ /* Do the fixup, and release the resources acquired to do the displaced
+ step. */
+ displaced_step_finish_status finish_status =
+ gdbarch_displaced_step_finish (displaced->get_original_gdbarch (),
+ event_thread, signal);
- /* Did the instruction complete successfully? */
- if (signal == GDB_SIGNAL_TRAP
- && !(target_stopped_by_watchpoint ()
- && (gdbarch_have_nonsteppable_watchpoint (displaced->step_gdbarch)
- || target_have_steppable_watchpoint)))
- {
- /* Fix up the resulting state. */
- gdbarch_displaced_step_fixup (displaced->step_gdbarch,
- displaced->step_closure.get (),
- displaced->step_original,
- displaced->step_copy,
- get_thread_regcache (displaced->step_thread));
- ret = 1;
- }
+ if (finish_status == DISPLACED_STEP_FINISH_STATUS_OK)
+ return 1;
else
- {
- /* Since the instruction didn't complete, all we can do is
- relocate the PC. */
- struct regcache *regcache = get_thread_regcache (event_thread);
- CORE_ADDR pc = regcache_read_pc (regcache);
-
- pc = displaced->step_original + (pc - displaced->step_copy);
- regcache_write_pc (regcache, pc);
- ret = -1;
- }
-
- return ret;
+ return -1;
}
/* Data to be passed around while handling an event. This data is
start_step_over (void)
{
struct thread_info *tp, *next;
+ int started = 0;
/* Don't start a new step-over if we already have an in-line
step-over operation ongoing. */
if (step_over_info_valid_p ())
- return 0;
+ return started;
+
+ /* Steal the global thread step over chain. */
+ thread_info *threads_to_step = global_thread_step_over_chain_head;
+ global_thread_step_over_chain_head = NULL;
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: stealing list of %d threads to step from global queue\n",
+ thread_step_over_chain_length (threads_to_step));
- for (tp = global_thread_step_over_chain_head; tp != NULL; tp = next)
+ for (tp = threads_to_step; tp != NULL; tp = next)
{
struct execution_control_state ecss;
struct execution_control_state *ecs = &ecss;
gdb_assert (!tp->stop_requested);
- next = global_thread_step_over_chain_next (tp);
-
- /* If this inferior already has a displaced step in process,
- don't start a new one. */
- if (displaced_step_in_progress (tp->inf))
- continue;
+ next = thread_step_over_chain_next (threads_to_step, tp);
step_what = thread_still_needs_step_over (tp);
must_be_in_line = ((step_what & STEP_OVER_WATCHPOINT)
/* We currently stop all threads of all processes to step-over
in-line. If we need to start a new in-line step-over, let
any pending displaced steps finish first. */
- if (must_be_in_line && displaced_step_in_progress_any_inferior ())
- return 0;
-
- global_thread_step_over_chain_remove (tp);
+ if (must_be_in_line && displaced_step_in_progress_any_thread ())
+ continue;
- if (global_thread_step_over_chain_head == NULL)
- infrun_log_debug ("step-over queue now empty");
+ thread_step_over_chain_remove (&threads_to_step, tp);
if (tp->control.trap_expected
|| tp->resumed
if (!ecs->wait_some_more)
error (_("Command aborted."));
- gdb_assert (tp->resumed);
+ /* If the thread's step over could not be initiated, it was re-added
+ to the global step over chain. */
+ if (tp->resumed)
+ {
+ infrun_log_debug ("start_step_over: [%s] was resumed.\n",
+ target_pid_to_str (tp->ptid).c_str ());
+ gdb_assert (!thread_is_in_step_over_chain (tp));
+ }
+ else
+ {
+ infrun_log_debug ("infrun: start_step_over: [%s] was NOT resumed.\n",
+ target_pid_to_str (tp->ptid).c_str ());
+ gdb_assert (thread_is_in_step_over_chain (tp));
+
+ }
/* If we started a new in-line step-over, we're done. */
if (step_over_info_valid_p ())
{
gdb_assert (tp->control.trap_expected);
- return 1;
+ started = 1;
+ break;
}
if (!target_is_non_stop_p ())
/* With remote targets (at least), in all-stop, we can't
issue any further remote commands until the program stops
again. */
- return 1;
+ started = 1;
+ break;
}
/* Either the thread no longer needed a step-over, or a new
displaced step on a thread of other process. */
}
- return 0;
+ /* If there are threads left in the THREADS_TO_STEP list, but we have
+ detected that we can't start anything more, put back these threads
+ in the global list. */
+ if (threads_to_step == NULL)
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: step-over queue now empty\n");
+ }
+ else
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: putting back %d threads to step in global queue\n",
+ thread_step_over_chain_length (threads_to_step));
+ while (threads_to_step != nullptr)
+ {
+ thread_info *thread = threads_to_step;
+
+ /* Remove from that list. */
+ thread_step_over_chain_remove (&threads_to_step, thread);
+
+ /* Add to global list. */
+ global_thread_step_over_chain_enqueue (thread);
+
+ }
+ }
+
+ return started;
}
/* Update global variables holding ptids to hold NEW_PTID if they were
&& sig == GDB_SIGNAL_0
&& !current_inferior ()->waiting_for_vfork_done)
{
- int prepared = displaced_step_prepare (tp);
+ displaced_step_prepare_status prepare_status
+ = displaced_step_prepare (tp);
- if (prepared == 0)
+ if (prepare_status == DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE)
{
infrun_log_debug ("Got placed in step-over queue");
tp->control.trap_expected = 0;
return;
}
- else if (prepared < 0)
+ else if (prepare_status == DISPLACED_STEP_PREPARE_STATUS_ERROR)
{
/* Fallback to stepping over the breakpoint in-line. */
insert_breakpoints ();
}
- else if (prepared > 0)
+ else if (prepare_status == DISPLACED_STEP_PREPARE_STATUS_OK)
{
- struct displaced_step_inferior_state *displaced;
-
- /* Update pc to reflect the new address from which we will
- execute instructions due to displaced stepping. */
- 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.get ());
+ step = gdbarch_displaced_step_hw_singlestep (gdbarch, NULL);
}
+ else
+ gdb_assert_not_reached ("invalid displaced_step_prepare_status value");
}
/* Do we need to do it the hard way, w/temp breakpoints? */
struct inferior *inf = current_inferior ();
ptid_t pid_ptid = ptid_t (inf->pid);
- displaced_step_inferior_state *displaced = get_displaced_stepping_state (inf);
+ // displaced_step_inferior_state *displaced = get_displaced_stepping_state (inf);
/* Is any thread of this process displaced stepping? If not,
there's nothing else to do. */
- if (displaced->step_thread == nullptr)
+ if (displaced_step_in_progress (inf))
return;
infrun_log_debug ("displaced-stepping in-process while detaching");
scoped_restore restore_detaching = make_scoped_restore (&inf->detaching, true);
- while (displaced->step_thread != nullptr)
+ // FIXME
+ while (false)
{
struct execution_control_state ecss;
struct execution_control_state *ecs;
t->suspend.waitstatus.kind = TARGET_WAITKIND_IGNORE;
t->suspend.waitstatus_pending_p = 0;
- if (displaced_step_fixup (t, GDB_SIGNAL_0) < 0)
+ if (displaced_step_finish (t, GDB_SIGNAL_0) < 0)
{
/* Add it back to the step-over queue. */
infrun_log_debug ("displaced-step of %s "
sig = (event.ws.kind == TARGET_WAITKIND_STOPPED
? event.ws.value.sig : GDB_SIGNAL_0);
- if (displaced_step_fixup (t, sig) < 0)
+ if (displaced_step_finish (t, sig) < 0)
{
/* Add it back to the step-over queue. */
t->control.trap_expected = 0;
/* If checking displaced stepping is supported, and thread
ecs->ptid is displaced stepping. */
- if (displaced_step_in_progress_thread (ecs->event_thread))
+ if (displaced_step_in_progress (ecs->event_thread))
{
struct inferior *parent_inf
= find_inferior_ptid (ecs->target, ecs->ptid);
if (ecs->ws.kind == TARGET_WAITKIND_FORKED)
{
- struct displaced_step_inferior_state *displaced
- = get_displaced_stepping_state (parent_inf);
+ // 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);
+ //displaced_step_restore (displaced, ecs->ws.value.related_pid);
+ // FIXME: we should restore all the buffers that were currently in use
}
/* GDB has got TARGET_WAITKIND_FORKED or TARGET_WAITKIND_VFORKED,
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_fixup (ecs->event_thread, GDB_SIGNAL_TRAP);
+ displaced_step_finish (ecs->event_thread, GDB_SIGNAL_TRAP);
/* Start a new step-over in another thread if there's one
that needs it. */
start_step_over ();
{
int had_step_over_info;
- displaced_step_fixup (ecs->event_thread,
- ecs->event_thread->suspend.stop_signal);
+ displaced_step_finish (ecs->event_thread,
+ ecs->event_thread->suspend.stop_signal);
had_step_over_info = step_over_info_valid_p ();
started or re-started). */
extern void all_uis_on_sync_execution_starting (void);
-/* Base class for displaced stepping closures (the arch-specific data). */
-
-struct displaced_step_copy_insn_closure
-{
- virtual ~displaced_step_copy_insn_closure () = 0;
-};
-
-using displaced_step_copy_insn_closure_up
- = std::unique_ptr<displaced_step_copy_insn_closure>;
-
-/* A simple displaced step closure that contains only a byte buffer. */
-
-struct buf_displaced_step_copy_insn_closure : displaced_step_copy_insn_closure
-{
- buf_displaced_step_copy_insn_closure (int buf_size)
- : buf (buf_size)
- {}
-
- gdb::byte_vector buf;
-};
-
-/* Per-inferior displaced stepping state. */
-struct displaced_step_inferior_state
-{
- displaced_step_inferior_state ()
- {
- reset ();
- }
-
- /* 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 ();
- }
-
- /* True if preparing a displaced step ever failed. If so, we won't
- try displaced stepping for this inferior again. */
- int failed_before;
-
- /* If this is not nullptr, this is the thread carrying out a
- displaced single-step in process PID. This thread's state will
- require fixing up once it has completed its step. */
- thread_info *step_thread;
-
- /* The architecture the thread had when we stepped it. */
- gdbarch *step_gdbarch;
-
- /* The closure provided gdbarch_displaced_step_copy_insn, to be used
- for post-step cleanup. */
- displaced_step_copy_insn_closure_up step_closure;
-
- /* The address of the original instruction, and the copy we
- made. */
- CORE_ADDR step_original, step_copy;
-
- /* Saved contents of copy area. */
- gdb::byte_vector step_saved_copy;
-};
-
#endif /* INFRUN_H */
gdb_test_no_output "set debug displaced on"
gdb_test "continue" \
- "Continuing.*displaced: displaced pc to.*Breakpoint.*, ${test_end_label} ().*" \
+ "Continuing.*displaced: prepared successfully.*Breakpoint.*, ${test_end_label} ().*" \
"continue to ${test_end_label}"
gdb_test_no_output "set debug displaced off"
# that breakpoint.
gdb_test_no_output "set debug displaced 1"
gdb_test_multiple "next" "probe" {
- -re "displaced pc to.*$gdb_prompt $" {
+ -re "displaced: prepared successfully .*$gdb_prompt $" {
pass "supported"
}
-re ".*$gdb_prompt $" {
return refcount () == 0 && !is_current_thread (this);
}
+/* See gdbthread.h. */
+regcache *
+thread_info::regcache ()
+{
+ return get_thread_regcache (this);
+}
+
+/* See gdbthread.h. */
+gdbarch *
+thread_info::arch ()
+{
+ return this->regcache ()-> arch ();
+}
+
/* Add TP to the end of the step-over chain LIST_P. */
static void
}
}
-/* Remove TP from step-over chain LIST_P. */
+/* See gdbthread.h. */
-static void
-step_over_chain_remove (struct thread_info **list_p, struct thread_info *tp)
+void
+thread_step_over_chain_remove (thread_info **list_p, thread_info *tp)
{
gdb_assert (tp->step_over_next != NULL);
gdb_assert (tp->step_over_prev != NULL);
/* See gdbthread.h. */
-struct thread_info *
-global_thread_step_over_chain_next (struct thread_info *tp)
+void
+global_thread_step_over_chain_remove (thread_info *tp)
+{
+ thread_step_over_chain_remove (&global_thread_step_over_chain_head, tp);
+}
+
+/* See gdbthread.h. */
+
+thread_info *
+thread_step_over_chain_next (thread_info *chain_head, thread_info *tp)
{
- struct thread_info *next = tp->step_over_next;
+ thread_info *next = tp->step_over_next;
- return (next == global_thread_step_over_chain_head ? NULL : next);
+ return next == chain_head ? NULL : next;
+}
+
+/* See gdbthread.h. */
+
+thread_info *
+global_thread_step_over_chain_next (thread_info *tp)
+{
+ return thread_step_over_chain_next (global_thread_step_over_chain_head, tp);
}
/* See gdbthread.h. */
/* See gdbthread.h. */
-void
-global_thread_step_over_chain_enqueue (struct thread_info *tp)
+int thread_step_over_chain_length (thread_info *tp)
{
- step_over_chain_enqueue (&global_thread_step_over_chain_head, tp);
+ if (tp == nullptr)
+ return 0;
+
+ int num = 1;
+ thread_info *iter = tp->step_over_next;
+
+ while (iter != tp)
+ {
+ num++;
+ iter = iter->step_over_next;
+ }
+
+ return num;
+
+
}
/* See gdbthread.h. */
void
-global_thread_step_over_chain_remove (struct thread_info *tp)
+global_thread_step_over_chain_enqueue (struct thread_info *tp)
{
- step_over_chain_remove (&global_thread_step_over_chain_head, tp);
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "enqueueing thread %ld in global step over chain\n", tp->ptid.lwp());
+ step_over_chain_enqueue (&global_thread_step_over_chain_head, tp);
}
/* Delete the thread referenced by THR. If SILENT, don't notify