Commit 480af54c authored by Simon Marchi's avatar Simon Marchi
Browse files

gdb: make displaced stepping implementation capable of managing multiple buffers

The displaced_step_buffer class, introduced in the previous patch,
manages access to a single displaced step buffer.  Change it into
displaced_step_buffers (note the plural), which manages access to
multiple displaced step buffers.

When preparing a displaced step for a thread, it looks for an unused
buffer.

For now, all users still pass a single displaced step buffer, so no real
behavior change is expected here.  The following patch makes a user pass
more than one buffer, so the functionality introduced by this patch is
going to be useful in the next one.

gdb/ChangeLog:

	* displaced-stepping.h (struct displaced_step_buffer): Rename
	to...
	(struct displaced_step_buffers): ... this.
	<m_addr, m_current_thread, m_copy_insn_closure>: Remove.
	<struct displaced_step_buffer>: New inner class.
	<m_buffers>: New.
	* displaced-stepping.c (displaced_step_buffer::prepare): Rename
	to...
	(displaced_step_buffers::prepare): ... this, adjust for multiple
	buffers.
	(displaced_step_buffer::finish):  Rename to...
	(displaced_step_buffers::finish): ... this, adjust for multiple
	buffers.
	(displaced_step_buffer::copy_insn_closure_by_addr): Rename to...
	(displaced_step_buffers::copy_insn_closure_by_addr): ... this,
	adjust for multiple buffers.
	(displaced_step_buffer::restore_in_ptid): Rename to...
	(displaced_step_buffers::restore_in_ptid): ... this, adjust for
	multiple buffers.
	* linux-tdep.h (linux_init_abi): Change supports_displaced_step
	for num_disp_step_buffers.
	* linux-tdep.c (struct linux_gdbarch_data)
	<num_disp_step_buffers>: New field.
	(struct linux_info) <disp_step_buf>: Rename to...
	<disp_step_bufs>: ... this, change type to
	displaced_step_buffers.
	(linux_displaced_step_prepare): Use
	linux_gdbarch_data::num_disp_step_buffers to create that number
	of buffers.
	(linux_displaced_step_finish): Adjust.
	(linux_displaced_step_copy_insn_closure_by_addr): Adjust.
	(linux_displaced_step_restore_all_in_ptid): Adjust.
	(linux_init_abi): Change supports_displaced_step parameter for
	num_disp_step_buffers, save it in linux_gdbarch_data.
	* aarch64-linux-tdep.c (aarch64_linux_init_abi): Adjust.
	* alpha-linux-tdep.c (alpha_linux_init_abi): Adjust.
	* amd64-linux-tdep.c (amd64_linux_init_abi_common): Change
	supports_displaced_step parameter for num_disp_step_buffers.
	(amd64_linux_init_abi): Adjust.
	(amd64_x32_linux_init_abi): Adjust.
	* arc-linux-tdep.c (arc_linux_init_osabi): Adjust.
	* arm-linux-tdep.c (arm_linux_init_abi): Adjust.
	* bfin-linux-tdep.c (bfin_linux_init_abi): Adjust.
	* cris-linux-tdep.c (cris_linux_init_abi): Adjust.
	* csky-linux-tdep.c (csky_linux_init_abi): Adjust.
	* frv-linux-tdep.c (frv_linux_init_abi): Adjust.
	* hppa-linux-tdep.c (hppa_linux_init_abi): Adjust.
	* i386-linux-tdep.c (i386_linux_init_abi): Adjust.
	* ia64-linux-tdep.c (ia64_linux_init_abi): Adjust.
	* m32r-linux-tdep.c (m32r_linux_init_abi): Adjust.
	* m68k-linux-tdep.c (m68k_linux_init_abi):
	* microblaze-linux-tdep.c (microblaze_linux_init_abi):
	* mips-linux-tdep.c (mips_linux_init_abi): Adjust.
	* mn10300-linux-tdep.c (am33_linux_init_osabi): Adjust.
	* nios2-linux-tdep.c (nios2_linux_init_abi): Adjust.
	* or1k-linux-tdep.c (or1k_linux_init_abi): Adjust.
	* ppc-linux-tdep.c (ppc_linux_init_abi): Adjust.
	* riscv-linux-tdep.c (riscv_linux_init_abi): Adjust.
	* rs6000-tdep.c (struct ppc_inferior_data) <disp_step_buf>:
	Change type to displaced_step_buffers.
	* s390-linux-tdep.c (s390_linux_init_abi_any): Adjust.
	* sh-linux-tdep.c (sh_linux_init_abi): Adjust.
	* sparc-linux-tdep.c (sparc32_linux_init_abi): Adjust.
	* sparc64-linux-tdep.c (sparc64_linux_init_abi): Adjust.
	* tic6x-linux-tdep.c (tic6x_uclinux_init_abi): Adjust.
	* tilegx-linux-tdep.c (tilegx_linux_init_abi): Adjust.
	* xtensa-linux-tdep.c (xtensa_linux_init_abi): Adjust.

