This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[patch/rfc] register_offset_hack()
- From: Andrew Cagney <ac131313 at ges dot redhat dot com>
- To: gdb-patches at sources dot redhat dot com
- Date: Sat, 17 Aug 2002 23:12:00 -0400
- Subject: [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. */