public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Alan Hayward <alan.hayward@arm.com>
To: gdb-patches@sourceware.org
Cc: nd@arm.com,	Alan Hayward <alan.hayward@arm.com>
Subject: [PATCH v2 3/3] Use partial register read/writes in transfer_regset
Date: Thu, 21 Jun 2018 09:39:00 -0000	[thread overview]
Message-ID: <20180621093802.79342-4-alan.hayward@arm.com> (raw)
In-Reply-To: <20180621093802.79342-1-alan.hayward@arm.com>

This avoids assert failures when the register is bigger than the
slot size. This happens on Aarch64 when truncating Z registers
into an fpsimd structure.

Also, when the register is smaller then the slot size, then
zero pad when writing to the slot, and truncate when writing
to the regcache. This happens on Aarch64 with the CPSR register.

Continue to ensure registers are invalidated when both buffers
are null.

2018-06-21  Alan Hayward  <alan.hayward@arm.com>

	* regcache.c (reg_buffer::raw_collect_part): New function.
	(reg_buffer::raw_supply_part): Likewise.
	(regcache::transfer_regset): Call new functions.
	* regcache.h (reg_buffer::raw_collect_part): New declaration.
	(reg_buffer::raw_supply_part): Likewise.
---
 gdb/regcache.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 gdb/regcache.h | 10 +++++++
 2 files changed, 95 insertions(+), 8 deletions(-)