Change-Id: Ia9c02f207da2c9e1d9188020139619122392bb70
parent d9655058
2020-12-04 Simon Marchi <simon.marchi@efficios.com>
* displaced-stepping.h (struct displaced_step_buffer): Rename
to...
(struct displaced_step_buffers): ... this.
<m_addr, m_current_thread, m_copy_insn_closure>: Remove.
<struct displaced_step_buffer>: New inner class.
<m_buffers>: New.
* displaced-stepping.c (displaced_step_buffer::prepare): Rename
to...
(displaced_step_buffers::prepare): ... this, adjust for multiple
buffers.
(displaced_step_buffer::finish): Rename to...
(displaced_step_buffers::finish): ... this, adjust for multiple
buffers.
(displaced_step_buffer::copy_insn_closure_by_addr): Rename to...
(displaced_step_buffers::copy_insn_closure_by_addr): ... this,
adjust for multiple buffers.
(displaced_step_buffer::restore_in_ptid): Rename to...
(displaced_step_buffers::restore_in_ptid): ... this, adjust for
multiple buffers.
* linux-tdep.h (linux_init_abi): Change supports_displaced_step
for num_disp_step_buffers.
* linux-tdep.c (struct linux_gdbarch_data)
<num_disp_step_buffers>: New field.
(struct linux_info) <disp_step_buf>: Rename to...
<disp_step_bufs>: ... this, change type to
displaced_step_buffers.
(linux_displaced_step_prepare): Use
linux_gdbarch_data::num_disp_step_buffers to create that number
of buffers.
(linux_displaced_step_finish): Adjust.
(linux_displaced_step_copy_insn_closure_by_addr): Adjust.
(linux_displaced_step_restore_all_in_ptid): Adjust.
(linux_init_abi): Change supports_displaced_step parameter for
num_disp_step_buffers, save it in linux_gdbarch_data.
* aarch64-linux-tdep.c (aarch64_linux_init_abi): Adjust.
* alpha-linux-tdep.c (alpha_linux_init_abi): Adjust.
* amd64-linux-tdep.c (amd64_linux_init_abi_common): Change
supports_displaced_step parameter for num_disp_step_buffers.
(amd64_linux_init_abi): Adjust.
(amd64_x32_linux_init_abi): Adjust.
* arc-linux-tdep.c (arc_linux_init_osabi): Adjust.
* arm-linux-tdep.c (arm_linux_init_abi): Adjust.
* bfin-linux-tdep.c (bfin_linux_init_abi): Adjust.
* cris-linux-tdep.c (cris_linux_init_abi): Adjust.
* csky-linux-tdep.c (csky_linux_init_abi): Adjust.
* frv-linux-tdep.c (frv_linux_init_abi): Adjust.
* hppa-linux-tdep.c (hppa_linux_init_abi): Adjust.
* i386-linux-tdep.c (i386_linux_init_abi): Adjust.
* ia64-linux-tdep.c (ia64_linux_init_abi): Adjust.
* m32r-linux-tdep.c (m32r_linux_init_abi): Adjust.
* m68k-linux-tdep.c (m68k_linux_init_abi):
* microblaze-linux-tdep.c (microblaze_linux_init_abi):
* mips-linux-tdep.c (mips_linux_init_abi): Adjust.
* mn10300-linux-tdep.c (am33_linux_init_osabi): Adjust.
* nios2-linux-tdep.c (nios2_linux_init_abi): Adjust.
* or1k-linux-tdep.c (or1k_linux_init_abi): Adjust.
* ppc-linux-tdep.c (ppc_linux_init_abi): Adjust.
* riscv-linux-tdep.c (riscv_linux_init_abi): Adjust.
* rs6000-tdep.c (struct ppc_inferior_data) <disp_step_buf>:
Change type to displaced_step_buffers.
* s390-linux-tdep.c (s390_linux_init_abi_any): Adjust.
* sh-linux-tdep.c (sh_linux_init_abi): Adjust.
* sparc-linux-tdep.c (sparc32_linux_init_abi): Adjust.
* sparc64-linux-tdep.c (sparc64_linux_init_abi): Adjust.
* tic6x-linux-tdep.c (tic6x_uclinux_init_abi): Adjust.
* tilegx-linux-tdep.c (tilegx_linux_init_abi): Adjust.
* xtensa-linux-tdep.c (xtensa_linux_init_abi): Adjust.
2020-12-04 Simon Marchi <simon.marchi@efficios.com> 2020-12-04 Simon Marchi <simon.marchi@efficios.com>
   
