This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch/rfc] register_offset_hack()


Hello,

The attached adds a number of ``hacks'' to the regcache. The intent is for these hacks to replace the far worse and much dreaded read_register_bytes() and write_register_bytes().

The struct value and expression evaluator view the register cache as a linear byte array. Hence, to read adjacent registers, a ``memcpy'' of the relevant bytes is all that is needed.

The attached provides the following methods:

register_offset_hack(gdbarch,regnum)
Replaces REGISTER_BYTE(). Returns the ``offset'' of regnum in the register buffer.

regcache_cooked read/write using_offset_hack(regcache,offset,len,buf)
read/write the cooked register cache treating the cache as a big array.

While similar to the read_register_bytes() and write_register_bytes() methods they have far simpler interfaces. Hacks such as reading, or even allowing, gaps between registers have been removed.

Other than a couple cases related to the expression evaluator and struct value, there should be no reason for using these functions.

I'll look to commit this code in a few days but won't even consider changing things over until post 5.3 branch.

enjoy,
Andrew
2002-08-17  Andrew Cagney  <ac131313@redhat.com>

	* regcache.c (register_offset_hack): New function.
	(regcache_cooked_read_using_offset_hack): New function.
	(regcache_cooked_write_using_offset_hack): New function.
	(regcache_dump): Check that the registers, according to their
	offset, are packed hard against each other.
	(xfer_using_offset_hack): New function.
	* regcache.h (register_offset_hack): Declare.
	(regcache_cooked_read_using_offset_hack): Declare.
	(regcache_cooked_write_using_offset_hack): Declare.

Index: regcache.c
===================================================================
RCS file: /cvs/src/src/gdb/regcache.c,v
retrieving revision 1.53
diff -u -r1.53 regcache.c
--- regcache.c	13 Aug 2002 23:06:40 -0000	1.53
+++ regcache.c	18 Aug 2002 02:41:34 -0000
@@ -917,6 +917,124 @@
 }
 
 
+/* Hack to keep code that view the register buffer as raw bytes
+   working.  */
+
+int
+register_offset_hack (struct gdbarch *gdbarch, int regnum)
+{
+  struct regcache_descr *descr = regcache_descr (gdbarch);
+  gdb_assert (regnum >= 0 && regnum < descr->nr_cooked_registers);
+  return descr->register_offset[regnum];
+}
+
+static void
+xfer_using_offset_hack (struct regcache *regcache,
+			int buf_start, int buf_len, void *in_b,
+			const void *out_b)
+{
+  struct regcache_descr *descr = regcache->descr;
+  struct gdbarch *gdbarch = descr->gdbarch;
+  bfd_byte *in_buf = in_b;
+  const bfd_byte *out_buf = out_b;
+  int buf_end = buf_start + buf_len;
+  int regnum;
+  char *reg_buf = alloca (descr->max_register_size);
+
+  /* NOTE: cagney/2002-08-17: This code assumes that the register
+     offsets are strictly increasing and do not overlap.  If this
+     isn't the case then the bug is in the target architecture and NOT
+     this code.  */
+
+  /* NOTE: cagney/2002-08-17: This code assumes that only registers
+     identified should be transfered.  If, for some reason, there is a
+     gap between two registers, then that gap isn't transfered.  (The
+     gap shouldn't be there but that is another story.)  */
+
+  /* Iterate through all registers looking for those that lie within
+     offset:length.  */
+
+  for (regnum = 0; regnum < descr->nr_cooked_registers; regnum++)
+    {
+      int start;
+      int end;
+      int byte;
+      int reg_start = descr->register_offset[regnum];
+      int reg_len = descr->sizeof_register[regnum];
+      int reg_end = reg_start + reg_len;
+
+      if (reg_end <= buf_start || reg_start >= buf_end)
+	/* The register does not fall within in the buffer, skip it.  */
+	continue;
+
+      if (reg_start >= buf_start && reg_end < buf_end)
+	{
+	  /* The entire register value falls within the buffer,
+             transfer using a single operation.  For writes, this
+             avoids the need to first do a read/modify on a register
+             that may not have been fetched.  */
+	  int buf_offset = reg_start - buf_start;
+	  if (in_buf != NULL)
+	    regcache_cooked_read (regcache, regnum, in_buf + buf_offset);
+	  if (out_buf != NULL)
+	    regcache_cooked_write (regcache, regnum, out_buf + buf_offset);
+	}
+      else
+	{
+	  /* The register and the buffer overlap.  The register extens
+             beyond the start and/or end of the buffer.  Perform a
+             partial transfer using read, modify and (optionally)
+             write.  */
+
+	  /* The START, END and BYTE within the register cache.  */
+	  int start;
+	  int end;
+	  int byte;
+
+	  /* start = max (reg_start, buf_start) */
+	  if (reg_start > buf_start)
+	    start = reg_start;
+	  else
+	    start = buf_start;
+	  
+	  /* end = min (reg_end, buf_end) */
+	  if (reg_end < buf_end)
+	    end = reg_end;
+	  else
+	    end = buf_end;
+	  
+	  /* Perform the read, modify, write.  */
+	  regcache_cooked_read (regcache, regnum, reg_buf);
+	  for (byte = start; byte < end; byte++)
+	    {
+	      int buf_offset = byte - buf_start;
+	      int reg_offset = byte - reg_start;
+	      if (in_buf != NULL)
+		in_buf[buf_offset] = reg_buf[reg_offset];
+	      if (out_buf != NULL)
+		reg_buf[reg_offset] = out_buf[buf_offset];
+	    }
+	  if (out_buf != NULL)
+	    regcache_cooked_write (regcache, regnum, reg_buf);
+	}
+    }
+}
+
+void
+regcache_cooked_read_using_offset_hack (struct regcache *regcache,
+					int buf_start, int buf_len, void *b)
+{
+  xfer_using_offset_hack (regcache, buf_start, buf_len, b, NULL);
+}
+
+void
+regcache_cooked_write_using_offset_hack (struct regcache *regcache,
+					 int buf_start, int buf_len,
+					 const void *b)
+{
+  xfer_using_offset_hack (regcache, buf_start, buf_len, NULL, b);
+}
+
 /* Return the contents of register REGNUM as an unsigned integer.  */
 
 ULONGEST
