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
This commit is contained in:
Simon Marchi 2020-12-04 16:43:56 -05:00
parent d965505887
commit 480af54cf6
34 changed files with 295 additions and 126 deletions

View File

@ -1,3 +1,73 @@
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>
* linux-tdep.c (init_linux_gdbarch_data): Change parameter to

View File

@ -1445,7 +1445,7 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
tdep->lowest_pc = 0x8000;
linux_init_abi (info, gdbarch, true);
linux_init_abi (info, gdbarch, 1);
set_solib_svr4_fetch_link_map_offsets (gdbarch,
svr4_lp64_fetch_link_map_offsets);

View File

@ -356,7 +356,7 @@ alpha_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep;
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
/* Hook into the DWARF CFI frame unwinder. */
alpha_dwarf2_init_abi (info, gdbarch);

View File

@ -1796,11 +1796,11 @@ amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
static void
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);
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->sigcontext_addr = amd64_linux_sigcontext_addr;
@ -1880,7 +1880,7 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
if (!valid_p)
return;
amd64_linux_init_abi_common (info, gdbarch, true);
amd64_linux_init_abi_common (info, gdbarch, 1);
/* Initialize the amd64_linux_record_tdep. */
/* 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)
if (!valid_p)
return;
amd64_linux_init_abi_common (info, gdbarch, false);
amd64_linux_init_abi_common (info, gdbarch, 0);
/* Initialize the amd64_x32_linux_record_tdep. */
/* These values are the size of the type that will be used in a system

View File

@ -439,7 +439,7 @@ arc_linux_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
*/
tdep->jb_pc = 15;
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
/* Set up target dependent GDB architecture entries. */
set_gdbarch_cannot_fetch_register (gdbarch, arc_linux_cannot_fetch_register);

View File

@ -1721,7 +1721,7 @@ arm_linux_init_abi (struct gdbarch_info info,
NULL };
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
linux_init_abi (info, gdbarch, true);
linux_init_abi (info, gdbarch, 1);
tdep->lowest_pc = 0x8000;
if (info.byte_order_for_code == BFD_ENDIAN_BIG)

View File

@ -150,7 +150,7 @@ bfin_linux_get_syscall_number (struct gdbarch *gdbarch,
static void
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. */
tramp_frame_prepend_unwinder (gdbarch, &bfin_linux_sigframe);

View File

@ -35,7 +35,7 @@ cris_linux_init_abi (struct gdbarch_info info, struct gdbarch *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)
/* Threaded debugging is only supported on CRISv32 for now. */

View File

@ -233,7 +233,7 @@ csky_linux_rt_sigreturn_tramp_frame = {
static void
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. */
set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);

View File

@ -44,82 +44,121 @@ show_debug_displaced (struct ui_file *file, int from_tty,
}
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 ());
/* 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;
}
/* Sanity check: the thread should not be using a buffer at this point. */
for (displaced_step_buffer &buf : m_buffers)
gdb_assert (buf.current_thread != thread);
regcache *regcache = get_thread_regcache (thread);
const address_space *aspace = regcache->aspace ();
gdbarch *arch = regcache->arch ();
ULONGEST len = gdbarch_max_insn_length (arch);
if (breakpoint_in_range_p (aspace, m_addr, 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. */
displaced_debug_printf ("breakpoint set in scratch pad. "
"Stepping over breakpoint in-line instead.");
/* Search for an unused buffer. */
displaced_step_buffer *buffer = nullptr;
displaced_step_prepare_status fail_status
= DISPLACED_STEP_PREPARE_STATUS_CANT;
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);
displaced_pc = m_addr;
if (buffer == nullptr)
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. */
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)
throw_error (MEMORY_ERROR,
_("Error accessing memory address %s (%s) for "
"displaced-stepping scratch space."),
paddress (arch, m_addr), safe_strerror (status));
paddress (arch, buffer->addr), safe_strerror (status));
displaced_debug_printf ("saved %s: %s",
paddress (arch, m_addr),
paddress (arch, buffer->addr),
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
throws. */
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)
{
/* The architecture doesn't know how or want to displaced step
this instruction or instruction sequence. Fallback to
stepping over the breakpoint in-line. */
this instruction or instruction sequence. Fallback to
stepping over the breakpoint in-line. */
return DISPLACED_STEP_PREPARE_STATUS_CANT;
}
/* 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. */
m_current_thread = thread;
buffer->current_thread = thread;
/* 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;
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;
}
@ -152,21 +191,34 @@ displaced_step_instruction_executed_successfully (gdbarch *arch,
}
displaced_step_finish_status
displaced_step_buffer::finish (gdbarch *arch, thread_info *thread,
gdb_signal sig)
displaced_step_buffers::finish (gdbarch *arch, thread_info *thread,
gdb_signal sig)
{
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
wrong. */
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);
/* Reset M_CURRENT_THREAD immediately to mark the buffer as available, in case
something goes wrong below. */
m_current_thread = nullptr;
/* Reset BUFFER->CURRENT_THREAD immediately to mark the buffer as available,
in case something goes wrong below. */
buffer->current_thread = nullptr;
/* 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
@ -175,12 +227,13 @@ displaced_step_buffer::finish (gdbarch *arch, thread_info *thread,
ULONGEST len = gdbarch_max_insn_length (arch);
write_memory_ptid (thread->ptid, m_addr,
m_saved_copy.data (), len);
/* Restore memory of the buffer. */
write_memory_ptid (thread->ptid, buffer->addr,
buffer->saved_copy.data (), len);
displaced_debug_printf ("restored %s %s",
target_pid_to_str (thread->ptid).c_str (),
paddress (arch, m_addr));
paddress (arch, buffer->addr));
regcache *rc = get_thread_regcache (thread);
@ -189,8 +242,9 @@ displaced_step_buffer::finish (gdbarch *arch, thread_info *thread,
if (instruction_executed_successfully)
{
gdbarch_displaced_step_fixup (arch, copy_insn_closure.get (), m_original_pc,
m_addr, rc);
gdbarch_displaced_step_fixup (arch, copy_insn_closure.get (),
buffer->original_pc,
buffer->addr, rc);
return DISPLACED_STEP_FINISH_STATUS_OK;
}
else
@ -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
PC. */
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);
return DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED;
}
}
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)
return m_copy_insn_closure.get ();
else
return nullptr;
for (const displaced_step_buffer &buffer : m_buffers)
{
if (addr == buffer.addr)
return buffer.copy_insn_closure.get ();
}
return nullptr;
}
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 ();
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",
target_pid_to_str (ptid).c_str (),
paddress (arch, m_addr));
paddress (arch, buffer.addr));
}
}

