From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id QCZ+EW8Kq18oGQAAWB0awg (envelope-from ) for ; Tue, 10 Nov 2020 16:47:27 -0500 Received: by simark.ca (Postfix, from userid 112) id D26251F08B; Tue, 10 Nov 2020 16:47:26 -0500 (EST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on simark.ca X-Spam-Level: X-Spam-Status: No, score=0.2 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,MAILING_LIST_MULTI,RDNS_NONE,URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2 Received: from sourceware.org (unknown [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 0F5EA1E58E for ; Tue, 10 Nov 2020 16:47:25 -0500 (EST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BF99A398742D; Tue, 10 Nov 2020 21:47:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BF99A398742D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1605044844; bh=ud45c23dA0uvKuqvuZMOiQr7Moa7jBWCkm5xKaQqsUQ=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=KEI7yejZzKb+Ln66qLqBsOhojcRKZ9PxoNKB7VTA+WF03mgYZ1515PPrvQ5gYAi7q U00EzWZ9wXThlgmPPRlrdARmbCoaPEHrQRpzRij9XBjyV3FI4vWoHpUK2p3rf3iNTr M4kATNNwCfFJCXRIiiAvh2raqHHykijuLLHJaHxo= Received: from barracuda.ebox.ca (barracuda.ebox.ca [96.127.255.19]) by sourceware.org (Postfix) with ESMTPS id 6D560398742D for ; Tue, 10 Nov 2020 21:47:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 6D560398742D X-ASG-Debug-ID: 1605044838-0c856e6cd6716f0001-fS2M51 Received: from smtp.ebox.ca (smtp.ebox.ca [96.127.255.82]) by barracuda.ebox.ca with ESMTP id tMAW4HMsbqHWmDXJ (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 10 Nov 2020 16:47:18 -0500 (EST) X-Barracuda-Envelope-From: simon.marchi@efficios.com X-Barracuda-RBL-Trusted-Forwarder: 96.127.255.82 Received: from epycamd.internal.efficios.com (192-222-181-218.qc.cable.ebox.net [192.222.181.218]) by smtp.ebox.ca (Postfix) with ESMTP id F3861441D64; Tue, 10 Nov 2020 16:47:17 -0500 (EST) X-Barracuda-RBL-IP: 192.222.181.218 X-Barracuda-Effective-Source-IP: 192-222-181-218.qc.cable.ebox.net[192.222.181.218] X-Barracuda-Apparent-Source-IP: 192.222.181.218 To: gdb-patches@sourceware.org Subject: [PATCH 11/12] gdb: make displaced stepping implementation capable of managing multiple buffers Date: Tue, 10 Nov 2020 16:46:13 -0500 X-ASG-Orig-Subj: [PATCH 11/12] gdb: make displaced stepping implementation capable of managing multiple buffers Message-Id: <20201110214614.2842615-12-simon.marchi@efficios.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201110214614.2842615-1-simon.marchi@efficios.com> References: <20201110214614.2842615-1-simon.marchi@efficios.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Barracuda-Connect: smtp.ebox.ca[96.127.255.82] X-Barracuda-Start-Time: 1605044838 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://96.127.255.19:443/cgi-mod/mark.cgi X-Barracuda-BRTS-Status: 1 X-Virus-Scanned: by bsmtpd at ebox.ca X-Barracuda-Scan-Msg-Size: 38111 X-Barracuda-Spam-Score: 0.50 X-Barracuda-Spam-Status: No, SCORE=0.50 using global scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=8.0 tests=BSF_RULE7568M X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.85785 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- 0.50 BSF_RULE7568M Custom Rule 7568M X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Simon Marchi via Gdb-patches Reply-To: Simon Marchi Cc: Simon Marchi Errors-To: gdb-patches-bounces@sourceware.org Sender: "Gdb-patches" 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. : Remove. : New inner class. : 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) : New field. (struct linux_info) : Rename to... : ... 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) : 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 --- gdb/aarch64-linux-tdep.c | 2 +- gdb/alpha-linux-tdep.c | 2 +- gdb/amd64-linux-tdep.c | 8 +- gdb/arc-linux-tdep.c | 2 +- gdb/arm-linux-tdep.c | 2 +- gdb/bfin-linux-tdep.c | 2 +- gdb/cris-linux-tdep.c | 2 +- gdb/csky-linux-tdep.c | 2 +- gdb/displaced-stepping.c | 171 +++++++++++++++++++++++------------- gdb/displaced-stepping.h | 46 +++++++--- gdb/frv-linux-tdep.c | 2 +- gdb/hppa-linux-tdep.c | 2 +- gdb/i386-linux-tdep.c | 2 +- gdb/ia64-linux-tdep.c | 2 +- gdb/linux-tdep.c | 54 ++++++++---- gdb/linux-tdep.h | 2 +- gdb/m32r-linux-tdep.c | 2 +- gdb/m68k-linux-tdep.c | 2 +- gdb/microblaze-linux-tdep.c | 2 +- gdb/mips-linux-tdep.c | 2 +- gdb/mn10300-linux-tdep.c | 2 +- gdb/nios2-linux-tdep.c | 2 +- gdb/or1k-linux-tdep.c | 2 +- gdb/ppc-linux-tdep.c | 2 +- gdb/riscv-linux-tdep.c | 2 +- gdb/rs6000-tdep.c | 2 +- gdb/s390-linux-tdep.c | 2 +- gdb/sh-linux-tdep.c | 2 +- gdb/sparc-linux-tdep.c | 2 +- gdb/sparc64-linux-tdep.c | 2 +- gdb/tic6x-linux-tdep.c | 2 +- gdb/tilegx-linux-tdep.c | 2 +- gdb/xtensa-linux-tdep.c | 2 +- 33 files changed, 214 insertions(+), 123 deletions(-) diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index 4fe7babe59c..ce697ff246e 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -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); diff --git a/gdb/alpha-linux-tdep.c b/gdb/alpha-linux-tdep.c index a6d6b15e9fd..520dd980d88 100644 --- a/gdb/alpha-linux-tdep.c +++ b/gdb/alpha-linux-tdep.c @@ -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); diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index a81bb9039df..60707ed7aaf 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -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 diff --git a/gdb/arc-linux-tdep.c b/gdb/arc-linux-tdep.c index 71dcdcc1811..5ad66bd5eec 100644 --- a/gdb/arc-linux-tdep.c +++ b/gdb/arc-linux-tdep.c @@ -434,7 +434,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); diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c index d164cff3dff..11e71e56b46 100644 --- a/gdb/arm-linux-tdep.c +++ b/gdb/arm-linux-tdep.c @@ -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) diff --git a/gdb/bfin-linux-tdep.c b/gdb/bfin-linux-tdep.c index fc2f1d9ac65..bc2bb1aad45 100644 --- a/gdb/bfin-linux-tdep.c +++ b/gdb/bfin-linux-tdep.c @@ -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); diff --git a/gdb/cris-linux-tdep.c b/gdb/cris-linux-tdep.c index 85cbf4cc093..4ae1cdd1390 100644 --- a/gdb/cris-linux-tdep.c +++ b/gdb/cris-linux-tdep.c @@ -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. */ diff --git a/gdb/csky-linux-tdep.c b/gdb/csky-linux-tdep.c index 184fa5ffb23..a0d32b5f2d0 100644 --- a/gdb/csky-linux-tdep.c +++ b/gdb/csky-linux-tdep.c @@ -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); diff --git a/gdb/displaced-stepping.c b/gdb/displaced-stepping.c index f92eb52293f..1d7c6d8ae4d 100644 --- a/gdb/displaced-stepping.c +++ b/gdb/displaced-stepping.c @@ -44,86 +44,114 @@ 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_ERROR; - return DISPLACED_STEP_PREPARE_STATUS_ERROR; + 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 ()); - m_copy_insn_closure = gdbarch_displaced_step_copy_insn (arch, - m_original_pc, - m_addr, - regcache); - if (m_copy_insn_closure == nullptr) + buffer->copy_insn_closure + = gdbarch_displaced_step_copy_insn (arch, buffer->original_pc, + buffer->addr, regcache); + if (buffer->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_ERROR; } try { /* Resume execution at the copy. */ - regcache_write_pc (regcache, m_addr); + regcache_write_pc (regcache, 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 (); + stepping resources and the thread's displaced stepping state. */ + buffer->copy_insn_closure.reset (); return DISPLACED_STEP_PREPARE_STATUS_ERROR; } /* This marks the buffer as being in use. */ - m_current_thread = thread; + buffer->current_thread = thread; return DISPLACED_STEP_PREPARE_STATUS_OK; } @@ -156,20 +184,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 (thread == candidate.current_thread) + { + buffer = &candidate; + break; + } + } + + gdb_assert (buffer != nullptr); 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); @@ -179,8 +221,9 @@ displaced_step_buffer::finish (gdbarch *arch, thread_info *thread, if (instruction_executed_successfully) { - gdbarch_displaced_step_fixup (arch, m_copy_insn_closure.get (), m_original_pc, - m_addr, rc); + gdbarch_displaced_step_fixup (arch, buffer->copy_insn_closure.get (), + buffer->original_pc, + buffer->addr, rc); status = DISPLACED_STEP_FINISH_STATUS_OK; } else @@ -188,40 +231,46 @@ 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); status = DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED; } - m_copy_insn_closure.reset (); - m_current_thread = nullptr; + buffer->copy_insn_closure.reset (); + buffer->current_thread = nullptr; return status; } 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)); } } diff --git a/gdb/displaced-stepping.h b/gdb/displaced-stepping.h index 6c1da46777c..ce9abcd2307 100644 --- a/gdb/displaced-stepping.h +++ b/gdb/displaced-stepping.h @@ -20,6 +20,7 @@ #ifndef DISPLACED_STEPPING_H #define DISPLACED_STEPPING_H +#include "gdbsupport/array-view.h" #include "gdbsupport/byte-vector.h" struct gdbarch; @@ -142,13 +143,17 @@ struct displaced_step_thread_state 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 { - displaced_step_buffer (CORE_ADDR buffer_addr) - : m_addr (buffer_addr) - {} + displaced_step_buffers (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, CORE_ADDR &displaced_pc); @@ -163,14 +168,33 @@ struct displaced_step_buffer private: - CORE_ADDR m_original_pc = 0; - const CORE_ADDR m_addr; + /* State of a single buffer. */ + + struct displaced_step_buffer + { + displaced_step_buffer (CORE_ADDR addr) + : addr (addr) + {} + + const CORE_ADDR addr; + + /* The original PC of the instruction currently begin 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; - /* If set, the thread currently using the buffer. */ - thread_info *m_current_thread = nullptr; + /* 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; + }; - gdb::byte_vector m_saved_copy; - displaced_step_copy_insn_closure_up m_copy_insn_closure; + std::vector m_buffers; }; #endif /* DISPLACED_STEPPING_H */ diff --git a/gdb/frv-linux-tdep.c b/gdb/frv-linux-tdep.c index c5ae4212ab4..c5b20737654 100644 --- a/gdb/frv-linux-tdep.c +++ b/gdb/frv-linux-tdep.c @@ -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); diff --git a/gdb/hppa-linux-tdep.c b/gdb/hppa-linux-tdep.c index a171e582e59..ce85f327d1e 100644 --- a/gdb/hppa-linux-tdep.c +++ b/gdb/hppa-linux-tdep.c @@ -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; diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c index 1b209fd3eff..90ee30969aa 100644 --- a/gdb/i386-linux-tdep.c +++ b/gdb/i386-linux-tdep.c @@ -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); diff --git a/gdb/ia64-linux-tdep.c b/gdb/ia64-linux-tdep.c index d6d581ab3dd..3a69f758c11 100644 --- a/gdb/ia64-linux-tdep.c +++ b/gdb/ia64-linux-tdep.c @@ -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. */ diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index 767cca4afd0..a3af21790ff 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -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 disp_step_buf; + /* Inferior's displaced step buffers. */ + gdb::optional disp_step_bufs; }; /* Per-inferior data key. */ @@ -2541,15 +2542,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 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); } /* Implementation gdbarch_displaced_step_finish. */ @@ -2559,9 +2570,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); } const displaced_step_copy_insn_closure * @@ -2570,10 +2581,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); } void @@ -2582,10 +2593,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. */ @@ -2633,15 +2644,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); diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h index 0f83dc3c781..723eec3dc10 100644 --- a/gdb/linux-tdep.h +++ b/gdb/linux-tdep.h @@ -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); diff --git a/gdb/m32r-linux-tdep.c b/gdb/m32r-linux-tdep.c index 961d54a2ca2..0a1ff780d8c 100644 --- a/gdb/m32r-linux-tdep.c +++ b/gdb/m32r-linux-tdep.c @@ -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. */ diff --git a/gdb/m68k-linux-tdep.c b/gdb/m68k-linux-tdep.c index 509333558ec..f057915965f 100644 --- a/gdb/m68k-linux-tdep.c +++ b/gdb/m68k-linux-tdep.c @@ -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; diff --git a/gdb/microblaze-linux-tdep.c b/gdb/microblaze-linux-tdep.c index 2a91e1bb39a..54f89ec0377 100644 --- a/gdb/microblaze-linux-tdep.c +++ b/gdb/microblaze-linux-tdep.c @@ -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); diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c index 9ca59e5b296..ed95c220084 100644 --- a/gdb/mips-linux-tdep.c +++ b/gdb/mips-linux-tdep.c @@ -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); diff --git a/gdb/mn10300-linux-tdep.c b/gdb/mn10300-linux-tdep.c index 27645b1260c..f7586bf3eae 100644 --- a/gdb/mn10300-linux-tdep.c +++ b/gdb/mn10300-linux-tdep.c @@ -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); diff --git a/gdb/nios2-linux-tdep.c b/gdb/nios2-linux-tdep.c index b5c12852c70..0a28c9cca6d 100644 --- a/gdb/nios2-linux-tdep.c +++ b/gdb/nios2-linux-tdep.c @@ -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); diff --git a/gdb/or1k-linux-tdep.c b/gdb/or1k-linux-tdep.c index 33ddd10e85f..2779fd0d1e6 100644 --- a/gdb/or1k-linux-tdep.c +++ b/gdb/or1k-linux-tdep.c @@ -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); diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c index e6c10dd83db..57bdd2d7a72 100644 --- a/gdb/ppc-linux-tdep.c +++ b/gdb/ppc-linux-tdep.c @@ -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. diff --git a/gdb/riscv-linux-tdep.c b/gdb/riscv-linux-tdep.c index a2238ad786e..623c7d9382c 100644 --- a/gdb/riscv-linux-tdep.c +++ b/gdb/riscv-linux-tdep.c @@ -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); diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index 1a7c7fcb9f1..235abd873f7 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -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 disp_step_buf; + gdb::optional disp_step_buf; }; static inferior_key ppc_inferior_data_key; diff --git a/gdb/s390-linux-tdep.c b/gdb/s390-linux-tdep.c index 14e92d2c6f3..8588d046bd6 100644 --- a/gdb/s390-linux-tdep.c +++ b/gdb/s390-linux-tdep.c @@ -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); diff --git a/gdb/sh-linux-tdep.c b/gdb/sh-linux-tdep.c index b7c66b70294..84bcd300069 100644 --- a/gdb/sh-linux-tdep.c +++ b/gdb/sh-linux-tdep.c @@ -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); diff --git a/gdb/sparc-linux-tdep.c b/gdb/sparc-linux-tdep.c index 3dbc65ca24d..71759e19fa8 100644 --- a/gdb/sparc-linux-tdep.c +++ b/gdb/sparc-linux-tdep.c @@ -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; diff --git a/gdb/sparc64-linux-tdep.c b/gdb/sparc64-linux-tdep.c index 10a6eb52778..fe1b276bc4e 100644 --- a/gdb/sparc64-linux-tdep.c +++ b/gdb/sparc64-linux-tdep.c @@ -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; diff --git a/gdb/tic6x-linux-tdep.c b/gdb/tic6x-linux-tdep.c index 5a8d7c7f825..7820e2da5a0 100644 --- a/gdb/tic6x-linux-tdep.c +++ b/gdb/tic6x-linux-tdep.c @@ -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); diff --git a/gdb/tilegx-linux-tdep.c b/gdb/tilegx-linux-tdep.c index 14cfafe33de..37c0790a190 100644 --- a/gdb/tilegx-linux-tdep.c +++ b/gdb/tilegx-linux-tdep.c @@ -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); diff --git a/gdb/xtensa-linux-tdep.c b/gdb/xtensa-linux-tdep.c index c2aeb8e9397..fccac7d49fc 100644 --- a/gdb/xtensa-linux-tdep.c +++ b/gdb/xtensa-linux-tdep.c @@ -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); -- 2.28.0