#include "gdbcmd.h"
#include "regcache.h"
#include "gdb_assert.h"
+#include "gdb_string.h"
+#include "gdbcmd.h" /* For maintenanceprintlist. */
/*
* DATA STRUCTURE
/* If an old style architecture, construct the register cache
description using all the register macros. */
- if (!gdbarch_register_read_p (gdbarch)
- && !gdbarch_register_write_p (gdbarch))
+ if (!gdbarch_pseudo_register_read_p (gdbarch)
+ && !gdbarch_pseudo_register_write_p (gdbarch))
return init_legacy_regcache_descr (gdbarch);
descr = XMALLOC (struct regcache_descr);
/* Construct a strictly RAW register cache. Don't allow pseudo's
into the register cache. */
descr->nr_raw_registers = NUM_REGS;
- descr->sizeof_raw_register_valid_p = NUM_REGS;
+
+ /* FIXME: cagney/2002-08-13: Overallocate the register_valid_p
+ array. This pretects GDB from erant code that accesses elements
+ of the global register_valid_p[] array in the range [NUM_REGS
+ .. NUM_REGS + NUM_PSEUDO_REGS). */
+ descr->sizeof_raw_register_valid_p = NUM_REGS + NUM_PSEUDO_REGS;
/* Lay out the register cache. The pseud-registers are included in
the layout even though their value isn't stored in the register
return regcache->raw_register_valid_p[regnum];
}
-CORE_ADDR
-regcache_raw_read_as_address (struct regcache *regcache, int regnum)
-{
- char *buf;
- gdb_assert (regcache != NULL);
- gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
- buf = alloca (regcache->descr->sizeof_register[regnum]);
- regcache_raw_read (regcache, regnum, buf);
- return extract_address (buf, regcache->descr->sizeof_register[regnum]);
-}
-
char *
deprecated_grub_regcache_for_registers (struct regcache *regcache)
{
void
set_register_cached (int regnum, int state)
{
- register_valid[regnum] = state;
+ gdb_assert (regnum >= 0);
+ gdb_assert (regnum < current_regcache->descr->nr_raw_registers);
+ current_regcache->raw_register_valid_p[regnum] = state;
}
/* REGISTER_CHANGED
return regnum >= 0 && regnum < NUM_REGS;
}
-/* Return whether register REGNUM is a pseudo register. */
-
-static int
-pseudo_register (int regnum)
-{
- return regnum >= NUM_REGS && regnum < NUM_REGS + NUM_PSEUDO_REGS;
-}
-
-/* Fetch register REGNUM into the cache. */
-
-static void
-fetch_register (int regnum)
-{
- /* NOTE: cagney/2001-12-04: Legacy targets were using fetch/store
- pseudo-register as a way of handling registers that needed to be
- constructed from one or more raw registers. New targets instead
- use gdbarch register read/write. */
- if (FETCH_PSEUDO_REGISTER_P ()
- && pseudo_register (regnum))
- FETCH_PSEUDO_REGISTER (regnum);
- else
- target_fetch_registers (regnum);
-}
-
-/* Write register REGNUM cached value to the target. */
-
-static void
-store_register (int regnum)
-{
- /* NOTE: cagney/2001-12-04: Legacy targets were using fetch/store
- pseudo-register as a way of handling registers that needed to be
- constructed from one or more raw registers. New targets instead
- use gdbarch register read/write. */
- if (STORE_PSEUDO_REGISTER_P ()
- && pseudo_register (regnum))
- STORE_PSEUDO_REGISTER (regnum);
- else
- target_store_registers (regnum);
-}
-
/* Low level examining and depositing of registers.
The caller is responsible for making sure that the inferior is
gdb gives control to the user (ie watchpoints). */
alloca (0);
- for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
+ for (i = 0; i < current_regcache->descr->nr_raw_registers; i++)
set_register_cached (i, 0);
if (registers_changed_hook)
}
if (!register_cached (regnum))
- fetch_register (regnum);
+ target_fetch_registers (regnum);
memcpy (myaddr, register_buffer (current_regcache, regnum),
REGISTER_RAW_SIZE (regnum));
registers_ptid = inferior_ptid;
}
if (!register_cached (regnum))
- fetch_register (regnum);
+ target_fetch_registers (regnum);
}
/* Copy the value directly into the register cache. */
memcpy (buf, (regcache->raw_registers
regcache->descr->sizeof_register[regnum]);
}
+void
+regcache_raw_read_signed (struct regcache *regcache, int regnum, LONGEST *val)
+{
+ char *buf;
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+ buf = alloca (regcache->descr->sizeof_register[regnum]);
+ regcache_raw_read (regcache, regnum, buf);
+ (*val) = extract_signed_integer (buf,
+ regcache->descr->sizeof_register[regnum]);
+}
+
+void
+regcache_raw_read_unsigned (struct regcache *regcache, int regnum,
+ ULONGEST *val)
+{
+ char *buf;
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+ buf = alloca (regcache->descr->sizeof_register[regnum]);
+ regcache_raw_read (regcache, regnum, buf);
+ (*val) = extract_unsigned_integer (buf,
+ regcache->descr->sizeof_register[regnum]);
+}
+
void
read_register_gen (int regnum, char *buf)
{
legacy_read_register_gen (regnum, buf);
return;
}
+ regcache_cooked_read (current_regcache, regnum, buf);
+}
+
+void
+regcache_cooked_read (struct regcache *regcache, int regnum, void *buf)
+{
gdb_assert (regnum >= 0);
- gdb_assert (regnum < current_regcache->descr->nr_cooked_registers);
- if (regnum < current_regcache->descr->nr_raw_registers)
- regcache_raw_read (current_regcache, regnum, buf);
+ gdb_assert (regnum < regcache->descr->nr_cooked_registers);
+ if (regnum < regcache->descr->nr_raw_registers)
+ regcache_raw_read (regcache, regnum, buf);
else
- gdbarch_register_read (current_gdbarch, regnum, buf);
+ gdbarch_pseudo_register_read (regcache->descr->gdbarch, regcache,
+ regnum, buf);
}
+void
+regcache_cooked_read_signed (struct regcache *regcache, int regnum,
+ LONGEST *val)
+{
+ char *buf;
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+ buf = alloca (regcache->descr->sizeof_register[regnum]);
+ regcache_cooked_read (regcache, regnum, buf);
+ (*val) = extract_signed_integer (buf,
+ regcache->descr->sizeof_register[regnum]);
+}
+
+void
+regcache_cooked_read_unsigned (struct regcache *regcache, int regnum,
+ ULONGEST *val)
+{
+ char *buf;
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
+ buf = alloca (regcache->descr->sizeof_register[regnum]);
+ regcache_cooked_read (regcache, regnum, buf);
+ (*val) = extract_unsigned_integer (buf,
+ regcache->descr->sizeof_register[regnum]);
+}
/* Write register REGNUM at MYADDR to the target. MYADDR points at
REGISTER_RAW_BYTES(REGNUM), which must be in target byte-order. */
memcpy (register_buffer (current_regcache, regnum), myaddr, size);
set_register_cached (regnum, 1);
- store_register (regnum);
+ target_store_registers (regnum);
}
void
memcpy (register_buffer (regcache, regnum), buf,
regcache->descr->sizeof_register[regnum]);
regcache->raw_register_valid_p[regnum] = 1;
- store_register (regnum);
+ target_store_registers (regnum);
}
void
legacy_write_register_gen (regnum, buf);
return;
}
+ regcache_cooked_write (current_regcache, regnum, buf);
+}
+
+void
+regcache_cooked_write (struct regcache *regcache, int regnum, const void *buf)
+{
gdb_assert (regnum >= 0);
- gdb_assert (regnum < current_regcache->descr->nr_cooked_registers);
- if (regnum < current_regcache->descr->nr_raw_registers)
- regcache_raw_write (current_regcache, regnum, buf);
+ gdb_assert (regnum < regcache->descr->nr_cooked_registers);
+ if (regnum < regcache->descr->nr_raw_registers)
+ regcache_raw_write (regcache, regnum, buf);
else
- gdbarch_register_write (current_gdbarch, regnum, buf);
+ gdbarch_pseudo_register_write (regcache->descr->gdbarch, regcache,
+ regnum, buf);
}
/* Copy INLEN bytes of consecutive data from memory at MYADDR
myaddr + (overlapstart - myregstart),
overlapend - overlapstart);
- store_register (regnum);
+ target_store_registers (regnum);
}
}
}
+/* Perform a partial register transfer using a read, modify, write
+ operation. */
+
+typedef void (regcache_read_ftype) (struct regcache *regcache, int regnum,
+ void *buf);
+typedef void (regcache_write_ftype) (struct regcache *regcache, int regnum,
+ const void *buf);
+
+void
+regcache_xfer_part (struct regcache *regcache, int regnum,
+ int offset, int len, void *in, const void *out,
+ regcache_read_ftype *read, regcache_write_ftype *write)
+{
+ struct regcache_descr *descr = regcache->descr;
+ bfd_byte *reg = alloca (descr->max_register_size);
+ gdb_assert (offset >= 0 && offset <= descr->sizeof_register[regnum]);
+ gdb_assert (len >= 0 && offset + len <= descr->sizeof_register[regnum]);
+ /* Something to do? */
+ if (offset + len == 0)
+ return;
+ /* Read (when needed) ... */
+ if (in != NULL
+ || offset > 0
+ || offset + len < descr->sizeof_register[regnum])
+ {
+ gdb_assert (read != NULL);
+ read (regcache, regnum, reg);
+ }
+ /* ... modify ... */
+ if (in != NULL)
+ memcpy (in, reg + offset, len);
+ if (out != NULL)
+ memcpy (reg + offset, out, len);
+ /* ... write (when needed). */
+ if (out != NULL)
+ {
+ gdb_assert (write != NULL);
+ write (regcache, regnum, reg);
+ }
+}
+
+void
+regcache_raw_read_part (struct regcache *regcache, int regnum,
+ int offset, int len, void *buf)
+{
+ struct regcache_descr *descr = regcache->descr;
+ gdb_assert (regnum >= 0 && regnum < descr->nr_raw_registers);
+ regcache_xfer_part (regcache, regnum, offset, len, buf, NULL,
+ regcache_raw_read, regcache_raw_write);
+}
+
+void
+regcache_raw_write_part (struct regcache *regcache, int regnum,
+ int offset, int len, const void *buf)
+{
+ struct regcache_descr *descr = regcache->descr;
+ gdb_assert (regnum >= 0 && regnum < descr->nr_raw_registers);
+ regcache_xfer_part (regcache, regnum, offset, len, NULL, buf,
+ regcache_raw_read, regcache_raw_write);
+}
+
+void
+regcache_cooked_read_part (struct regcache *regcache, int regnum,
+ int offset, int len, void *buf)
+{
+ struct regcache_descr *descr = regcache->descr;
+ gdb_assert (regnum >= 0 && regnum < descr->nr_cooked_registers);
+ regcache_xfer_part (regcache, regnum, offset, len, buf, NULL,
+ regcache_cooked_read, regcache_cooked_write);
+}
+
+void
+regcache_cooked_write_part (struct regcache *regcache, int regnum,
+ int offset, int len, const void *buf)
+{
+ struct regcache_descr *descr = regcache->descr;
+ gdb_assert (regnum >= 0 && regnum < descr->nr_cooked_registers);
+ regcache_xfer_part (regcache, regnum, offset, len, NULL, buf,
+ regcache_cooked_read, regcache_cooked_write);
+}
/* Return the contents of register REGNUM as an unsigned integer. */
/* NOTE: cagney/2001-03-16: The macro CLEAN_UP_REGISTER_VALUE is
going to be deprecated. Instead architectures will leave the raw
register value as is and instead clean things up as they pass
- through the method gdbarch_register_read() clean up the
+ through the method gdbarch_pseudo_register_read() clean up the
values. */
#ifdef DEPRECATED_CLEAN_UP_REGISTER_VALUE
register_valid = deprecated_grub_regcache_for_register_valid (current_regcache);
}
+static void
+dump_endian_bytes (struct ui_file *file, enum bfd_endian endian,
+ const unsigned char *buf, long len)
+{
+ int i;
+ switch (endian)
+ {
+ case BFD_ENDIAN_BIG:
+ for (i = 0; i < len; i++)
+ fprintf_unfiltered (file, "%02x", buf[i]);
+ break;
+ case BFD_ENDIAN_LITTLE:
+ for (i = len - 1; i >= 0; i--)
+ fprintf_unfiltered (file, "%02x", buf[i]);
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, "Bad switch");
+ }
+}
+
+enum regcache_dump_what
+{
+ regcache_dump_none, regcache_dump_raw, regcache_dump_cooked
+};
+
+static void
+regcache_dump (struct regcache *regcache, struct ui_file *file,
+ enum regcache_dump_what what_to_dump)
+{
+ struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
+ int regnum;
+ int footnote_nr = 0;
+ int footnote_register_size = 0;
+ int footnote_register_offset = 0;
+ int footnote_register_type_name_null = 0;
+ long register_offset = 0;
+ unsigned char *buf = alloca (regcache->descr->max_register_size);
+
+#if 0
+ fprintf_unfiltered (file, "legacy_p %d\n", regcache->descr->legacy_p);
+ fprintf_unfiltered (file, "nr_raw_registers %d\n",
+ regcache->descr->nr_raw_registers);
+ fprintf_unfiltered (file, "nr_cooked_registers %d\n",
+ regcache->descr->nr_cooked_registers);
+ fprintf_unfiltered (file, "sizeof_raw_registers %ld\n",
+ regcache->descr->sizeof_raw_registers);
+ fprintf_unfiltered (file, "sizeof_raw_register_valid_p %ld\n",
+ regcache->descr->sizeof_raw_register_valid_p);
+ fprintf_unfiltered (file, "max_register_size %ld\n",
+ regcache->descr->max_register_size);
+ fprintf_unfiltered (file, "NUM_REGS %d\n", NUM_REGS);
+ fprintf_unfiltered (file, "NUM_PSEUDO_REGS %d\n", NUM_PSEUDO_REGS);
+#endif
+
+ gdb_assert (regcache->descr->nr_cooked_registers
+ == (NUM_REGS + NUM_PSEUDO_REGS));
+
+ for (regnum = -1; regnum < regcache->descr->nr_cooked_registers; regnum++)
+ {
+ /* Name. */
+ if (regnum < 0)
+ fprintf_unfiltered (file, " %-10s", "Name");
+ else
+ {
+ const char *p = REGISTER_NAME (regnum);
+ if (p == NULL)
+ p = "";
+ else if (p[0] == '\0')
+ p = "''";
+ fprintf_unfiltered (file, " %-10s", p);
+ }
+
+ /* Number. */
+ if (regnum < 0)
+ fprintf_unfiltered (file, " %4s", "Nr");
+ else
+ fprintf_unfiltered (file, " %4d", regnum);
+
+ /* Relative number. */
+ if (regnum < 0)
+ fprintf_unfiltered (file, " %4s", "Rel");
+ else if (regnum < NUM_REGS)
+ fprintf_unfiltered (file, " %4d", regnum);
+ else
+ fprintf_unfiltered (file, " %4d", (regnum - NUM_REGS));
+
+ /* Offset. */
+ if (regnum < 0)
+ fprintf_unfiltered (file, " %6s ", "Offset");
+ else
+ {
+ fprintf_unfiltered (file, " %6ld",
+ regcache->descr->register_offset[regnum]);
+ if (register_offset != regcache->descr->register_offset[regnum]
+ || register_offset != REGISTER_BYTE (regnum))
+ {
+ if (!footnote_register_offset)
+ footnote_register_offset = ++footnote_nr;
+ fprintf_unfiltered (file, "*%d", footnote_register_offset);
+ }
+ else
+ fprintf_unfiltered (file, " ");
+ register_offset = (regcache->descr->register_offset[regnum]
+ + regcache->descr->sizeof_register[regnum]);
+ }
+
+ /* Size. */
+ if (regnum < 0)
+ fprintf_unfiltered (file, " %5s ", "Size");
+ else
+ {
+ fprintf_unfiltered (file, " %5ld",
+ regcache->descr->sizeof_register[regnum]);
+ if ((regcache->descr->sizeof_register[regnum]
+ != REGISTER_RAW_SIZE (regnum))
+ || (regcache->descr->sizeof_register[regnum]
+ != REGISTER_VIRTUAL_SIZE (regnum))
+ || (regcache->descr->sizeof_register[regnum]
+ != TYPE_LENGTH (REGISTER_VIRTUAL_TYPE (regnum)))
+ )
+ {
+ if (!footnote_register_size)
+ footnote_register_size = ++footnote_nr;
+ fprintf_unfiltered (file, "*%d", footnote_register_size);
+ }
+ else
+ fprintf_unfiltered (file, " ");
+ }
+
+ /* Type. */
+ if (regnum < 0)
+ fprintf_unfiltered (file, " %-20s", "Type");
+ else
+ {
+ static const char blt[] = "builtin_type";
+ const char *t = TYPE_NAME (REGISTER_VIRTUAL_TYPE (regnum));
+ if (t == NULL)
+ {
+ char *n;
+ if (!footnote_register_type_name_null)
+ footnote_register_type_name_null = ++footnote_nr;
+ xasprintf (&n, "*%d", footnote_register_type_name_null);
+ make_cleanup (xfree, n);
+ t = n;
+ }
+ /* Chop a leading builtin_type. */
+ if (strncmp (t, blt, strlen (blt)) == 0)
+ t += strlen (blt);
+ fprintf_unfiltered (file, " %-20s", t);
+ }
+
+ /* Value, raw. */
+ if (what_to_dump == regcache_dump_raw)
+ {
+ if (regnum < 0)
+ fprintf_unfiltered (file, "Raw value");
+ else if (regnum >= regcache->descr->nr_raw_registers)
+ fprintf_unfiltered (file, "<cooked>");
+ else if (!regcache_valid_p (regcache, regnum))
+ fprintf_unfiltered (file, "<invalid>");
+ else
+ {
+ regcache_raw_read (regcache, regnum, buf);
+ fprintf_unfiltered (file, "0x");
+ dump_endian_bytes (file, TARGET_BYTE_ORDER, buf,
+ REGISTER_RAW_SIZE (regnum));
+ }
+ }
+
+ /* Value, cooked. */
+ if (what_to_dump == regcache_dump_cooked)
+ {
+ if (regnum < 0)
+ fprintf_unfiltered (file, "Cooked value");
+ else
+ {
+ regcache_cooked_read (regcache, regnum, buf);
+ fprintf_unfiltered (file, "0x");
+ dump_endian_bytes (file, TARGET_BYTE_ORDER, buf,
+ REGISTER_VIRTUAL_SIZE (regnum));
+ }
+ }
+
+ fprintf_unfiltered (file, "\n");
+ }
+
+ if (footnote_register_size)
+ fprintf_unfiltered (file, "*%d: Inconsistent register sizes.\n",
+ footnote_register_size);
+ if (footnote_register_offset)
+ fprintf_unfiltered (file, "*%d: Inconsistent register offsets.\n",
+ footnote_register_offset);
+ if (footnote_register_type_name_null)
+ fprintf_unfiltered (file,
+ "*%d: Register type's name NULL.\n",
+ footnote_register_type_name_null);
+ do_cleanups (cleanups);
+}
+
+static void
+regcache_print (char *args, enum regcache_dump_what what_to_dump)
+{
+ if (args == NULL)
+ regcache_dump (current_regcache, gdb_stdout, what_to_dump);
+ else
+ {
+ struct ui_file *file = gdb_fopen (args, "w");
+ if (file == NULL)
+ perror_with_name ("maintenance print architecture");
+ regcache_dump (current_regcache, file, what_to_dump);
+ ui_file_delete (file);
+ }
+}
+
+static void
+maintenance_print_registers (char *args, int from_tty)
+{
+ regcache_print (args, regcache_dump_none);
+}
+
+static void
+maintenance_print_raw_registers (char *args, int from_tty)
+{
+ regcache_print (args, regcache_dump_raw);
+}
+
+static void
+maintenance_print_cooked_registers (char *args, int from_tty)
+{
+ regcache_print (args, regcache_dump_cooked);
+}
+
void
_initialize_regcache (void)
{
/* Initialize the thread/process associated with the current set of
registers. For now, -1 is special, and means `no current process'. */
registers_ptid = pid_to_ptid (-1);
+
+ add_cmd ("registers", class_maintenance,
+ maintenance_print_registers,
+ "Print the internal register configuration.\
+Takes an optional file parameter.",
+ &maintenanceprintlist);
+ add_cmd ("raw-registers", class_maintenance,
+ maintenance_print_raw_registers,
+ "Print the internal register configuration including raw values.\
+Takes an optional file parameter.",
+ &maintenanceprintlist);
+ add_cmd ("cooked-registers", class_maintenance,
+ maintenance_print_cooked_registers,
+ "Print the internal register configuration including cooked values.\
+Takes an optional file parameter.",
+ &maintenanceprintlist);
+
}