From: Simon Marchi Date: Wed, 11 Mar 2020 22:13:44 +0000 (-0400) Subject: gdb: change single_displaced_buffer_manager into multiple_displaced_buffer_manager X-Git-Url: http://git.efficios.com/?p=deliverable%2Fbinutils-gdb.git;a=commitdiff_plain;h=e10250a6e063232a344fc33152b7a328467047ef gdb: change single_displaced_buffer_manager into multiple_displaced_buffer_manager single_displaced_buffer_manager, introduced in a previous patch, is responsible for managing the access to a single displaced step buffer. We'll want to be able to use more than one, so change it to multiple_displaced_buffer_manager, which receives a collection of buffer addresses at construction, instead of a single buffer address. The callers keep passing a single buffer, however, so there is not expected behavior change. --- diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index 65cdcb6308..58532fdf26 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -20,6 +20,7 @@ #include "defs.h" #include "arch-utils.h" +#include "displaced-stepping.h" #include "frame.h" #include "gdbarch.h" #include "gdbcore.h" @@ -1798,11 +1799,11 @@ amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch, struct amd64_linux_per_inferior { - amd64_linux_per_inferior (CORE_ADDR disp_step_buffer_addr) - : disp_step_buf_mgr (disp_step_buffer_addr) + amd64_linux_per_inferior (gdb::array_view disp_step_buffer_addrs) + : disp_step_buf_mgr (disp_step_buffer_addrs) {} - single_displaced_buffer_manager disp_step_buf_mgr; + multiple_displaced_buffer_manager disp_step_buf_mgr; }; static const inferior_key diff --git a/gdb/displaced-stepping.c b/gdb/displaced-stepping.c index cbf2425e37..f373be7964 100644 --- a/gdb/displaced-stepping.c +++ b/gdb/displaced-stepping.c @@ -11,43 +11,59 @@ displaced_step_copy_insn_closure::~displaced_step_copy_insn_closure() = default; displaced_step_prepare_status -single_displaced_buffer_manager::prepare (thread_info *thread) +multiple_displaced_buffer_manager::prepare (thread_info *thread) { - /* Is a thread currently using the buffer? */ - if (m_current_thread != nullptr) + gdb_assert (!thread->displaced_step_state.in_progress ()); + displaced_step_buffer_state *buffer = nullptr; + + /* Sanity check. */ + for (displaced_step_buffer_state &buf : m_buffers) + gdb_assert (buf.m_current_thread != thread); + + /* Search for an unused buffer. */ + for (displaced_step_buffer_state &candidate : m_buffers) { - /* If so, it better not be this thread. */ - gdb_assert (thread != m_current_thread); - return DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE; + if (candidate.m_current_thread == nullptr) + { + buffer = &candidate; + break; + } } + if (buffer == nullptr) + return DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE; + gdbarch *arch = thread->arch (); + + if (debug_displaced) + fprintf_unfiltered (gdb_stdlog, "displaced: selected buffer at %s\n", + paddress (arch, buffer->m_buffer_addr)); + struct regcache *regcache = thread->regcache (); ULONGEST len = gdbarch_max_insn_length (arch); - m_original_pc = regcache_read_pc (regcache); + buffer->m_original_pc = regcache_read_pc (regcache); /* Save the original contents of the displaced stepping buffer. */ - m_saved_copy.resize (len); + buffer->m_saved_copy.resize (len); - int status = target_read_memory (m_buffer_addr, m_saved_copy.data (), len); + int status = target_read_memory (buffer->m_buffer_addr, buffer->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)); + paddress (arch, buffer->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); + paddress (arch, buffer->m_buffer_addr)); + displaced_step_dump_bytes (gdb_stdlog, buffer->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) + buffer->m_copy_insn_closure + = gdbarch_displaced_step_copy_insn (arch, buffer->m_original_pc, + buffer->m_buffer_addr, regcache); + if (buffer->m_copy_insn_closure == nullptr) { /* The architecture doesn't know how or want to displaced step this instruction or instruction sequence. Fallback to @@ -58,19 +74,19 @@ single_displaced_buffer_manager::prepare (thread_info *thread) try { /* Resume execution at the copy. */ - regcache_write_pc (regcache, m_buffer_addr); + regcache_write_pc (regcache, buffer->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 (); + buffer->m_copy_insn_closure.reset (); return DISPLACED_STEP_PREPARE_STATUS_ERROR; } /* This marks the buffer as being in use. */ - m_current_thread = thread; + buffer->m_current_thread = thread; return DISPLACED_STEP_PREPARE_STATUS_OK; } @@ -103,32 +119,46 @@ displaced_step_instruction_executed_successfully (gdbarch *arch, gdb_signal sign } displaced_step_finish_status -single_displaced_buffer_manager::finish (gdbarch *arch, thread_info *thread, - gdb_signal sig) +multiple_displaced_buffer_manager::finish (gdbarch *arch, thread_info *thread, + gdb_signal sig) { displaced_step_finish_status status; + displaced_step_buffer_state *buffer = nullptr; - gdb_assert (thread == m_current_thread); + gdb_assert (thread->displaced_step_state.in_progress ()); + + /* Find the buffer this thread was using. */ + for (displaced_step_buffer_state &candidate : m_buffers) + { + if (thread == candidate.m_current_thread) + { + buffer = &candidate; + break; + } + } + + gdb_assert (buffer != nullptr); ULONGEST len = gdbarch_max_insn_length (arch); - write_memory_ptid (thread->ptid, m_buffer_addr, - m_saved_copy.data (), len); + /* Restore memory of the buffer. */ + write_memory_ptid (thread->ptid, buffer->m_buffer_addr, + buffer->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)); + paddress (arch, buffer->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); + gdbarch_displaced_step_fixup (arch, buffer->m_copy_insn_closure.get (), + buffer->m_original_pc, + buffer->m_buffer_addr, rc); status = DISPLACED_STEP_FINISH_STATUS_OK; } else @@ -136,13 +166,13 @@ single_displaced_buffer_manager::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_buffer_addr); + pc = buffer->m_original_pc + (pc - buffer->m_buffer_addr); regcache_write_pc (rc, pc); status = DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED; } - m_copy_insn_closure.reset (); - m_current_thread = nullptr; + buffer->m_copy_insn_closure.reset (); + buffer->m_current_thread = nullptr; return status; } diff --git a/gdb/displaced-stepping.h b/gdb/displaced-stepping.h index 835fd92086..7bb02b3bbf 100644 --- a/gdb/displaced-stepping.h +++ b/gdb/displaced-stepping.h @@ -1,6 +1,7 @@ #ifndef DISPLACED_STEPPING_H #define DISPLACED_STEPPING_H +#include "gdbsupport/array-view.h" #include "gdbsupport/byte-vector.h" struct gdbarch; @@ -98,14 +99,43 @@ private: gdbarch *m_original_gdbarch = nullptr; }; +struct displaced_step_buffer_state +{ + displaced_step_buffer_state (CORE_ADDR buffer_addr) + : m_buffer_addr (buffer_addr) + {} + + const CORE_ADDR m_buffer_addr; + + /* When a displaced step operation is using this buffer, this is the original + PC of the instruction currently begin stepped. */ + CORE_ADDR m_original_pc = 0; + + /* If set, the thread currently using the buffer. If unset, the buffer is not + used. */ + thread_info *m_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 m_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 m_copy_insn_closure; +}; + /* Manage access to a single displaced stepping buffer, without any sharing. */ -struct single_displaced_buffer_manager +struct multiple_displaced_buffer_manager { - single_displaced_buffer_manager (CORE_ADDR buffer_addr) - : m_buffer_addr (buffer_addr) - {} + multiple_displaced_buffer_manager (gdb::array_view buffer_addrs) + { + gdb_assert (buffer_addrs.size () > 0); + + for (CORE_ADDR buffer_addr : buffer_addrs) + m_buffers.emplace_back (buffer_addr); + } displaced_step_prepare_status prepare (thread_info *thread); @@ -113,15 +143,7 @@ struct single_displaced_buffer_manager 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; + std::vector m_buffers; };