View File

@ -20,6 +20,7 @@
#ifndef DISPLACED_STEPPING_H
#define DISPLACED_STEPPING_H
#include "gdbsupport/array-view.h"
#include "gdbsupport/byte-vector.h"
struct gdbarch;
@ -154,13 +155,19 @@ private:
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)
: m_addr (buffer_addr)
{}
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);
@ -174,21 +181,35 @@ struct displaced_step_buffer
void restore_in_ptid (ptid_t ptid);
private:
/* Original PC of the instruction being displaced-stepped in this buffer. */
CORE_ADDR m_original_pc = 0;
/* Address of the buffer. */
const CORE_ADDR m_addr;
/* State of a single buffer. */
/* If set, the thread currently using the buffer. */
thread_info *m_current_thread = nullptr;
struct displaced_step_buffer
{
explicit displaced_step_buffer (CORE_ADDR addr)
: addr (addr)
{}
/* Saved contents of copy area. */
gdb::byte_vector m_saved_copy;
/* Address of the buffer. */
const CORE_ADDR addr;
/* The closure provided gdbarch_displaced_step_copy_insn, to be used
for post-step cleanup. */
displaced_step_copy_insn_closure_up m_copy_insn_closure;
/* 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;
/* Saved copy of the bytes in the displaced buffer, to be restored once the
buffer is no longer used. */
gdb::byte_vector saved_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;
};
std::vector<displaced_step_buffer> m_buffers;
};
#endif /* DISPLACED_STEPPING_H */

View File

@ -456,7 +456,7 @@ frv_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
static void
frv_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. */
frame_unwind_append_unwinder (gdbarch, &frv_linux_sigtramp_frame_unwind);

View File

@ -489,7 +489,7 @@ hppa_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
/* GNU/Linux is always ELF. */
tdep->is_elf = 1;

View File

@ -832,7 +832,7 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
gdb_assert (tdesc_data);
linux_init_abi (info, gdbarch, true);
linux_init_abi (info, gdbarch, 1);
/* GNU/Linux uses ELF. */
i386_elf_init_abi (info, gdbarch);

View File

@ -223,7 +223,7 @@ ia64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
static const char *const stap_register_indirection_suffixes[] = { "]",
NULL };
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
/* Set the method of obtaining the sigcontext addresses at which
registers are saved. */

View File

