From patchwork Fri Dec 1 16:27:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Marchi X-Patchwork-Id: 81140 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 87F2F385E45D for ; Fri, 1 Dec 2023 16:28:56 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from simark.ca (simark.ca [158.69.221.121]) by sourceware.org (Postfix) with ESMTPS id 99E92385B53E for ; Fri, 1 Dec 2023 16:27:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 99E92385B53E Authentication-Results: sourceware.org; dmarc=fail (p=none dis=none) header.from=efficios.com Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=efficios.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 99E92385B53E Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=158.69.221.121 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701448082; cv=none; b=fzj3NKjs1JQ21m/AqpwBMZ+nyRE0CoFhvkqblsZkqXlYDkm11n065+bVgY6MQNhNwnc5cYFAxx8izBkboam8o/787cPdDGSAhyCaC7y/YxykK+FAFIzWcSSEsmmtu0oRa1tD+C8s0UcNR6sAeG60gnSD6eidykBDIQEx/A04u8I= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701448082; c=relaxed/simple; bh=uApraNbineIh2OAenFjbkWmZTwYY/nVYudg8YN/y5iw=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=WaIr5BFFlD1dKXM/YuoNOlOhTIcl035R1zGsn4iYjxtxMrklmRm3BSpZKBJdrebQGIggsBAvws+U4j+BsFgfok6ovlH29s4/eQWz5+yXY/iKu1dMcjOiQ8AkqZsKnH+MgzkdrMsoBPRrbSb5qA0tbr/GQhKg8TNOt8kvmo1rPj8= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from smarchi-efficios.internal.efficios.com (192-222-143-198.qc.cable.ebox.net [192.222.143.198]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPSA id C5F111E1A7; Fri, 1 Dec 2023 11:27:54 -0500 (EST) From: Simon Marchi To: gdb-patches@sourceware.org Cc: Luis Machado , John Baldwin , "Aktemur, Tankut Baris" , Simon Marchi , John Baldwin Subject: [PATCH 05/24] gdb: change regcache interface to use array_view Date: Fri, 1 Dec 2023 11:27:18 -0500 Message-ID: <20231201162751.741751-6-simon.marchi@efficios.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20231201162751.741751-1-simon.marchi@efficios.com> References: <20231201162751.741751-1-simon.marchi@efficios.com> MIME-Version: 1.0 X-Spam-Status: No, score=-3496.7 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_SOFTFAIL, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org New in v3: - fix regression in reg_buffer::raw_compare: the old code allows passing an offset equal to the register size, effectively comparing 0 bytes, the code in v2 does not. Add a selftest checking that this behavior works. - rename len to size in some functions New in v2: - remove dummy float parameters Change most of regcache (and base classes) to use array_view when possible, instead of raw pointers. By propagating the use of array_view further, it enables having some runtime checks to make sure the what we read from or write to regcaches has the expected length (such as the one in the `copy(array_view, array_view)` function. It also integrates well when connecting with other APIs already using gdb::array_view. Add some overloads of the methods using raw pointers to avoid having to change all call sites at once (which is both a lot of work and risky). I tried to do this change in small increments, but since many of these functions use each other, it ended up simpler to do it in one shot than having a lot of intermediary / transient changes. This change extends into gdbserver as well, because there is some part of the regcache interface that is shared. Changing the reg_buffer_common interface to use array_view caused some build failures in nat/aarch64-scalable-linux-ptrace.c. That file currently "takes advantage" of the fact that reg_buffer_common::{raw_supply,raw_collect} operates on `void *`, which IMO is dangerous. It uses raw_supply/raw_collect directly on uint64_t's, which I guess is fine because it is expected that native code will have the same endianness as the debugged process. To accomodate that, add some overloads of raw_collect and raw_supply that work on uint64_t. This file also uses raw_collect and raw_supply on `char` pointers. Change it to use `gdb_byte` pointers instead. Add overloads of raw_collect and raw_supply that work on `gdb_byte *` and make an array_view on the fly using the register's size. Those call sites could be converted to use array_view with not much work, in which case these overloads could be removed, but I didn't want to do it in this patch, to avoid starting to dig in arch-specific code. During development, I inadvertently changed reg_buffer::raw_compare's behavior to not accept an offset equal to the register size. This behavior (effectively comparing 0 bytes, returning true) change was caught by the AArch64 SME core tests. Add a selftest to make sure that this raw_compare behavior is preserved in the future. Change-Id: I9005f04114543ddff738949e12d85a31855304c2 Reviewed-By: John Baldwin --- gdb/frame.c | 4 +- gdb/nat/aarch64-scalable-linux-ptrace.c | 20 +- gdb/regcache.c | 493 ++++++++++++++---------- gdb/regcache.h | 110 ++++-- gdbserver/regcache.cc | 49 ++- gdbserver/regcache.h | 4 +- gdbsupport/common-regcache.h | 38 +- gdbsupport/rsp-low.cc | 8 + gdbsupport/rsp-low.h | 2 + 9 files changed, 457 insertions(+), 271 deletions(-) diff --git a/gdb/frame.c b/gdb/frame.c index 2a8a33b072d9..529453efa158 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -1108,9 +1108,9 @@ get_frame_func (frame_info_ptr this_frame) std::unique_ptr frame_save_as_regcache (frame_info_ptr this_frame) { - auto cooked_read = [this_frame] (int regnum, gdb_byte *buf) + auto cooked_read = [this_frame] (int regnum, gdb::array_view buf) { - if (!deprecated_frame_register_read (this_frame, regnum, buf)) + if (!deprecated_frame_register_read (this_frame, regnum, buf.data ())) return REG_UNAVAILABLE; else return REG_VALID; diff --git a/gdb/nat/aarch64-scalable-linux-ptrace.c b/gdb/nat/aarch64-scalable-linux-ptrace.c index dc0e45fa91ee..b8fb317edaca 100644 --- a/gdb/nat/aarch64-scalable-linux-ptrace.c +++ b/gdb/nat/aarch64-scalable-linux-ptrace.c @@ -613,7 +613,7 @@ aarch64_sve_regs_copy_to_reg_buf (int tid, struct reg_buffer_common *reg_buf) { gdb::byte_vector sve_state = aarch64_fetch_sve_regset (tid); - char *base = (char *) sve_state.data (); + gdb_byte *base = sve_state.data (); struct user_sve_header *header = (struct user_sve_header *) sve_state.data (); @@ -684,8 +684,10 @@ aarch64_sve_regs_copy_to_reg_buf (int tid, struct reg_buffer_common *reg_buf) reg_buf->raw_supply (AARCH64_SVE_Z0_REGNUM + i, reg); } - reg_buf->raw_supply (AARCH64_FPSR_REGNUM, &fpsimd->fpsr); - reg_buf->raw_supply (AARCH64_FPCR_REGNUM, &fpsimd->fpcr); + reg_buf->raw_supply (AARCH64_FPSR_REGNUM, + (const gdb_byte *) &fpsimd->fpsr); + reg_buf->raw_supply (AARCH64_FPCR_REGNUM, + (const gdb_byte *) &fpsimd->fpcr); /* Clear the SVE only registers. */ memset (reg, 0, SVE_PT_SVE_ZREG_SIZE (vq)); @@ -720,7 +722,7 @@ aarch64_sve_regs_copy_from_reg_buf (int tid, gdb::byte_vector new_state (SVE_PT_SIZE (32, SVE_PT_REGS_SVE), 0); memcpy (new_state.data (), sve_state.data (), sve_state.size ()); header = (struct user_sve_header *) new_state.data (); - char *base = (char *) new_state.data (); + gdb_byte *base = new_state.data (); /* Sanity check the data in the header. */ if (!sve_vl_valid (header->vl) @@ -805,9 +807,11 @@ aarch64_sve_regs_copy_from_reg_buf (int tid, } if (REG_VALID == reg_buf->get_register_status (AARCH64_FPSR_REGNUM)) - reg_buf->raw_collect (AARCH64_FPSR_REGNUM, &fpsimd->fpsr); + reg_buf->raw_collect (AARCH64_FPSR_REGNUM, + (gdb_byte *) &fpsimd->fpsr); if (REG_VALID == reg_buf->get_register_status (AARCH64_FPCR_REGNUM)) - reg_buf->raw_collect (AARCH64_FPCR_REGNUM, &fpsimd->fpcr); + reg_buf->raw_collect (AARCH64_FPCR_REGNUM, + (gdb_byte *) &fpsimd->fpcr); /* At this point we have collected all the data from the register cache and we are ready to update the FPSIMD register content @@ -894,7 +898,7 @@ aarch64_za_regs_copy_to_reg_buf (int tid, struct reg_buffer_common *reg_buf, /* Sanity check. */ gdb_assert (!za_state.empty ()); - char *base = (char *) za_state.data (); + gdb_byte *base = za_state.data (); struct user_za_header *header = (struct user_za_header *) base; /* If we have ZA state, read it. Otherwise, make the contents of ZA @@ -1027,7 +1031,7 @@ aarch64_za_regs_copy_from_reg_buf (int tid, /* Fetch the current ZA state from the thread. */ gdb::byte_vector za_state = aarch64_fetch_za_regset (tid); - char *base = (char *) za_state.data (); + gdb_byte *base = za_state.data (); struct user_za_header *za_header = (struct user_za_header *) base; uint64_t svq = sve_vq_from_vl (za_header->vl); diff --git a/gdb/regcache.c b/gdb/regcache.c index 7eb54d27b135..19ba353a335c 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -220,10 +220,9 @@ regcache::regcache (inferior *inf_for_target_calls, gdbarch *gdbarch) readonly_detached_regcache::readonly_detached_regcache (regcache &src) : readonly_detached_regcache (src.arch (), - [&src] (int regnum, gdb_byte *buf) - { - return src.cooked_read (regnum, buf); - }) + [&src] (int regnum, + gdb::array_view buf) + { return src.cooked_read (regnum, buf); }) { } @@ -233,19 +232,38 @@ reg_buffer::arch () const return m_descr->gdbarch; } -/* Return a pointer to register REGNUM's buffer cache. */ +/* Helper for reg_buffer::register_buffer. */ -gdb_byte * +template +gdb::array_view reg_buffer::register_buffer (int regnum) const { - return m_registers.get () + m_descr->register_offset[regnum]; + assert_regnum (regnum); + ElemType *start = &m_registers[m_descr->register_offset[regnum]]; + int size = m_descr->sizeof_register[regnum]; + return gdb::array_view (start, size); +} + +/* See regcache.h. */ + +gdb::array_view +reg_buffer::register_buffer (int regnum) const +{ + return register_buffer (regnum); +} + +/* See regcache.h. */ + +gdb::array_view +reg_buffer::register_buffer (int regnum) +{ + return register_buffer (regnum); } void reg_buffer::save (register_read_ftype cooked_read) { struct gdbarch *gdbarch = m_descr->gdbarch; - int regnum; /* It should have pseudo registers. */ gdb_assert (m_has_pseudo); @@ -256,17 +274,17 @@ reg_buffer::save (register_read_ftype cooked_read) save_reggroup) and mark them as valid. The full [0 .. gdbarch_num_regs + gdbarch_num_pseudo_regs) range is checked since some architectures need to save/restore `cooked' registers that live in memory. */ - for (regnum = 0; regnum < m_descr->nr_cooked_registers; regnum++) + for (int regnum = 0; regnum < m_descr->nr_cooked_registers; regnum++) { if (gdbarch_register_reggroup_p (gdbarch, regnum, save_reggroup)) { - gdb_byte *dst_buf = register_buffer (regnum); - enum register_status status = cooked_read (regnum, dst_buf); + gdb::array_view dst_buf = register_buffer (regnum); + register_status status = cooked_read (regnum, dst_buf); gdb_assert (status != REG_UNKNOWN); if (status != REG_VALID) - memset (dst_buf, 0, register_size (gdbarch, regnum)); + memset (dst_buf.data (), 0, dst_buf.size ()); m_register_status[regnum] = status; } @@ -592,21 +610,30 @@ regcache::raw_update (int regnum) } } -enum register_status -readable_regcache::raw_read (int regnum, gdb_byte *buf) +register_status +readable_regcache::raw_read (int regnum, gdb::array_view dst) { - gdb_assert (buf != NULL); + assert_regnum (regnum); + gdb_assert (dst.size () == m_descr->sizeof_register[regnum]); + raw_update (regnum); if (m_register_status[regnum] != REG_VALID) - memset (buf, 0, m_descr->sizeof_register[regnum]); + memset (dst.data (), 0, dst.size ()); else - memcpy (buf, register_buffer (regnum), - m_descr->sizeof_register[regnum]); + copy (register_buffer (regnum), dst); return m_register_status[regnum]; } +register_status +readable_regcache::raw_read (int regnum, gdb_byte *dst) +{ + assert_regnum (regnum); + int size = m_descr->sizeof_register[regnum]; + return raw_read (regnum, gdb::make_array_view (dst, size)); +} + enum register_status regcache_raw_read_signed (struct regcache *regcache, int regnum, LONGEST *val) { @@ -619,14 +646,16 @@ enum register_status readable_regcache::raw_read (int regnum, T *val) { assert_regnum (regnum); - size_t len = m_descr->sizeof_register[regnum]; - gdb_byte *buf = (gdb_byte *) alloca (len); - register_status status = raw_read (regnum, buf); + size_t size = m_descr->sizeof_register[regnum]; + gdb_byte *buf = (gdb_byte *) alloca (size); + auto view = gdb::make_array_view (buf, size); + register_status status = raw_read (regnum, view); + if (status == REG_VALID) - *val = extract_integer ({buf, len}, - gdbarch_byte_order (m_descr->gdbarch)); + *val = extract_integer (view, gdbarch_byte_order (m_descr->gdbarch)); else *val = 0; + return status; } @@ -650,13 +679,13 @@ template void regcache::raw_write (int regnum, T val) { - gdb_byte *buf; - assert_regnum (regnum); - buf = (gdb_byte *) alloca (m_descr->sizeof_register[regnum]); - store_integer (buf, m_descr->sizeof_register[regnum], - gdbarch_byte_order (m_descr->gdbarch), val); - raw_write (regnum, buf); + + int size = m_descr->sizeof_register[regnum]; + gdb_byte *buf = (gdb_byte *) alloca (size); + auto view = gdb::make_array_view (buf, size); + store_integer (view, gdbarch_byte_order (m_descr->gdbarch), val); + raw_write (regnum, view); } void @@ -680,47 +709,60 @@ regcache_raw_get_signed (struct regcache *regcache, int regnum) return value; } -enum register_status -readable_regcache::cooked_read (int regnum, gdb_byte *buf) +/* See regcache.h. */ + +register_status +readable_regcache::cooked_read (int regnum, gdb::array_view dst) { gdb_assert (regnum >= 0); gdb_assert (regnum < m_descr->nr_cooked_registers); + if (regnum < num_raw_registers ()) - return raw_read (regnum, buf); - else if (m_has_pseudo - && m_register_status[regnum] != REG_UNKNOWN) + return raw_read (regnum, dst); + + gdb_assert (dst.size () == m_descr->sizeof_register[regnum]); + + if (m_has_pseudo && m_register_status[regnum] != REG_UNKNOWN) { if (m_register_status[regnum] == REG_VALID) - memcpy (buf, register_buffer (regnum), - m_descr->sizeof_register[regnum]); + copy (register_buffer (regnum), dst); else - memset (buf, 0, m_descr->sizeof_register[regnum]); + memset (dst.data (), 0, dst.size ()); return m_register_status[regnum]; } else if (gdbarch_pseudo_register_read_value_p (m_descr->gdbarch)) { - struct value *computed; - enum register_status result = REG_VALID; - + register_status result = REG_VALID; scoped_value_mark mark; + value *computed + = gdbarch_pseudo_register_read_value (m_descr->gdbarch, this, regnum); - computed = gdbarch_pseudo_register_read_value (m_descr->gdbarch, - this, regnum); if (computed->entirely_available ()) - memcpy (buf, computed->contents_raw ().data (), - m_descr->sizeof_register[regnum]); + copy (computed->contents_raw (), dst); else { - memset (buf, 0, m_descr->sizeof_register[regnum]); + memset (dst.data (), 0, dst.size ()); result = REG_UNAVAILABLE; } return result; } else - return gdbarch_pseudo_register_read (m_descr->gdbarch, this, - regnum, buf); + return gdbarch_pseudo_register_read (m_descr->gdbarch, this, regnum, + dst.data ()); +} + +/* See regcache.h. */ + +register_status +readable_regcache::cooked_read (int regnum, gdb_byte *dst) +{ + gdb_assert (regnum >= 0); + gdb_assert (regnum < m_descr->nr_cooked_registers); + + int size = m_descr->sizeof_register[regnum]; + return cooked_read (regnum, gdb::make_array_view (dst, size)); } struct value * @@ -742,8 +784,7 @@ readable_regcache::cooked_read_value (int regnum) /* It is more efficient in general to do this delegation in this direction than in the other one, even though the value-based API is preferred. */ - if (cooked_read (regnum, - result->contents_raw ().data ()) == REG_UNAVAILABLE) + if (cooked_read (regnum, result->contents_raw ()) == REG_UNAVAILABLE) result->mark_bytes_unavailable (0, result->type ()->length ()); @@ -767,12 +808,12 @@ enum register_status readable_regcache::cooked_read (int regnum, T *val) { gdb_assert (regnum >= 0 && regnum < m_descr->nr_cooked_registers); - size_t len = m_descr->sizeof_register[regnum]; - gdb_byte *buf = (gdb_byte *) alloca (len); - register_status status = cooked_read (regnum, buf); + size_t size = m_descr->sizeof_register[regnum]; + gdb_byte *buf = (gdb_byte *) alloca (size); + auto view = gdb::make_array_view (buf, size); + register_status status = cooked_read (regnum, view); if (status == REG_VALID) - *val = extract_integer ({buf, len}, - gdbarch_byte_order (m_descr->gdbarch)); + *val = extract_integer (view, gdbarch_byte_order (m_descr->gdbarch)); else *val = 0; return status; @@ -798,13 +839,14 @@ template void regcache::cooked_write (int regnum, T val) { - gdb_byte *buf; + gdb_assert (regnum >= 0); + gdb_assert (regnum < m_descr->nr_cooked_registers); - gdb_assert (regnum >=0 && regnum < m_descr->nr_cooked_registers); - buf = (gdb_byte *) alloca (m_descr->sizeof_register[regnum]); - store_integer (buf, m_descr->sizeof_register[regnum], - gdbarch_byte_order (m_descr->gdbarch), val); - cooked_write (regnum, buf); + int size = m_descr->sizeof_register[regnum]; + gdb_byte *buf = (gdb_byte *) alloca (size); + auto view = gdb::make_array_view (buf, size); + store_integer (view, gdbarch_byte_order (m_descr->gdbarch), val); + cooked_write (regnum, view); } void @@ -816,11 +858,10 @@ regcache_cooked_write_unsigned (struct regcache *regcache, int regnum, } void -regcache::raw_write (int regnum, const gdb_byte *buf) +regcache::raw_write (int regnum, gdb::array_view src) { - - gdb_assert (buf != NULL); assert_regnum (regnum); + gdb_assert (src.size () == m_descr->sizeof_register[regnum]); /* On the sparc, writing %g0 is a no-op, so we don't even want to change the registers array if something writes to this register. */ @@ -830,15 +871,15 @@ regcache::raw_write (int regnum, const gdb_byte *buf) /* If we have a valid copy of the register, and new value == old value, then don't bother doing the actual store. */ if (get_register_status (regnum) == REG_VALID - && (memcmp (register_buffer (regnum), buf, - m_descr->sizeof_register[regnum]) == 0)) + && (memcmp (register_buffer (regnum).data (), src.data (), src.size ()) + == 0)) return; std::optional maybe_restore_thread = maybe_switch_inferior (m_inf_for_target_calls); target_prepare_to_store (this); - raw_supply (regnum, buf); + raw_supply (regnum, src); /* Invalidate the register after it is written, in case of a failure. */ @@ -853,211 +894,248 @@ regcache::raw_write (int regnum, const gdb_byte *buf) } void -regcache::cooked_write (int regnum, const gdb_byte *buf) +regcache::raw_write (int regnum, const gdb_byte *src) +{ + assert_regnum (regnum); + + int size = m_descr->sizeof_register[regnum]; + raw_write (regnum, gdb::make_array_view (src, size)); +} + +/* See regcache.h. */ + +void +regcache::cooked_write (int regnum, gdb::array_view src) { gdb_assert (regnum >= 0); gdb_assert (regnum < m_descr->nr_cooked_registers); + if (regnum < num_raw_registers ()) - raw_write (regnum, buf); + raw_write (regnum, src); else - gdbarch_pseudo_register_write (m_descr->gdbarch, this, - regnum, buf); + gdbarch_pseudo_register_write (m_descr->gdbarch, this, regnum, + src.data ()); } /* See regcache.h. */ -enum register_status -readable_regcache::read_part (int regnum, int offset, int len, - gdb_byte *out, bool is_raw) +void +regcache::cooked_write (int regnum, const gdb_byte *src) +{ + gdb_assert (regnum >= 0); + gdb_assert (regnum < m_descr->nr_cooked_registers); + + int size = m_descr->sizeof_register[regnum]; + return cooked_write (regnum, gdb::make_array_view (src, size)); +} + +/* See regcache.h. */ + +register_status +readable_regcache::read_part (int regnum, int offset, + gdb::array_view dst, bool is_raw) { int reg_size = register_size (arch (), regnum); - gdb_assert (out != NULL); gdb_assert (offset >= 0); - gdb_assert (len >= 0 && offset + len <= reg_size); + gdb_assert (offset + dst.size () <= reg_size); - if (len == 0) + if (dst.size () == 0) { /* Nothing to do. */ return REG_VALID; } - if (len == reg_size) + if (dst.size () == reg_size) { /* Read the full register. */ - return (is_raw) ? raw_read (regnum, out) : cooked_read (regnum, out); + if (is_raw) + return raw_read (regnum, dst); + else + return cooked_read (regnum, dst); } - enum register_status status; - gdb_byte *reg = (gdb_byte *) alloca (reg_size); - /* Read full register to buffer. */ - status = (is_raw) ? raw_read (regnum, reg) : cooked_read (regnum, reg); + register_status status; + gdb_byte *reg_buf = (gdb_byte *) alloca (reg_size); + auto reg = gdb::make_array_view (reg_buf, reg_size); + + if (is_raw) + status = raw_read (regnum, reg); + else + status = cooked_read (regnum, reg); + if (status != REG_VALID) return status; /* Copy out. */ - memcpy (out, reg + offset, len); + copy (reg.slice (offset, dst.size ()), dst); return REG_VALID; } /* See regcache.h. */ void -reg_buffer::raw_collect_part (int regnum, int offset, int len, - gdb_byte *out) const +reg_buffer::raw_collect_part (int regnum, int offset, + gdb::array_view dst) const { int reg_size = register_size (arch (), regnum); - gdb_assert (out != nullptr); gdb_assert (offset >= 0); - gdb_assert (len >= 0 && offset + len <= reg_size); + gdb_assert (offset + dst.size () <= reg_size); - if (len == 0) + if (dst.size () == 0) { /* Nothing to do. */ return; } - if (len == reg_size) + if (dst.size () == reg_size) { /* Collect the full register. */ - return raw_collect (regnum, out); + return raw_collect (regnum, dst); } /* Read to buffer, then write out. */ - gdb_byte *reg = (gdb_byte *) alloca (reg_size); + gdb_byte *reg_buf = (gdb_byte *) alloca (reg_size); + auto reg = gdb::make_array_view (reg_buf, reg_size); raw_collect (regnum, reg); - memcpy (out, reg + offset, len); + copy (reg.slice (offset, dst.size ()), dst); } /* See regcache.h. */ -enum register_status -regcache::write_part (int regnum, int offset, int len, - const gdb_byte *in, bool is_raw) +register_status +regcache::write_part (int regnum, int offset, + gdb::array_view src, bool is_raw) { int reg_size = register_size (arch (), regnum); - gdb_assert (in != NULL); gdb_assert (offset >= 0); - gdb_assert (len >= 0 && offset + len <= reg_size); + gdb_assert (offset + src.size () <= reg_size); - if (len == 0) + if (src.size () == 0) { /* Nothing to do. */ return REG_VALID; } - if (len == reg_size) + if (src.size () == reg_size) { /* Write the full register. */ - (is_raw) ? raw_write (regnum, in) : cooked_write (regnum, in); + if (is_raw) + raw_write (regnum, src); + else + cooked_write (regnum, src); + return REG_VALID; } - enum register_status status; - gdb_byte *reg = (gdb_byte *) alloca (reg_size); - /* Read existing register to buffer. */ - status = (is_raw) ? raw_read (regnum, reg) : cooked_read (regnum, reg); + register_status status; + gdb_byte *reg_buf = (gdb_byte *) alloca (reg_size); + auto reg = gdb::make_array_view (reg_buf, reg_size); + + if (is_raw) + status = raw_read (regnum, reg); + else + status = cooked_read (regnum, reg); + if (status != REG_VALID) return status; /* Update buffer, then write back to regcache. */ - memcpy (reg + offset, in, len); - is_raw ? raw_write (regnum, reg) : cooked_write (regnum, reg); + copy (src, reg.slice (offset, src.size ())); + + if (is_raw) + raw_write (regnum, reg); + else + cooked_write (regnum, reg); + return REG_VALID; } /* See regcache.h. */ void -reg_buffer::raw_supply_part (int regnum, int offset, int len, - const gdb_byte *in) +reg_buffer::raw_supply_part (int regnum, int offset, + gdb::array_view src) { int reg_size = register_size (arch (), regnum); - gdb_assert (in != nullptr); gdb_assert (offset >= 0); - gdb_assert (len >= 0 && offset + len <= reg_size); + gdb_assert (offset + src.size () <= reg_size); - if (len == 0) + if (src.size () == 0) { /* Nothing to do. */ return; } - if (len == reg_size) + if (src.size () == reg_size) { /* Supply the full register. */ - return raw_supply (regnum, in); + return raw_supply (regnum, src); } - gdb_byte *reg = (gdb_byte *) alloca (reg_size); - /* Read existing value to buffer. */ + gdb_byte *reg_buf = (gdb_byte *) alloca (reg_size); + auto reg = gdb::make_array_view (reg_buf, reg_size); raw_collect (regnum, reg); /* Write to buffer, then write out. */ - memcpy (reg + offset, in, len); + copy (src, reg.slice (offset, src.size ())); raw_supply (regnum, reg); } -enum register_status -readable_regcache::raw_read_part (int regnum, int offset, int len, - gdb_byte *buf) +register_status +readable_regcache::raw_read_part (int regnum, int offset, + gdb::array_view dst) { assert_regnum (regnum); - return read_part (regnum, offset, len, buf, true); + return read_part (regnum, offset, dst, true); } /* See regcache.h. */ void -regcache::raw_write_part (int regnum, int offset, int len, - const gdb_byte *buf) +regcache::raw_write_part (int regnum, int offset, + gdb::array_view src) { assert_regnum (regnum); - write_part (regnum, offset, len, buf, true); + write_part (regnum, offset, src, true); } /* See regcache.h. */ -enum register_status -readable_regcache::cooked_read_part (int regnum, int offset, int len, - gdb_byte *buf) +register_status +readable_regcache::cooked_read_part (int regnum, int offset, + gdb::array_view dst) { gdb_assert (regnum >= 0 && regnum < m_descr->nr_cooked_registers); - return read_part (regnum, offset, len, buf, false); + return read_part (regnum, offset, dst, false); } /* See regcache.h. */ void -regcache::cooked_write_part (int regnum, int offset, int len, - const gdb_byte *buf) +regcache::cooked_write_part (int regnum, int offset, + gdb::array_view src) { gdb_assert (regnum >= 0 && regnum < m_descr->nr_cooked_registers); - write_part (regnum, offset, len, buf, false); + write_part (regnum, offset, src, false); } /* See gdbsupport/common-regcache.h. */ void -reg_buffer::raw_supply (int regnum, const void *buf) +reg_buffer::raw_supply (int regnum, gdb::array_view src) { - void *regbuf; - size_t size; + gdb::array_view dst = register_buffer (regnum); - assert_regnum (regnum); - - regbuf = register_buffer (regnum); - size = m_descr->sizeof_register[regnum]; - - if (buf) + if (src.data () != nullptr) { - memcpy (regbuf, buf, size); + copy (src, dst); m_register_status[regnum] = REG_VALID; } else @@ -1065,7 +1143,7 @@ reg_buffer::raw_supply (int regnum, const void *buf) /* This memset not strictly necessary, but better than garbage in case the register value manages to escape somewhere (due to a bug, no less). */ - memset (regbuf, 0, size); + memset (dst.data (), 0, dst.size ()); m_register_status[regnum] = REG_UNAVAILABLE; } } @@ -1073,19 +1151,24 @@ reg_buffer::raw_supply (int regnum, const void *buf) /* See regcache.h. */ void -reg_buffer::raw_supply_integer (int regnum, const gdb_byte *addr, - int addr_len, bool is_signed) +reg_buffer::raw_supply (int regnum, const void *src) { - enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch); - gdb_byte *regbuf; - size_t regsize; - assert_regnum (regnum); - regbuf = register_buffer (regnum); - regsize = m_descr->sizeof_register[regnum]; + int size = m_descr->sizeof_register[regnum]; + raw_supply (regnum, gdb::make_array_view ((const gdb_byte *) src, size)); +} + +/* See regcache.h. */ - copy_integer_to_size (regbuf, regsize, addr, addr_len, is_signed, +void +reg_buffer::raw_supply_integer (int regnum, const gdb_byte *addr, int addr_len, + bool is_signed) +{ + gdb::array_view dst = register_buffer (regnum); + bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch); + + copy_integer_to_size (dst.data (), dst.size (), addr, addr_len, is_signed, byte_order); m_register_status[regnum] = REG_VALID; } @@ -1095,32 +1178,29 @@ reg_buffer::raw_supply_integer (int regnum, const gdb_byte *addr, void reg_buffer::raw_supply_zeroed (int regnum) { - void *regbuf; - size_t size; - - assert_regnum (regnum); - - regbuf = register_buffer (regnum); - size = m_descr->sizeof_register[regnum]; - - memset (regbuf, 0, size); + gdb::array_view dst = register_buffer (regnum); + memset (dst.data (), 0, dst.size ()); m_register_status[regnum] = REG_VALID; } /* See gdbsupport/common-regcache.h. */ void -reg_buffer::raw_collect (int regnum, void *buf) const +reg_buffer::raw_collect (int regnum, gdb::array_view dst) const { - const void *regbuf; - size_t size; + gdb::array_view src = register_buffer (regnum); + copy (src, dst); +} - gdb_assert (buf != NULL); +/* See regcache.h. */ + +void +reg_buffer::raw_collect (int regnum, void *dst) const +{ assert_regnum (regnum); - regbuf = register_buffer (regnum); - size = m_descr->sizeof_register[regnum]; - memcpy (buf, regbuf, size); + int size = m_descr->sizeof_register[regnum]; + return raw_collect (regnum, gdb::make_array_view ((gdb_byte *) dst, size)); } /* See regcache.h. */ @@ -1129,16 +1209,9 @@ void reg_buffer::raw_collect_integer (int regnum, gdb_byte *addr, int addr_len, bool is_signed) const { - enum bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch); - const gdb_byte *regbuf; - size_t regsize; - - assert_regnum (regnum); - - regbuf = register_buffer (regnum); - regsize = m_descr->sizeof_register[regnum]; - - copy_integer_to_size (addr, addr_len, regbuf, regsize, is_signed, + gdb::array_view dst = register_buffer (regnum); + bfd_endian byte_order = gdbarch_byte_order (m_descr->gdbarch); + copy_integer_to_size (addr, addr_len, dst.data (), dst.size (), is_signed, byte_order); } @@ -1157,7 +1230,8 @@ regcache::transfer_regset_register (struct regcache *out_regcache, int regnum, if (out_buf != nullptr) { - raw_collect_part (regnum, 0, reg_size, out_buf + offs); + raw_collect_part (regnum, 0, + gdb::make_array_view (out_buf + offs, reg_size)); /* Ensure any additional space is cleared. */ if (slot_size > reg_size) @@ -1168,12 +1242,14 @@ regcache::transfer_regset_register (struct regcache *out_regcache, int regnum, /* Zero-extend the register value if the slot is smaller than the register. */ if (slot_size < register_size (gdbarch, regnum)) out_regcache->raw_supply_zeroed (regnum); - out_regcache->raw_supply_part (regnum, 0, reg_size, in_buf + offs); + out_regcache->raw_supply_part (regnum, 0, + gdb::make_array_view (in_buf + offs, + reg_size)); } else { /* Invalidate the register. */ - out_regcache->raw_supply (regnum, nullptr); + out_regcache->raw_supply (regnum, {}); } } @@ -1304,13 +1380,12 @@ bool reg_buffer::raw_compare (int regnum, const void *buf, int offset) const { gdb_assert (buf != NULL); - assert_regnum (regnum); - const char *regbuf = (const char *) register_buffer (regnum); - size_t size = m_descr->sizeof_register[regnum]; - gdb_assert (size >= offset); + gdb::array_view regbuf = register_buffer (regnum); + gdb_assert (offset <= regbuf.size ()); + regbuf = regbuf.slice (offset); - return (memcmp (buf, regbuf + offset, size - offset) == 0); + return memcmp (buf, regbuf.data (), regbuf.size ()) == 0; } /* Special handling for register PC. */ @@ -1399,17 +1474,15 @@ regcache::debug_print_register (const char *func, int regno) if (regno >= 0 && regno < gdbarch_num_regs (gdbarch)) { enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - int size = register_size (gdbarch, regno); - gdb_byte *buf = register_buffer (regno); + gdb::array_view buf = register_buffer (regno); gdb_printf (gdb_stdlog, " = "); - for (int i = 0; i < size; i++) - { - gdb_printf (gdb_stdlog, "%02x", buf[i]); - } - if (size <= sizeof (LONGEST)) + for (gdb_byte byte : buf) + gdb_printf (gdb_stdlog, "%02x", byte); + + if (buf.size () <= sizeof (LONGEST)) { - ULONGEST val = extract_unsigned_integer (buf, size, byte_order); + ULONGEST val = extract_unsigned_integer (buf, byte_order); gdb_printf (gdb_stdlog, " %s %s", core_addr_to_string_nz (val), plongest (val)); @@ -1758,6 +1831,23 @@ registers_changed_ptid_target_ptid_test () ptid_t (2, 2)) == 1); } +/* Test using reg_buffer::raw_compare with offset equal to the register size + (thus comparing 0 bytes). */ + +static void +reg_buffer_raw_compare_zero_len_test () +{ + regcache_test_data_up data = populate_regcaches_for_test (); + inferior &inf = data->test_ctx_1.mock_inferior; + const regcache *regcache + = get_thread_arch_regcache (&inf, ptid_t (1, 1), inf.arch ()); + + /* The buffer address is irrelevant since we end up comparing 0 bytes, we just + need to pass something. */ + gdb_byte buf; + SELF_CHECK (regcache->raw_compare (0, &buf, register_size (inf.arch (), 0))); +} + class target_ops_no_register : public test_target_ops { public: @@ -1869,7 +1959,7 @@ cooked_read_test (struct gdbarch *gdbarch) readwrite.set_ptid (mockctx.mock_ptid); gdb::byte_vector buf (register_size (gdbarch, nonzero_regnum)); - readwrite.raw_read (nonzero_regnum, buf.data ()); + readwrite.raw_read (nonzero_regnum, buf); /* raw_read calls target_fetch_registers. */ SELF_CHECK (mockctx.mock_target.fetch_registers_called > 0); @@ -1890,9 +1980,7 @@ cooked_read_test (struct gdbarch *gdbarch) gdb::byte_vector inner_buf (register_size (gdbarch, regnum)); - SELF_CHECK (REG_VALID == readwrite.cooked_read (regnum, - inner_buf.data ())); - + SELF_CHECK (REG_VALID == readwrite.cooked_read (regnum, inner_buf)); SELF_CHECK (mockctx.mock_target.fetch_registers_called == 0); SELF_CHECK (mockctx.mock_target.store_registers_called == 0); SELF_CHECK (mockctx.mock_target.xfer_partial_called == 0); @@ -1912,8 +2000,7 @@ cooked_read_test (struct gdbarch *gdbarch) continue; gdb::byte_vector inner_buf (register_size (gdbarch, regnum)); - enum register_status status = readonly.cooked_read (regnum, - inner_buf.data ()); + register_status status = readonly.cooked_read (regnum, inner_buf); if (regnum < gdbarch_num_regs (gdbarch)) { @@ -2003,8 +2090,8 @@ cooked_write_test (struct gdbarch *gdbarch) && regnum <= gdbarch_num_regs (gdbarch) + 4)) continue; - std::vector expected (register_size (gdbarch, regnum), 0); - std::vector buf (register_size (gdbarch, regnum), 0); + gdb::byte_vector expected (register_size (gdbarch, regnum), 0); + gdb::byte_vector buf (register_size (gdbarch, regnum), 0); const auto type = register_type (gdbarch, regnum); if (type->code () == TYPE_CODE_FLT @@ -2059,9 +2146,9 @@ cooked_write_test (struct gdbarch *gdbarch) SELF_CHECK (0); } - readwrite.cooked_write (regnum, expected.data ()); + readwrite.cooked_write (regnum, expected); - SELF_CHECK (readwrite.cooked_read (regnum, buf.data ()) == REG_VALID); + SELF_CHECK (readwrite.cooked_read (regnum, buf) == REG_VALID); SELF_CHECK (expected == buf); } } @@ -2154,6 +2241,8 @@ _initialize_regcache () selftests::registers_changed_ptid_target_pid_test); selftests::register_test ("registers_changed_ptid_target_ptid", selftests::registers_changed_ptid_target_ptid_test); + selftests::register_test ("reg_buffer_raw_compare_zero_len", + selftests::reg_buffer_raw_compare_zero_len_test); selftests::register_test_foreach_arch ("regcache::cooked_read_test", selftests::cooked_read_test); diff --git a/gdb/regcache.h b/gdb/regcache.h index 7922a5c5ae21..d90f74bfbb06 100644 --- a/gdb/regcache.h +++ b/gdb/regcache.h @@ -20,6 +20,7 @@ #ifndef REGCACHE_H #define REGCACHE_H +#include "gdbsupport/array-view.h" #include "gdbsupport/common-regcache.h" #include "gdbsupport/function-view.h" @@ -167,8 +168,8 @@ extern struct type *register_type (struct gdbarch *gdbarch, int regnum); extern int register_size (struct gdbarch *gdbarch, int regnum); -typedef gdb::function_view - register_read_ftype; +using register_read_ftype + = gdb::function_view)>; /* A (register_number, register_value) pair. */ @@ -194,7 +195,10 @@ class reg_buffer : public reg_buffer_common enum register_status get_register_status (int regnum) const override; /* See gdbsupport/common-regcache.h. */ - void raw_collect (int regnum, void *buf) const override; + void raw_collect (int regnum, gdb::array_view dst) const override; + + /* Deprecated overload of the above. */ + void raw_collect (int regnum, void *dst) const; /* Collect register REGNUM from REGCACHE. Store collected value as an integer at address ADDR, in target endian, with length ADDR_LEN and sign IS_SIGNED. @@ -204,17 +208,23 @@ class reg_buffer : public reg_buffer_common void raw_collect_integer (int regnum, gdb_byte *addr, int addr_len, bool is_signed) const; - /* Collect register REGNUM from REGCACHE, starting at OFFSET in register, - reading only LEN. */ - void raw_collect_part (int regnum, int offset, int len, gdb_byte *out) const; + /* Collect part of register REGNUM from this register buffer. Start at OFFSET + in register. The size is given by the size of DST. */ + void raw_collect_part (int regnum, int offset, + gdb::array_view dst) const; + + /* Deprecated overload of the above. */ + void raw_collect_part (int regnum, int offset, int len, gdb_byte *dst) const + { raw_collect_part (regnum, offset, gdb::make_array_view (dst, len)); } /* See gdbsupport/common-regcache.h. */ - void raw_supply (int regnum, const void *buf) override; + void raw_supply (int regnum, gdb::array_view src) override; + + /* Deprecated overload of the above. */ + void raw_supply (int regnum, const void *src); void raw_supply (int regnum, const reg_buffer &src) - { - raw_supply (regnum, src.register_buffer (regnum)); - } + { raw_supply (regnum, src.register_buffer (regnum)); } /* Supply register REGNUM to REGCACHE. Value to supply is an integer stored at address ADDR, in target endian, with length ADDR_LEN and sign IS_SIGNED. @@ -229,9 +239,11 @@ class reg_buffer : public reg_buffer_common unavailable). */ void raw_supply_zeroed (int regnum); - /* Supply register REGNUM to REGCACHE, starting at OFFSET in register, writing - only LEN, without editing the rest of the register. */ - void raw_supply_part (int regnum, int offset, int len, const gdb_byte *in); + /* Supply part of register REGNUM to this register buffer. Start at OFFSET in + the register. The size is given by the size of SRC. The rest of the + register left untouched. */ + void raw_supply_part (int regnum, int offset, + gdb::array_view src); void invalidate (int regnum); @@ -246,7 +258,11 @@ class reg_buffer : public reg_buffer_common int num_raw_registers () const; - gdb_byte *register_buffer (int regnum) const; + /* Return a view on register REGNUM's buffer cache. */ + template + gdb::array_view register_buffer (int regnum) const; + gdb::array_view register_buffer (int regnum) const; + gdb::array_view register_buffer (int regnum); /* Save a register cache. The set of registers saved into the regcache determined by the save_reggroup. COOKED_READ returns @@ -276,27 +292,41 @@ class readable_regcache : public reg_buffer /* Transfer a raw register [0..NUM_REGS) from core-gdb to this regcache, return its value in *BUF and return its availability status. */ + register_status raw_read (int regnum, gdb::array_view dst); + + /* Deprecated overload of the above. */ + register_status raw_read (int regnum, gdb_byte *dst); - enum register_status raw_read (int regnum, gdb_byte *buf); template> - enum register_status raw_read (int regnum, T *val); + register_status raw_read (int regnum, T *val); /* Partial transfer of raw registers. Return the status of the register. */ - enum register_status raw_read_part (int regnum, int offset, int len, - gdb_byte *buf); + register_status raw_read_part (int regnum, int offset, + gdb::array_view dst); + + /* Deprecated overload of the above. */ + register_status raw_read_part (int regnum, int offset, int len, + gdb_byte *dst) + { return raw_read_part (regnum, offset, gdb::make_array_view (dst, len)); } /* Make certain that the register REGNUM is up-to-date. */ virtual void raw_update (int regnum) = 0; /* Transfer a raw register [0..NUM_REGS+NUM_PSEUDO_REGS) from core-gdb to - this regcache, return its value in *BUF and return its availability status. */ - enum register_status cooked_read (int regnum, gdb_byte *buf); + this regcache, return its value in DST and return its availability status. */ + register_status cooked_read (int regnum, gdb::array_view dst); + register_status cooked_read (int regnum, gdb_byte *dst); + template> - enum register_status cooked_read (int regnum, T *val); + register_status cooked_read (int regnum, T *val); /* Partial transfer of a cooked register. */ - enum register_status cooked_read_part (int regnum, int offset, int len, - gdb_byte *buf); + register_status cooked_read_part (int regnum, int offset, + gdb::array_view dst); + + /* Deprecated overload of the above. */ + register_status cooked_read_part (int regnum, int offset, int len, gdb_byte *src) + { return cooked_read_part (regnum, offset, gdb::make_array_view (src, len)); } /* Read register REGNUM from the regcache and return a new value. This will call mark_value_bytes_unavailable as appropriate. */ @@ -306,8 +336,8 @@ class readable_regcache : public reg_buffer /* Perform a partial register transfer using a read, modify, write operation. Will fail if register is currently invalid. */ - enum register_status read_part (int regnum, int offset, int len, - gdb_byte *out, bool is_raw); + register_status read_part (int regnum, int offset, + gdb::array_view dst, bool is_raw); }; /* Buffer of registers, can be read and written. */ @@ -343,13 +373,19 @@ class regcache : public detached_regcache /* Update the value of raw register REGNUM (in the range [0..NUM_REGS)) and transfer its value to core-gdb. */ - void raw_write (int regnum, const gdb_byte *buf); + void raw_write (int regnum, gdb::array_view src); + + /* Deprecated overload of the above. */ + void raw_write (int regnum, const gdb_byte *src); template> void raw_write (int regnum, T val); /* Transfer of pseudo-registers. */ - void cooked_write (int regnum, const gdb_byte *buf); + void cooked_write (int regnum, gdb::array_view src); + + /* Deprecated overload of the above. */ + void cooked_write (int regnum, const gdb_byte *src); template> void cooked_write (int regnum, T val); @@ -358,12 +394,21 @@ class regcache : public detached_regcache /* Partial transfer of raw registers. Perform read, modify, write style operations. */ - void raw_write_part (int regnum, int offset, int len, const gdb_byte *buf); + void raw_write_part (int regnum, int offset, + gdb::array_view src); + + /* Deprecated overload of the above. */ + void raw_write_part (int regnum, int offset, int len, const gdb_byte *src) + { raw_write_part (regnum, offset, gdb::make_array_view (src, len)); } /* Partial transfer of a cooked register. Perform read, modify, write style operations. */ - void cooked_write_part (int regnum, int offset, int len, - const gdb_byte *buf); + void cooked_write_part (int regnum, int offset, + gdb::array_view src); + + /* Deprecated overload of the above. */ + void cooked_write_part (int regnum, int offset, int len, const gdb_byte *src) + { cooked_write_part (regnum, offset, gdb::make_array_view (src, len)); } /* Transfer a set of registers (as described by REGSET) between REGCACHE and BUF. If REGNUM == -1, transfer all registers @@ -430,8 +475,9 @@ class regcache : public detached_regcache /* Perform a partial register transfer using a read, modify, write operation. */ - enum register_status write_part (int regnum, int offset, int len, - const gdb_byte *in, bool is_raw); + register_status write_part (int regnum, int offset, + gdb::array_view src, + bool is_raw); /* The inferior to switch to, to make target calls. diff --git a/gdbserver/regcache.cc b/gdbserver/regcache.cc index 823ea1f015d3..c5d3670b4b56 100644 --- a/gdbserver/regcache.cc +++ b/gdbserver/regcache.cc @@ -315,27 +315,32 @@ regcache_register_size (const reg_buffer_common *regcache, int n) (gdb::checked_static_cast (regcache)->tdesc, n); } -static unsigned char * +static gdb::array_view register_data (const struct regcache *regcache, int n) { - return (regcache->registers - + find_register_by_number (regcache->tdesc, n).offset / 8); + const gdb::reg ® = find_register_by_number (regcache->tdesc, n); + return gdb::make_array_view (regcache->registers + reg.offset / 8, + reg.size / 8); } void -supply_register (struct regcache *regcache, int n, const void *buf) +supply_register (struct regcache *regcache, int n, const void *vbuf) { - return regcache->raw_supply (n, buf); + const gdb::reg ® = find_register_by_number (regcache->tdesc, n); + const gdb_byte *buf = static_cast (vbuf); + return regcache->raw_supply (n, gdb::make_array_view (buf, reg.size / 8)); } /* See gdbsupport/common-regcache.h. */ void -regcache::raw_supply (int n, const void *buf) +regcache::raw_supply (int n, gdb::array_view src) { - if (buf) + auto dst = register_data (this, n); + + if (src.data () != nullptr) { - memcpy (register_data (this, n), buf, register_size (tdesc, n)); + copy (src, dst); #ifndef IN_PROCESS_AGENT if (register_status != NULL) register_status[n] = REG_VALID; @@ -343,7 +348,7 @@ regcache::raw_supply (int n, const void *buf) } else { - memset (register_data (this, n), 0, register_size (tdesc, n)); + memset (dst.data (), 0, dst.size ()); #ifndef IN_PROCESS_AGENT if (register_status != NULL) register_status[n] = REG_UNAVAILABLE; @@ -356,8 +361,8 @@ regcache::raw_supply (int n, const void *buf) void supply_register_zeroed (struct regcache *regcache, int n) { - memset (register_data (regcache, n), 0, - register_size (regcache->tdesc, n)); + auto dst = register_data (regcache, n); + memset (dst.data (), 0, dst.size ()); #ifndef IN_PROCESS_AGENT if (regcache->register_status != NULL) regcache->register_status[n] = REG_VALID; @@ -426,17 +431,20 @@ supply_register_by_name (struct regcache *regcache, #endif void -collect_register (struct regcache *regcache, int n, void *buf) +collect_register (struct regcache *regcache, int n, void *vbuf) { - regcache->raw_collect (n, buf); + const gdb::reg ® = find_register_by_number (regcache->tdesc, n); + gdb_byte *buf = static_cast (vbuf); + regcache->raw_collect (n, gdb::make_array_view (buf, reg.size / 8)); } /* See gdbsupport/common-regcache.h. */ void -regcache::raw_collect (int n, void *buf) const +regcache::raw_collect (int n, gdb::array_view dst) const { - memcpy (buf, register_data (this, n), register_size (tdesc, n)); + auto src = register_data (this, n); + copy (src, dst); } enum register_status @@ -476,8 +484,7 @@ regcache_raw_get_unsigned_by_name (struct regcache *regcache, void collect_register_as_string (struct regcache *regcache, int n, char *buf) { - bin2hex (register_data (regcache, n), buf, - register_size (regcache->tdesc, n)); + bin2hex (register_data (regcache, n), buf); } void @@ -524,9 +531,9 @@ regcache::raw_compare (int regnum, const void *buf, int offset) const { gdb_assert (buf != NULL); - const unsigned char *regbuf = register_data (this, regnum); - int size = register_size (tdesc, regnum); - gdb_assert (size >= offset); + gdb::array_view regbuf = register_data (this, regnum); + gdb_assert (offset < regbuf.size ()); + regbuf = regbuf.slice (offset); - return (memcmp (buf, regbuf + offset, size - offset) == 0); + return memcmp (buf, regbuf.data (), regbuf.size ()) == 0; } diff --git a/gdbserver/regcache.h b/gdbserver/regcache.h index 4700c03f104e..02791a048fb0 100644 --- a/gdbserver/regcache.h +++ b/gdbserver/regcache.h @@ -50,10 +50,10 @@ struct regcache : public reg_buffer_common enum register_status get_register_status (int regnum) const override; /* See gdbsupport/common-regcache.h. */ - void raw_supply (int regnum, const void *buf) override; + void raw_supply (int regnum, gdb::array_view src) override; /* See gdbsupport/common-regcache.h. */ - void raw_collect (int regnum, void *buf) const override; + void raw_collect (int regnum, gdb::array_view dst) const override; /* See gdbsupport/common-regcache.h. */ bool raw_compare (int regnum, const void *buf, int offset) const override; diff --git a/gdbsupport/common-regcache.h b/gdbsupport/common-regcache.h index 6d98ca8c92ed..c40b92a83ee1 100644 --- a/gdbsupport/common-regcache.h +++ b/gdbsupport/common-regcache.h @@ -78,11 +78,41 @@ struct reg_buffer_common buffer. */ virtual register_status get_register_status (int regnum) const = 0; - /* Supply register REGNUM, whose contents are stored in BUF, to REGCACHE. */ - virtual void raw_supply (int regnum, const void *buf) = 0; + /* Supply register REGNUM, whose contents are stored in SRC, to this register + buffer. */ + virtual void raw_supply (int regnum, gdb::array_view src) + = 0; + + void raw_supply (int regnum, const uint64_t *src) + { + raw_supply (regnum, + gdb::make_array_view ((const gdb_byte *) src, sizeof (*src))); + } + + void raw_supply (int regnum, const gdb_byte *src) + { + raw_supply (regnum, + gdb::make_array_view (src, + regcache_register_size (this, regnum))); + } - /* Collect register REGNUM from REGCACHE and store its contents in BUF. */ - virtual void raw_collect (int regnum, void *buf) const = 0; + /* Collect register REGNUM from this register buffer and store its contents in + DST. */ + virtual void raw_collect (int regnum, gdb::array_view dst) const + = 0; + + void raw_collect (int regnum, uint64_t *dst) const + { + raw_collect (regnum, + gdb::make_array_view ((gdb_byte *) dst, sizeof (*dst))); + }; + + void raw_collect (int regnum, gdb_byte *dst) + { + raw_collect (regnum, + gdb::make_array_view (dst, + regcache_register_size (this, regnum))); + } /* Compare the contents of the register stored in the regcache (ignoring the first OFFSET bytes) to the contents of BUF (without any offset). Returns diff --git a/gdbsupport/rsp-low.cc b/gdbsupport/rsp-low.cc index 3d8c2002956e..632be265c00c 100644 --- a/gdbsupport/rsp-low.cc +++ b/gdbsupport/rsp-low.cc @@ -143,6 +143,14 @@ bin2hex (const gdb_byte *bin, char *hex, int count) /* See rsp-low.h. */ +int +bin2hex (gdb::array_view bin, char *hex) +{ + return bin2hex (bin.data (), hex, bin.size ()); +} + +/* See rsp-low.h. */ + std::string bin2hex (const gdb_byte *bin, int count) { diff --git a/gdbsupport/rsp-low.h b/gdbsupport/rsp-low.h index 327d5f3a0947..1fc2572a7f5c 100644 --- a/gdbsupport/rsp-low.h +++ b/gdbsupport/rsp-low.h @@ -54,6 +54,8 @@ extern std::string hex2str (const char *hex, int count); extern int bin2hex (const gdb_byte *bin, char *hex, int count); +extern int bin2hex (gdb::array_view bin, char *hex); + /* Overloaded version of bin2hex that returns a std::string. */ extern std::string bin2hex (const gdb_byte *bin, int count);