aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog7
-rw-r--r--gdb/regcache.h21
-rw-r--r--gdb/trad-frame.c57
-rw-r--r--gdb/trad-frame.h4
4 files changed, 87 insertions, 2 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 2bbccd5..1862ea4 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,10 @@
+2018-10-08 John Baldwin <jhb@FreeBSD.org>
+
+ * regcache.h (struct regcache_map_entry): Note that this type can
+ be used with traditional frame caches.
+ * trad-frame.c (trad_frame_set_reg_regmap): New.
+ * trad-frame.h (trad_frame_set_reg_regmap): New.
+
2018-10-08 Weimin Pan <weimin.pan@oracle.com>
PR c++/16841
diff --git a/gdb/regcache.h b/gdb/regcache.h
index 4a45f33..374826c 100644
--- a/gdb/regcache.h
+++ b/gdb/regcache.h
@@ -72,14 +72,31 @@ extern void regcache_cooked_write_unsigned (struct regcache *regcache,
extern void regcache_write_pc (struct regcache *regcache, CORE_ADDR pc);
/* Mapping between register numbers and offsets in a buffer, for use
- in the '*regset' functions below. In an array of
- 'regcache_map_entry' each element is interpreted like follows:
+ in the '*regset' functions below and with traditional frame caches.
+ In an array of 'regcache_map_entry' each element is interpreted
+ like follows:
- If 'regno' is a register number: Map register 'regno' to the
current offset (starting with 0) and increase the current offset
by 'size' (or the register's size, if 'size' is zero). Repeat
this with consecutive register numbers up to 'regno+count-1'.
+ For each described register, if 'size' is larger than the
+ register's size, the register's value is assumed to be stored in
+ the first N (where N is the register size) bytes at the current
+ offset. The remaining 'size' - N bytes are filled with zeroes by
+ 'regcache_collect_regset' and ignored by other consumers.
+
+ If 'size' is smaller than the register's size, only the first
+ 'size' bytes of a register's value are assumed to be stored at
+ the current offset. 'regcache_collect_regset' copies the first
+ 'size' bytes of a register's value to the output buffer.
+ 'regcache_supply_regset' copies the bytes from the input buffer
+ into the first 'size' bytes of the register's value leaving the
+ remaining bytes of the register's value unchanged. Frame caches
+ read the 'size' bytes from the stack frame and zero extend them
+ to generate the register's value.
+
- If 'regno' is REGCACHE_MAP_SKIP: Add 'count*size' to the current
offset.
diff --git a/gdb/trad-frame.c b/gdb/trad-frame.c
index fd9f240..a3484d2 100644
--- a/gdb/trad-frame.c
+++ b/gdb/trad-frame.c
@@ -22,6 +22,7 @@
#include "trad-frame.h"
#include "regcache.h"
#include "frame-unwind.h"
+#include "target.h"
#include "value.h"
struct trad_frame_cache
@@ -149,6 +150,62 @@ trad_frame_set_reg_addr (struct trad_frame_cache *this_trad_cache,
}
void
+trad_frame_set_reg_regmap (struct trad_frame_cache *this_trad_cache,
+ const struct regcache_map_entry *regmap,
+ CORE_ADDR addr, size_t size)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_trad_cache->this_frame);
+ int offs = 0, count;
+
+ for (; (count = regmap->count) != 0; regmap++)
+ {
+ int regno = regmap->regno;
+ int slot_size = regmap->size;
+
+ if (slot_size == 0 && regno != REGCACHE_MAP_SKIP)
+ slot_size = register_size (gdbarch, regno);
+
+ if (offs + slot_size > size)
+ break;
+
+ if (regno == REGCACHE_MAP_SKIP)
+ offs += count * slot_size;
+ else
+ for (; count--; regno++, offs += slot_size)
+ {
+ /* Mimic the semantics of regcache::transfer_regset if a
+ register slot's size does not match the size of a
+ register.
+
+ If a register slot is larger than a register, assume
+ the register's value is stored in the first N bytes of
+ the slot and ignore the remaining bytes.
+
+ If the register slot is smaller than the register,
+ assume that the slot contains the low N bytes of the
+ register's value. Since trad_frame assumes that
+ registers stored by address are sized according to the
+ register, read the low N bytes and zero-extend them to
+ generate a register value. */
+ if (slot_size >= register_size (gdbarch, regno))
+ trad_frame_set_reg_addr (this_trad_cache, regno, addr + offs);
+ else
+ {
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ gdb_byte buf[slot_size];
+
+ if (target_read_memory (addr + offs, buf, sizeof buf) == 0)
+ {
+ LONGEST val
+ = extract_unsigned_integer (buf, sizeof buf, byte_order);
+ trad_frame_set_reg_value (this_trad_cache, regno, val);
+ }
+ }
+ }
+ }
+}
+
+void
trad_frame_set_unknown (struct trad_frame_saved_reg this_saved_regs[],
int regnum)
{
diff --git a/gdb/trad-frame.h b/gdb/trad-frame.h
index a11a2c2..0d04bf4 100644
--- a/gdb/trad-frame.h
+++ b/gdb/trad-frame.h
@@ -23,6 +23,7 @@
#include "frame.h" /* For "struct frame_id". */
struct frame_info;
+struct regcache_map_entry;
struct trad_frame_cache;
/* A simple, or traditional frame cache.
@@ -45,6 +46,9 @@ void trad_frame_set_reg_realreg (struct trad_frame_cache *this_trad_cache,
int regnum, int realreg);
void trad_frame_set_reg_addr (struct trad_frame_cache *this_trad_cache,
int regnum, CORE_ADDR addr);
+void trad_frame_set_reg_regmap (struct trad_frame_cache *this_trad_cache,
+ const struct regcache_map_entry *regmap,
+ CORE_ADDR addr, size_t size);
void trad_frame_set_reg_value (struct trad_frame_cache *this_cache,
int regnum, LONGEST val);