@ -166,9 +166,10 @@ enum
static struct gdbarch_data *linux_gdbarch_data_handle;
struct linux_gdbarch_data
{
struct type *siginfo_type;
};
{
struct type *siginfo_type;
int num_disp_step_buffers;
};
static void *
init_linux_gdbarch_data (struct obstack *obstack)
@ -200,8 +201,8 @@ struct linux_info
if we tried looking it up but failed. */
int vsyscall_range_p = 0;
/* Inferior's displaced step buffer. */
gdb::optional<displaced_step_buffer> disp_step_buf;
/* Inferior's displaced step buffers. */
gdb::optional<displaced_step_buffers> disp_step_bufs;
};
/* Per-inferior data key. */
@ -2540,15 +2541,25 @@ linux_displaced_step_prepare (gdbarch *arch, thread_info *thread,
{
linux_info *per_inferior = get_linux_inferior_data (thread->inf);
if (!per_inferior->disp_step_buf.has_value ())
if (!per_inferior->disp_step_bufs.has_value ())
{
/* Figure out the location of the buffers. They are contiguous, starting
at DISP_STEP_BUF_ADDR. They are all of size BUF_LEN. */
CORE_ADDR disp_step_buf_addr
= linux_displaced_step_location (thread->inf->gdbarch);
int buf_len = gdbarch_max_insn_length (arch);
per_inferior->disp_step_buf.emplace (disp_step_buf_addr);
linux_gdbarch_data *gdbarch_data = get_linux_gdbarch_data (arch);
gdb_assert (gdbarch_data->num_disp_step_buffers > 0);
std::vector<CORE_ADDR> buffers;
for (int i = 0; i < gdbarch_data->num_disp_step_buffers; i++)
buffers.push_back (disp_step_buf_addr + i * buf_len);
per_inferior->disp_step_bufs.emplace (buffers);
}
return per_inferior->disp_step_buf->prepare (thread, displaced_pc);
return per_inferior->disp_step_bufs->prepare (thread, displaced_pc);
}
/* See linux-tdep.h. */
@ -2558,9 +2569,9 @@ linux_displaced_step_finish (gdbarch *arch, thread_info *thread, gdb_signal sig)
{
linux_info *per_inferior = get_linux_inferior_data (thread->inf);
gdb_assert (per_inferior->disp_step_buf.has_value ());
gdb_assert (per_inferior->disp_step_bufs.has_value ());
return per_inferior->disp_step_buf->finish (arch, thread, sig);
return per_inferior->disp_step_bufs->finish (arch, thread, sig);
}
/* See linux-tdep.h. */
@ -2571,10 +2582,10 @@ linux_displaced_step_copy_insn_closure_by_addr (inferior *inf, CORE_ADDR addr)
linux_info *per_inferior = linux_inferior_data.get (inf);
if (per_inferior == nullptr
|| !per_inferior->disp_step_buf.has_value ())
|| !per_inferior->disp_step_bufs.has_value ())
return nullptr;
return per_inferior->disp_step_buf->copy_insn_closure_by_addr (addr);
return per_inferior->disp_step_bufs->copy_insn_closure_by_addr (addr);
}
/* See linux-tdep.h. */
@ -2585,10 +2596,10 @@ linux_displaced_step_restore_all_in_ptid (inferior *parent_inf, ptid_t ptid)
linux_info *per_inferior = linux_inferior_data.get (parent_inf);
if (per_inferior == nullptr
|| !per_inferior->disp_step_buf.has_value ())
|| !per_inferior->disp_step_bufs.has_value ())
return;
per_inferior->disp_step_buf->restore_in_ptid (ptid);
per_inferior->disp_step_bufs->restore_in_ptid (ptid);
}
/* See linux-tdep.h. */
@ -2636,15 +2647,22 @@ show_dump_excluded_mappings (struct ui_file *file, int from_tty,
}
/* To be called from the various GDB_OSABI_LINUX handlers for the
various GNU/Linux architectures and machine types. */
various GNU/Linux architectures and machine types.
NUM_DISP_STEP_BUFFERS is the number of displaced step buffers to use. If 0,
displaced stepping is not supported. */
void
linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
bool supports_displaced_step)
int num_disp_step_buffers)
{
if (supports_displaced_step)
if (num_disp_step_buffers > 0)
{
set_gdbarch_displaced_step_prepare (gdbarch, linux_displaced_step_prepare);
linux_gdbarch_data *gdbarch_data = get_linux_gdbarch_data (gdbarch);
gdbarch_data->num_disp_step_buffers = num_disp_step_buffers;
set_gdbarch_displaced_step_prepare (gdbarch,
linux_displaced_step_prepare);
set_gdbarch_displaced_step_finish (gdbarch, linux_displaced_step_finish);
set_gdbarch_displaced_step_copy_insn_closure_by_addr
(gdbarch, linux_displaced_step_copy_insn_closure_by_addr);

View File

@ -82,7 +82,7 @@ extern void linux_displaced_step_restore_all_in_ptid (inferior *parent_inf,
ptid_t ptid);
extern void linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
bool supports_displaced_step);
int num_disp_step_buffers);
extern int linux_is_uclinux (void);