diff --git a/gdb/regcache.c b/gdb/regcache.c
index fe4742c2ee..4939150c66 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -807,6 +807,38 @@ readable_regcache::read_part (int regnum, int offset, int len,
 
 /* See regcache.h.  */
 
+void
+reg_buffer::raw_collect_part (int regnum, int offset, int len,
+			      gdb_byte *out) const
+{
+  int reg_size = register_size (arch (), regnum);
+
+  gdb_assert (out != nullptr);
+  gdb_assert (offset >= 0 && len >= 0 && offset <= reg_size);
+
+  if (offset == 0 && len == 0)
+    return;
+
+  if (offset == 0 && len == reg_size)
+    return raw_collect (regnum, out);
+
+  /* Read to buffer, then write out.  */
+  gdb_byte *reg = (gdb_byte *) alloca (reg_size);
+  raw_collect (regnum, reg);
+
+  if (offset + len <= reg_size)
+    memcpy (out, reg + offset, len);
+  else
+    {
+      /* Requested region runs off the end of the register.  Clear the
+	 additional space.  */
+      memcpy (out, reg + offset, reg_size - offset);
+      memset (out + reg_size, 0, offset + len - reg_size);
+    }
+}
+
+/* See regcache.h.  */
+
 enum register_status
 regcache::write_part (int regnum, int offset, int len,
 		      const gdb_byte *in, bool is_raw)
@@ -841,6 +873,38 @@ regcache::write_part (int regnum, int offset, int len,
 
 /* See regcache.h.  */
 
+void
+reg_buffer::raw_supply_part (int regnum, int offset, int len,
+			     const gdb_byte *in)
+{
+  int reg_size = register_size (arch (), regnum);
+
+  gdb_assert (in != nullptr);
+  gdb_assert (offset >= 0 && len >= 0 && offset <= reg_size);
+
+  if (offset == 0 && len == 0)
+    return;
+
+  if (offset + len > reg_size)
+    {
+      /* Truncate length to fit the size of the regcache register.  */
+      len = reg_size - offset;
+    }
+
+  if (offset == 0 && len == reg_size)
+    return raw_supply (regnum, in);
+
+  gdb_byte *reg = (gdb_byte *) alloca (reg_size);
+
+  /* Read when needed.  */
+  if (offset > 0 || offset + len < reg_size)
+    raw_collect (regnum, reg);
+
+  /* Write to buffer, then write out.  */
+  memcpy (reg + offset, in, len);
+  raw_supply (regnum, reg);
+}
+
 enum register_status
 readable_regcache::raw_read_part (int regnum, int offset, int len,
 				  gdb_byte *buf)
@@ -1013,12 +1077,18 @@ regcache::transfer_regset (const struct regset *regset,
 	    if (offs + slot_size > size)
 	      break;
 
+	    /* Use part versions to prevent possible overflow.  */
 	    if (out_buf)
-	      raw_collect (regno, (gdb_byte *) out_buf + offs);
+	      raw_collect_part (regno, 0, slot_size,
+				(gdb_byte *) out_buf + offs);
+	    else if (in_buf)
+	      out_regcache->raw_supply_part (regno, 0, slot_size,
+					     (const gdb_byte *) in_buf + offs);
 	    else
-	      out_regcache->raw_supply (regno, in_buf
-					? (const gdb_byte *) in_buf + offs
-					: NULL);
+	      {
+	      	/* Invalidate the register.  */
+		out_regcache->raw_supply (regno, nullptr);
+	      }
 	  }
       else
 	{
@@ -1027,12 +1097,19 @@ regcache::transfer_regset (const struct regset *regset,
 	  if (offs + slot_size > size)
 	    return;
 
+	  /* Use part versions to prevent possible overflow.  */
 	  if (out_buf)
-	    raw_collect (regnum, (gdb_byte *) out_buf + offs);
+	    raw_collect_part (regnum, 0, slot_size,
+			      (gdb_byte *) out_buf + offs);
+	  else if (in_buf)
+	    out_regcache->raw_supply_part (regnum, 0, slot_size,
+					   (const gdb_byte *) in_buf + offs);
 	  else
-	    out_regcache->raw_supply (regnum, in_buf
-				      ? (const gdb_byte *) in_buf + offs
-				      : NULL);
+	    {
+	      /* Invalidate the register.  */
+	      out_regcache->raw_supply (regnum, nullptr);
+	    }
+
 	  return;
 	}
     }
diff --git a/gdb/regcache.h b/gdb/regcache.h
index c17ce09dee..a69b67d513 100644
--- a/gdb/regcache.h
+++ b/gdb/regcache.h
@@ -162,6 +162,11 @@ public:
   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 REGCACHE,
+     reading only LEN.  If this runs off the end of the register, then fill the
+     additional space with zeros.  */
+  void raw_collect_part (int regnum, int offset, int len, gdb_byte *out) const;
+
   /* See common/common-regcache.h.  */
   void raw_supply (int regnum, const void *buf) override;
 
@@ -183,6 +188,11 @@ public:
      unavailable).  */
   void raw_supply_zeroed (int regnum);
 
+  /* Supply register REGNUM to REGCACHE, starting at offset in REGCACHE, writing
+     only LEN, without editing the rest of the register.  If the length of the
+     supplied value would overflow the register, then truncate.  */
+  void raw_supply_part (int regnum, int offset, int len, const gdb_byte *in);
+
   void invalidate (int regnum);
 
   virtual ~reg_buffer () = default;
-- 
2.15.2 (Apple Git-101.1)

  parent reply	other threads:[~2018-06-21  9:39 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-21  9:39 [PATCH v2 0/3] Support large registers in regcache transfer_regset Alan Hayward
2018-06-21  9:38 ` [PATCH v2 1/3] Use unsigned ints in regcache_map_entry Alan Hayward
2018-06-21 13:27   ` Simon Marchi
2018-06-21 13:52     ` Simon Marchi
2018-06-21 15:19       ` Alan Hayward
2018-06-21 15:34         ` Simon Marchi
2018-06-21 17:32           ` Simon Marchi
2018-06-21 19:52             ` Alan Hayward
2018-06-21  9:39 ` Alan Hayward [this message]
2018-06-21 14:16   ` [PATCH v2 3/3] Use partial register read/writes in transfer_regset Simon Marchi
2018-06-21 19:56     ` Alan Hayward
2018-06-21 15:02   ` Simon Marchi
2018-06-21  9:39 ` [PATCH v2 2/3] Avoid memcpys in regcache read_part/write_part for full registers Alan Hayward
2018-06-21 14:00   ` Simon Marchi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180621093802.79342-4-alan.hayward@arm.com \
    --to=alan.hayward@arm.com \
    --cc=gdb-patches@sourceware.org \
    --cc=nd@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).