* linux-tdep.c (init_linux_gdbarch_data): Change parameter to * linux-tdep.c (init_linux_gdbarch_data): Change parameter to
......
...@@ -1445,7 +1445,7 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) ...@@ -1445,7 +1445,7 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
tdep->lowest_pc = 0x8000; tdep->lowest_pc = 0x8000;
linux_init_abi (info, gdbarch, true); linux_init_abi (info, gdbarch, 1);
set_solib_svr4_fetch_link_map_offsets (gdbarch, set_solib_svr4_fetch_link_map_offsets (gdbarch,
svr4_lp64_fetch_link_map_offsets); svr4_lp64_fetch_link_map_offsets);
......
...@@ -356,7 +356,7 @@ alpha_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) ...@@ -356,7 +356,7 @@ alpha_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{ {
struct gdbarch_tdep *tdep; struct gdbarch_tdep *tdep;
linux_init_abi (info, gdbarch, false); linux_init_abi (info, gdbarch, 0);
/* Hook into the DWARF CFI frame unwinder. */ /* Hook into the DWARF CFI frame unwinder. */
alpha_dwarf2_init_abi (info, gdbarch); alpha_dwarf2_init_abi (info, gdbarch);
......
...@@ -1796,11 +1796,11 @@ amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch, ...@@ -1796,11 +1796,11 @@ amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
static void static void
amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch, amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch,
bool supports_displaced_step) int num_disp_step_buffers)
{ {
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
linux_init_abi (info, gdbarch, supports_displaced_step); linux_init_abi (info, gdbarch, num_disp_step_buffers);
tdep->sigtramp_p = amd64_linux_sigtramp_p; tdep->sigtramp_p = amd64_linux_sigtramp_p;
tdep->sigcontext_addr = amd64_linux_sigcontext_addr; tdep->sigcontext_addr = amd64_linux_sigcontext_addr;
...@@ -1880,7 +1880,7 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) ...@@ -1880,7 +1880,7 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
if (!valid_p) if (!valid_p)
return; return;
amd64_linux_init_abi_common (info, gdbarch, true); amd64_linux_init_abi_common (info, gdbarch, 1);
/* Initialize the amd64_linux_record_tdep. */ /* Initialize the amd64_linux_record_tdep. */
/* These values are the size of the type that will be used in a system /* These values are the size of the type that will be used in a system
...@@ -2095,7 +2095,7 @@ amd64_x32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) ...@@ -2095,7 +2095,7 @@ amd64_x32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
if (!valid_p) if (!valid_p)
return; return;
amd64_linux_init_abi_common (info, gdbarch, false); amd64_linux_init_abi_common (info, gdbarch, 0);
/* Initialize the amd64_x32_linux_record_tdep. */ /* Initialize the amd64_x32_linux_record_tdep. */
/* These values are the size of the type that will be used in a system /* These values are the size of the type that will be used in a system
......
...@@ -439,7 +439,7 @@ arc_linux_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch) ...@@ -439,7 +439,7 @@ arc_linux_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
*/ */
tdep->jb_pc = 15; tdep->jb_pc = 15;
linux_init_abi (info, gdbarch, false); linux_init_abi (info, gdbarch, 0);
/* Set up target dependent GDB architecture entries. */ /* Set up target dependent GDB architecture entries. */
set_gdbarch_cannot_fetch_register (gdbarch, arc_linux_cannot_fetch_register); set_gdbarch_cannot_fetch_register (gdbarch, arc_linux_cannot_fetch_register);
......
...@@ -1721,7 +1721,7 @@ arm_linux_init_abi (struct gdbarch_info info, ...@@ -1721,7 +1721,7 @@ arm_linux_init_abi (struct gdbarch_info info,
NULL }; NULL };
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
linux_init_abi (info, gdbarch, true); linux_init_abi (info, gdbarch, 1);
tdep->lowest_pc = 0x8000; tdep->lowest_pc = 0x8000;
if (info.byte_order_for_code == BFD_ENDIAN_BIG) if (info.byte_order_for_code == BFD_ENDIAN_BIG)
......
...@@ -150,7 +150,7 @@ bfin_linux_get_syscall_number (struct gdbarch *gdbarch, ...@@ -150,7 +150,7 @@ bfin_linux_get_syscall_number (struct gdbarch *gdbarch,
static void static void
bfin_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) bfin_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{ {
linux_init_abi (info, gdbarch, false); linux_init_abi (info, gdbarch, 0);
/* Set the sigtramp frame sniffer. */ /* Set the sigtramp frame sniffer. */
tramp_frame_prepend_unwinder (gdbarch, &bfin_linux_sigframe); tramp_frame_prepend_unwinder (gdbarch, &bfin_linux_sigframe);
......
...@@ -35,7 +35,7 @@ cris_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) ...@@ -35,7 +35,7 @@ cris_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{ {
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
linux_init_abi (info, gdbarch, false); linux_init_abi (info, gdbarch, 0);
if (tdep->cris_version == 32) if (tdep->cris_version == 32)
/* Threaded debugging is only supported on CRISv32 for now. */ /* Threaded debugging is only supported on CRISv32 for now. */
......
...@@ -233,7 +233,7 @@ csky_linux_rt_sigreturn_tramp_frame = { ...@@ -233,7 +233,7 @@ csky_linux_rt_sigreturn_tramp_frame = {
static void static void
csky_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) csky_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{ {
linux_init_abi (info, gdbarch, false); linux_init_abi (info, gdbarch, 0);
/* Shared library handling. */ /* Shared library handling. */
set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
......
...@@ -44,82 +44,121 @@ show_debug_displaced (struct ui_file *file, int from_tty, ...@@ -44,82 +44,121 @@ show_debug_displaced (struct ui_file *file, int from_tty,
} }
displaced_step_prepare_status displaced_step_prepare_status
displaced_step_buffer::prepare (thread_info *thread, CORE_ADDR &displaced_pc) displaced_step_buffers::prepare (thread_info *thread, CORE_ADDR &displaced_pc)
{ {
gdb_assert (!thread->displaced_step_state.in_progress ()); gdb_assert (!thread->displaced_step_state.in_progress ());
/* Is a thread currently using the buffer? */ /* Sanity check: the thread should not be using a buffer at this point. */
if (m_current_thread != nullptr) for (displaced_step_buffer &buf : m_buffers)
{ gdb_assert (buf.current_thread != thread);
/* If so, it better not be this thread. */
gdb_assert (thread != m_current_thread);
return DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE;
}
regcache *regcache = get_thread_regcache (thread); regcache *regcache = get_thread_regcache (thread);
const address_space *aspace = regcache->aspace (); const address_space *aspace = regcache->aspace ();
gdbarch *arch = regcache->arch (); gdbarch *arch = regcache->arch ();
ULONGEST len = gdbarch_max_insn_length (arch); ULONGEST len = gdbarch_max_insn_length (arch);
if (breakpoint_in_range_p (aspace, m_addr, len)) /* Search for an unused buffer. */
{ displaced_step_buffer *buffer = nullptr;
/* There's a breakpoint set in the scratch pad location range displaced_step_prepare_status fail_status
(which is usually around the entry point). We'd either = DISPLACED_STEP_PREPARE_STATUS_CANT;
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. */
displaced_debug_printf ("breakpoint set in scratch pad. "
"Stepping over breakpoint in-line instead.");
return DISPLACED_STEP_PREPARE_STATUS_CANT; for (displaced_step_buffer &candidate : m_buffers)
{
bool bp_in_range = breakpoint_in_range_p (aspace, candidate.addr, len);
bool is_free = candidate.current_thread == nullptr;
if (!bp_in_range)
{
if (is_free)
{
buffer = &candidate;
break;
}
else
{
/* This buffer would be suitable, but it's used right now. */
fail_status = DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE;
}
}
else
{
/* 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. */
displaced_debug_printf ("breakpoint set in displaced stepping "
"buffer at %s, can't use.",
paddress (arch, candidate.addr));
}
} }
m_original_pc = regcache_read_pc (regcache); if (buffer == nullptr)
displaced_pc = m_addr; return fail_status;
displaced_debug_printf ("selected buffer at %s",
paddress (arch, buffer->addr));
/* Save the original PC of the thread. */
buffer->original_pc = regcache_read_pc (regcache);
/* Return displaced step buffer address to caller. */
displaced_pc = buffer->addr;
/* Save the original contents of the displaced stepping buffer. */ /* Save the original contents of the displaced stepping buffer. */
m_saved_copy.resize (len); buffer->saved_copy.resize (len);
int status = target_read_memory (m_addr, m_saved_copy.data (), len); int status = target_read_memory (buffer->addr,
buffer->saved_copy.data (), len);
if (status != 0) if (status != 0)
throw_error (MEMORY_ERROR, throw_error (MEMORY_ERROR,
_("Error accessing memory address %s (%s) for " _("Error accessing memory address %s (%s) for "
"displaced-stepping scratch space."), "displaced-stepping scratch space."),
paddress (arch, m_addr), safe_strerror (status)); paddress (arch, buffer->addr), safe_strerror (status));
displaced_debug_printf ("saved %s: %s", displaced_debug_printf ("saved %s: %s",
paddress (arch, m_addr), paddress (arch, buffer->addr),
displaced_step_dump_bytes displaced_step_dump_bytes
(m_saved_copy.data (), len).c_str ()); (buffer->saved_copy.data (), len).c_str ());
/* Save this in a local variable first, so it's released if code below /* Save this in a local variable first, so it's released if code below
throws. */ throws. */
displaced_step_copy_insn_closure_up copy_insn_closure displaced_step_copy_insn_closure_up copy_insn_closure
= gdbarch_displaced_step_copy_insn (arch, m_original_pc, m_addr, regcache); = gdbarch_displaced_step_copy_insn (arch, buffer->original_pc,
buffer->addr, regcache);
if (copy_insn_closure == nullptr) if (copy_insn_closure == nullptr)
{ {
/* The architecture doesn't know how or want to displaced step /* The architecture doesn't know how or want to displaced step
this instruction or instruction sequence. Fallback to this instruction or instruction sequence. Fallback to
stepping over the breakpoint in-line. */ stepping over the breakpoint in-line. */
return DISPLACED_STEP_PREPARE_STATUS_CANT; return DISPLACED_STEP_PREPARE_STATUS_CANT;
} }
/* Resume execution at the copy. */ /* Resume execution at the copy. */
regcache_write_pc (regcache, m_addr); regcache_write_pc (regcache, buffer->addr);
/* This marks the buffer as being in use. */ /* This marks the buffer as being in use. */
m_current_thread = thread; buffer->current_thread = thread;
/* Save this, now that we know everything went fine. */ /* Save this, now that we know everything went fine. */
m_copy_insn_closure = std::move (copy_insn_closure); buffer->copy_insn_closure = std::move (copy_insn_closure);
/* Tell infrun not to try preparing a displaced step again for this inferior. */ /* Tell infrun not to try preparing a displaced step again for this inferior if
all buffers are taken. */
thread->inf->displaced_step_state.unavailable = true; thread->inf->displaced_step_state.unavailable = true;
for (const displaced_step_buffer &buf : m_buffers)
{
if (buf.current_thread == nullptr)
{
thread->inf->displaced_step_state.unavailable = false;
break;
}
}
return DISPLACED_STEP_PREPARE_STATUS_OK; return DISPLACED_STEP_PREPARE_STATUS_OK;
} }
...@@ -152,21 +191,34 @@ displaced_step_instruction_executed_successfully (gdbarch *arch, ...@@ -152,21 +191,34 @@ displaced_step_instruction_executed_successfully (gdbarch *arch,
} }
displaced_step_finish_status displaced_step_finish_status
displaced_step_buffer::finish (gdbarch *arch, thread_info *thread, displaced_step_buffers::finish (gdbarch *arch, thread_info *thread,
gdb_signal sig) gdb_signal sig)
{ {
gdb_assert (thread->displaced_step_state.in_progress ()); gdb_assert (thread->displaced_step_state.in_progress ());
gdb_assert (thread == m_current_thread);
/* Find the buffer this thread was using. */
displaced_step_buffer *buffer = nullptr;
for (displaced_step_buffer &candidate : m_buffers)
{
if (candidate.current_thread == thread)
{
buffer = &candidate;
break;
}
}
gdb_assert (buffer != nullptr);
/* Move this to a local variable so it's released in case something goes /* Move this to a local variable so it's released in case something goes
wrong. */ wrong. */
displaced_step_copy_insn_closure_up copy_insn_closure displaced_step_copy_insn_closure_up copy_insn_closure
= std::move (m_copy_insn_closure); = std::move (buffer->copy_insn_closure);
gdb_assert (copy_insn_closure != nullptr); gdb_assert (copy_insn_closure != nullptr);
/* Reset M_CURRENT_THREAD immediately to mark the buffer as available, in case /* Reset BUFFER->CURRENT_THREAD immediately to mark the buffer as available,
something goes wrong below. */ in case something goes wrong below. */
m_current_thread = nullptr; buffer->current_thread = nullptr;
/* Now that a buffer gets freed, tell infrun it can ask us to prepare a displaced /* Now that a buffer gets freed, tell infrun it can ask us to prepare a displaced
step again for this inferior. Do that here in case something goes wrong step again for this inferior. Do that here in case something goes wrong
...@@ -175,12 +227,13 @@ displaced_step_buffer::finish (gdbarch *arch, thread_info *thread, ...@@ -175,12 +227,13 @@ displaced_step_buffer::finish (gdbarch *arch, thread_info *thread,
ULONGEST len = gdbarch_max_insn_length (arch); ULONGEST len = gdbarch_max_insn_length (arch);
write_memory_ptid (thread->ptid, m_addr, /* Restore memory of the buffer. */
m_saved_copy.data (), len); write_memory_ptid (thread->ptid, buffer->addr,
buffer->saved_copy.data (), len);
displaced_debug_printf ("restored %s %s", displaced_debug_printf ("restored %s %s",
target_pid_to_str (thread->ptid).c_str (), target_pid_to_str (thread->ptid).c_str (),
paddress (arch, m_addr)); paddress (arch, buffer->addr));
regcache *rc = get_thread_regcache (thread); regcache *rc = get_thread_regcache (thread);
...@@ -189,8 +242,9 @@ displaced_step_buffer::finish (gdbarch *arch, thread_info *thread, ...@@ -189,8 +242,9 @@ displaced_step_buffer::finish (gdbarch *arch, thread_info *thread,
if (instruction_executed_successfully) if (instruction_executed_successfully)
{ {
gdbarch_displaced_step_fixup (arch, copy_insn_closure.get (), m_original_pc, gdbarch_displaced_step_fixup (arch, copy_insn_closure.get (),
m_addr, rc); buffer->original_pc,
buffer->addr, rc);
return DISPLACED_STEP_FINISH_STATUS_OK; return DISPLACED_STEP_FINISH_STATUS_OK;
} }
else else
...@@ -198,35 +252,41 @@ displaced_step_buffer::finish (gdbarch *arch, thread_info *thread, ...@@ -198,35 +252,41 @@ displaced_step_buffer::finish (gdbarch *arch, thread_info *thread,
/* Since the instruction didn't complete, all we can do is relocate the /* Since the instruction didn't complete, all we can do is relocate the
PC. */ PC. */
CORE_ADDR pc = regcache_read_pc (rc); CORE_ADDR pc = regcache_read_pc (rc);
pc = m_original_pc + (pc - m_addr); pc = buffer->original_pc + (pc - buffer->addr);
regcache_write_pc (rc, pc); regcache_write_pc (rc, pc);
return DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED; return DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED;
} }
} }
const displaced_step_copy_insn_closure * const displaced_step_copy_insn_closure *
displaced_step_buffer::copy_insn_closure_by_addr (CORE_ADDR addr) displaced_step_buffers::copy_insn_closure_by_addr (CORE_ADDR addr)
{ {
if (addr == m_addr) for (const displaced_step_buffer &buffer : m_buffers)
return m_copy_insn_closure.get (); {
else if (addr == buffer.addr)
return nullptr; return buffer.copy_insn_closure.get ();
}
return nullptr;
} }
void void
displaced_step_buffer::restore_in_ptid (ptid_t ptid) displaced_step_buffers::restore_in_ptid (ptid_t ptid)
{ {
if (m_current_thread != nullptr) for (const displaced_step_buffer &buffer : m_buffers)
{ {
regcache *regcache = get_thread_regcache (m_current_thread); if (buffer.current_thread == nullptr)
continue;
regcache *regcache = get_thread_regcache (buffer.current_thread);
gdbarch *arch = regcache->arch (); gdbarch *arch = regcache->arch ();
ULONGEST len = gdbarch_max_insn_length (arch); ULONGEST len = gdbarch_max_insn_length (arch);
write_memory_ptid (ptid, m_addr, m_saved_copy.data (), len); write_memory_ptid (ptid, buffer.addr, buffer.saved_copy.data (), len);
displaced_debug_printf ("restored in ptid %s %s", displaced_debug_printf ("restored in ptid %s %s",
target_pid_to_str (ptid).c_str (), target_pid_to_str (ptid).c_str (),
paddress (arch, m_addr)); paddress (arch, buffer.addr));
} }
} }
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#ifndef DISPLACED_STEPPING_H #ifndef DISPLACED_STEPPING_H
#define DISPLACED_STEPPING_H #define DISPLACED_STEPPING_H
#include "gdbsupport/array-view.h"
#include "gdbsupport/byte-vector.h" #include "gdbsupport/byte-vector.h"
struct gdbarch; struct gdbarch;
...@@ -154,13 +155,19 @@ private: ...@@ -154,13 +155,19 @@ private:
gdbarch *m_original_gdbarch = nullptr; gdbarch *m_original_gdbarch = nullptr;
}; };
/* Manage access to a single displaced stepping buffer. */ /* Control access to multiple displaced stepping buffers at fixed addresses. */
struct displaced_step_buffer struct displaced_step_buffers
{ {
explicit displaced_step_buffer (CORE_ADDR buffer_addr) explicit displaced_step_buffers (gdb::array_view<CORE_ADDR> buffer_addrs)
: m_addr (buffer_addr) {
{} 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, displaced_step_prepare_status prepare (thread_info *thread,
CORE_ADDR &displaced_pc); CORE_ADDR &displaced_pc);
...@@ -174,21 +181,35 @@ struct displaced_step_buffer ...@@ -174,21 +181,35 @@ struct displaced_step_buffer
void restore_in_ptid (ptid_t ptid);