View File

@ -449,7 +449,7 @@ static void
m32r_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
/* Since EVB register is not available for native debug, we reduce
the number of registers. */

View File

@ -385,7 +385,7 @@ m68k_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
tdep->jb_pc = M68K_LINUX_JB_PC;
tdep->jb_elt_size = M68K_LINUX_JB_ELEMENT_SIZE;

View File

@ -117,7 +117,7 @@ static void
microblaze_linux_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
{
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
set_gdbarch_memory_remove_breakpoint (gdbarch,
microblaze_linux_memory_remove_breakpoint);

View File

@ -1531,7 +1531,7 @@ mips_linux_init_abi (struct gdbarch_info info,
enum mips_abi abi = mips_abi (gdbarch);
struct tdesc_arch_data *tdesc_data = info.tdesc_data;
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
/* Get the syscall number from the arch's register. */
set_gdbarch_get_syscall_number (gdbarch, mips_linux_get_syscall_number);

View File

@ -704,7 +704,7 @@ am33_linux_sigframe_cache_init (const struct tramp_frame *self,
static void
am33_linux_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
set_gdbarch_iterate_over_regset_sections
(gdbarch, am33_iterate_over_regset_sections);

View File

@ -219,7 +219,7 @@ nios2_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
/* Shared library handling. */
set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);

View File

@ -140,7 +140,7 @@ or1k_linux_sigframe_init (const struct tramp_frame *self,
static void
or1k_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
set_solib_svr4_fetch_link_map_offsets (gdbarch,
svr4_ilp32_fetch_link_map_offsets);

View File

@ -1993,7 +1993,7 @@ ppc_linux_init_abi (struct gdbarch_info info,
static const char *const stap_register_indirection_suffixes[] = { ")",
NULL };
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
/* PPC GNU/Linux uses either 64-bit or 128-bit long doubles; where
128-bit, they can be either IBM long double or IEEE quad long double.

View File

@ -159,7 +159,7 @@ riscv_linux_sigframe_init (const struct tramp_frame *self,
static void
riscv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
set_gdbarch_software_single_step (gdbarch, riscv_software_single_step);

View File

@ -160,7 +160,7 @@ struct ppc_inferior_data
/* This is an optional in case we add more fields to ppc_inferior_data, we
don't want it instantiated as soon as we get the ppc_inferior_data for an
inferior. */
gdb::optional<displaced_step_buffer> disp_step_buf;
gdb::optional<displaced_step_buffers> disp_step_buf;
};
static inferior_key<ppc_inferior_data> ppc_inferior_data_key;

View File

@ -1119,7 +1119,7 @@ s390_linux_init_abi_any (struct gdbarch_info info, struct gdbarch *gdbarch)
tdep->s390_syscall_record = s390_linux_syscall_record;
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
/* Register handling. */
set_gdbarch_core_read_description (gdbarch, s390_core_read_description);

View File

@ -184,7 +184,7 @@ static struct tramp_frame sh_linux_rt_sigreturn_tramp_frame = {
static void
sh_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
/* GNU/Linux uses SVR4-style shared libraries. */
set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);

View File

@ -422,7 +422,7 @@ sparc32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
tdep->gregset = &sparc32_linux_gregset;
tdep->sizeof_gregset = 152;

View File

@ -365,7 +365,7 @@ sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
tdep->gregset = &sparc64_linux_gregset;
tdep->sizeof_gregset = 288;

View File

@ -167,7 +167,7 @@ tic6x_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
/* Shared library handling. */
set_solib_ops (gdbarch, &dsbt_so_ops);

View File

@ -111,7 +111,7 @@ tilegx_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
int arch_size = gdbarch_addr_bit (gdbarch);
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
tramp_frame_prepend_unwinder (gdbarch, &tilegx_linux_rt_sigframe);

View File

@ -110,7 +110,7 @@ xtensa_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_num_pseudo_regs (gdbarch, tdep->num_pseudo_regs);
}
linux_init_abi (info, gdbarch, false);
linux_init_abi (info, gdbarch, 0);
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_ilp32_fetch_link_map_offsets);