@@ -1327,7 +1445,12 @@
 	  fprintf_unfiltered (file, " %6ld",
 			      regcache->descr->register_offset[regnum]);
 	  if (register_offset != regcache->descr->register_offset[regnum]
-	      || register_offset != REGISTER_BYTE (regnum))
+	      || register_offset != REGISTER_BYTE (regnum)
+	      || (regnum > 0
+		  && (regcache->descr->register_offset[regnum]
+		      != (regcache->descr->register_offset[regnum - 1]
+			  + regcache->descr->sizeof_register[regnum - 1])))
+	      )
 	    {
 	      if (!footnote_register_offset)
 		footnote_register_offset = ++footnote_nr;
Index: regcache.h
===================================================================
RCS file: /cvs/src/src/gdb/regcache.h,v
retrieving revision 1.14
diff -u -r1.14 regcache.h
--- regcache.h	13 Aug 2002 14:32:28 -0000	1.14
+++ regcache.h	18 Aug 2002 02:41:34 -0000
@@ -71,6 +71,33 @@
 extern void regcache_collect (int regnum, void *buf);
 
 
+/* The register's ``offset''.
+
+   NOTE: cagney/2002-08-17: The ``struct value'' and expression
+   evaluator treat the register cache as a large liner buffer.
+   Instead of reading/writing a register using its register number,
+   the code read/writes registers by specifying their offset into the
+   buffer and a number of bytes.  The code also assumes that these
+   byte read/writes can cross register boundaries, adjacent registers
+   treated as a contiguous set of bytes.
+
+   The below map that model onto the real register cache.  New code
+   should go out of their way to avoid using these interfaces.
+
+   FIXME: cagney/2002-08-17: The ``struct value'' and expression
+   evaluator should be fixed.  Instead of using the { offset, length }
+   pair to describe a value within one or more registers, the code
+   should use a chain of { regnum, offset, len } tripples.  */
+
+extern int register_offset_hack (struct gdbarch *gdbarch, int regnum);
+extern void regcache_cooked_read_using_offset_hack (struct regcache *regcache,
+						    int offset, int len,
+						    void *buf);
+extern void regcache_cooked_write_using_offset_hack (struct regcache *regcache,
+						     int offset, int len,
+						     const void *buf);
+
+
 /* DEPRECATED: Character array containing an image of the inferior
    programs' registers for the most recently referenced thread. */
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]