This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[RFC][2/2] Rework value_from_register
- From: "Ulrich Weigand" <uweigand at de dot ibm dot com>
- To: gdb-patches at sourceware dot org
- Cc: jimb at codesourcery dot com, drow at false dot org
- Date: Fri, 8 Dec 2006 16:51:44 +0100 (CET)
- Subject: [RFC][2/2] Rework value_from_register
Hello,
based on the value_from_register cleanup patch, this patch adds a new
gdbarch method, gdbarch_value_from_register, that back-ends can use
instead of convert_register_p / value_to_register / register_to_value.
The idea is that the gdbarch routine sets up the contents of the
struct value such that subsequently, common code is able to access
the register (including sub-values) without further interaction
with gdbarch methods.
This currently works only on spu and s390, because there we simply
need to set the proper value_offset, and everything else works
automatically.
In the future, assuming Jim's per-value read/write methods are
implemented, the gdbarch_value_from_register routine could set
those to effect any arbitrary change; that solution would then
completly replace the existing value_to_register / register_to_value.
Until that is implemented, I've left in the old way as well.
I've considered one interface alternative; the patch below has
common code generate the struct value and fill in default values;
the gdbarch_value_from_register routine gets the struct value is
may change things as appropriate. The alternative would be to
have gdbarch_value_from_register fully construct the value
itself (possibly falling back on a common helper routine).
Any preference on that question?
Tested without regressions on spu-elf, s390-ibm-linux, s390x-ibm-linux.
Fixes all the currently existing sub-value problems on spu.
Bye,
Ulrich
ChangeLog:
* gdbarch.sh (value_from_register): New gdbarch function.
* gdbarch.c, gdbarch.h: Regenerate.
* findvar.c (default_value_from_register): New function.
(value_from_register): Use gdbarch_value_from_register.
* value.h (default_value_from_register): Declare.
* spu-tdep.c (spu_convert_register_p, spu_register_to_value,
spu_value_to_register): Remove.
(spu_value_from_register): New function.
(spu_gdbarch_init): Do not call set_gdbarch_convert_register_p,
set_gdbarch_register_to_value, set_gdbarch_value_to_register.
Call set_gdbarch_value_from_register.
* s390-tdep.c (s390_convert_register_p, s390_register_to_value,
s390_value_to_register): Remove.
(s390_value_from_register): New function.
(s390_gdbarch_init): Do not call set_gdbarch_convert_register_p,
set_gdbarch_register_to_value, set_gdbarch_value_to_register.
Call set_gdbarch_value_from_register.
diff -urp gdb-orig/gdb/findvar.c gdb-head/gdb/findvar.c
diff -urp gdb-orig/gdb/findvar.c gdb-head/gdb/findvar.c
--- gdb-orig/gdb/findvar.c 2006-12-08 14:54:18.000000000 +0100
+++ gdb-head/gdb/findvar.c 2006-12-08 15:27:51.647466736 +0100
@@ -599,6 +599,26 @@ addresses have not been bound by the dyn
return v;
}
+/* Install default attributes for register values. */
+
+void
+default_value_from_register (struct gdbarch *gdbarch, struct value *value)
+{
+ int len = TYPE_LENGTH (value_type (value));
+ int regnum = VALUE_REGNUM (value);
+
+ /* Any structure stored in more than one register will always be
+ an integral number of registers. Otherwise, you need to do
+ some fiddling with the last register copied here for little
+ endian machines. */
+ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+ && len < register_size (gdbarch, regnum))
+ /* Big-endian, and we want less than full size. */
+ set_value_offset (value, register_size (gdbarch, regnum) - len);
+ else
+ set_value_offset (value, 0);
+}
+
/* Return a value of type TYPE, stored in register REGNUM, in frame FRAME. */
struct value *
@@ -628,16 +648,8 @@ value_from_register (struct type *type,
struct gdbarch *gdbarch = get_frame_arch (frame);
int len = TYPE_LENGTH (type);
- /* Any structure stored in more than one register will always be
- an integral number of registers. Otherwise, you need to do
- some fiddling with the last register copied here for little
- endian machines. */
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
- && len < register_size (gdbarch, regnum))
- /* Big-endian, and we want less than full size. */
- set_value_offset (v, register_size (gdbarch, regnum) - len);
- else
- set_value_offset (v, 0);
+ /* Install value attributes. */
+ gdbarch_value_from_register (gdbarch, v);
/* Get the data. */
if (!get_frame_register_bytes (frame, regnum, value_offset (v), len,
diff -urp gdb-orig/gdb/gdbarch.c gdb-head/gdb/gdbarch.c
--- gdb-orig/gdb/gdbarch.c 2006-12-08 14:38:45.000000000 +0100
+++ gdb-head/gdb/gdbarch.c 2006-12-08 15:19:20.115487104 +0100
@@ -183,6 +183,7 @@ struct gdbarch
gdbarch_convert_register_p_ftype *convert_register_p;
gdbarch_register_to_value_ftype *register_to_value;
gdbarch_value_to_register_ftype *value_to_register;
+ gdbarch_value_from_register_ftype *value_from_register;
gdbarch_pointer_to_address_ftype *pointer_to_address;
gdbarch_address_to_pointer_ftype *address_to_pointer;
gdbarch_integer_to_address_ftype *integer_to_address;
@@ -309,6 +310,7 @@ struct gdbarch startup_gdbarch =
0, /* convert_register_p */
0, /* register_to_value */
0, /* value_to_register */
+ default_value_from_register, /* value_from_register */
0, /* pointer_to_address */
0, /* address_to_pointer */
0, /* integer_to_address */
@@ -429,6 +431,7 @@ gdbarch_alloc (const struct gdbarch_info
current_gdbarch->cannot_fetch_register = cannot_register_not;
current_gdbarch->cannot_store_register = cannot_register_not;
current_gdbarch->convert_register_p = generic_convert_register_p;
+ current_gdbarch->value_from_register = default_value_from_register;
current_gdbarch->pointer_to_address = unsigned_pointer_to_address;
current_gdbarch->address_to_pointer = unsigned_address_to_pointer;
current_gdbarch->return_value = legacy_return_value;
@@ -562,6 +565,8 @@ verify_gdbarch (struct gdbarch *current_
/* Skip verify of cannot_store_register, invalid_p == 0 */
/* Skip verify of get_longjmp_target, has predicate */
/* Skip verify of convert_register_p, invalid_p == 0 */
+ if (current_gdbarch->value_from_register == default_value_from_register)
+ fprintf_unfiltered (log, "\n\tvalue_from_register");
/* Skip verify of pointer_to_address, invalid_p == 0 */
/* Skip verify of address_to_pointer, invalid_p == 0 */
/* Skip verify of integer_to_address, has predicate */
@@ -1586,6 +1591,9 @@ gdbarch_dump (struct gdbarch *current_gd
fprintf_unfiltered (file,
"gdbarch_dump: unwind_sp = <0x%lx>\n",
(long) current_gdbarch->unwind_sp);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: value_from_register = <0x%lx>\n",
+ (long) current_gdbarch->value_from_register);
#ifdef VALUE_TO_REGISTER
fprintf_unfiltered (file,
"gdbarch_dump: %s # %s\n",
@@ -2636,6 +2644,23 @@ set_gdbarch_value_to_register (struct gd
gdbarch->value_to_register = value_to_register;
}
+void
+gdbarch_value_from_register (struct gdbarch *gdbarch, struct value *value)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->value_from_register != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_value_from_register called\n");
+ gdbarch->value_from_register (gdbarch, value);
+}
+
+void
+set_gdbarch_value_from_register (struct gdbarch *gdbarch,
+ gdbarch_value_from_register_ftype value_from_register)
+{
+ gdbarch->value_from_register = value_from_register;
+}
+
CORE_ADDR
gdbarch_pointer_to_address (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf)
{
diff -urp gdb-orig/gdb/gdbarch.h gdb-head/gdb/gdbarch.h
--- gdb-orig/gdb/gdbarch.h 2006-12-08 14:38:45.000000000 +0100
+++ gdb-head/gdb/gdbarch.h 2006-12-08 15:19:00.783497440 +0100
@@ -704,6 +704,10 @@ extern void set_gdbarch_value_to_registe
#define VALUE_TO_REGISTER(frame, regnum, type, buf) (gdbarch_value_to_register (current_gdbarch, frame, regnum, type, buf))
#endif
+typedef void (gdbarch_value_from_register_ftype) (struct gdbarch *gdbarch, struct value *value);
+extern void gdbarch_value_from_register (struct gdbarch *gdbarch, struct value *value);
+extern void set_gdbarch_value_from_register (struct gdbarch *gdbarch, gdbarch_value_from_register_ftype *value_from_register);
+
typedef CORE_ADDR (gdbarch_pointer_to_address_ftype) (struct type *type, const gdb_byte *buf);
extern CORE_ADDR gdbarch_pointer_to_address (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf);
extern void set_gdbarch_pointer_to_address (struct gdbarch *gdbarch, gdbarch_pointer_to_address_ftype *pointer_to_address);
diff -urp gdb-orig/gdb/gdbarch.sh gdb-head/gdb/gdbarch.sh
--- gdb-orig/gdb/gdbarch.sh 2006-12-08 14:38:45.000000000 +0100
+++ gdb-head/gdb/gdbarch.sh 2006-12-08 15:18:51.648421896 +0100
@@ -496,6 +496,7 @@ v:=:int:believe_pcc_promotion:::::::
f:=:int:convert_register_p:int regnum, struct type *type:regnum, type:0:generic_convert_register_p::0
f:=:void:register_to_value:struct frame_info *frame, int regnum, struct type *type, gdb_byte *buf:frame, regnum, type, buf:0
f:=:void:value_to_register:struct frame_info *frame, int regnum, struct type *type, const gdb_byte *buf:frame, regnum, type, buf:0
+m::void:value_from_register:struct value *value:value::default_value_from_register
#
f:=:CORE_ADDR:pointer_to_address:struct type *type, const gdb_byte *buf:type, buf::unsigned_pointer_to_address::0
f:=:void:address_to_pointer:struct type *type, gdb_byte *buf, CORE_ADDR addr:type, buf, addr::unsigned_address_to_pointer::0
diff -urp gdb-orig/gdb/s390-tdep.c gdb-head/gdb/s390-tdep.c
--- gdb-orig/gdb/s390-tdep.c 2006-11-28 21:46:03.000000000 +0100
+++ gdb-head/gdb/s390-tdep.c 2006-12-08 15:28:09.919485824 +0100
@@ -306,36 +306,16 @@ s390x_pseudo_register_write (struct gdba
/* 'float' values are stored in the upper half of floating-point
registers, even though we are otherwise a big-endian platform. */
-static int
-s390_convert_register_p (int regno, struct type *type)
-{
- return (regno >= S390_F0_REGNUM && regno <= S390_F15_REGNUM)
- && TYPE_LENGTH (type) < 8;
-}
-
static void
-s390_register_to_value (struct frame_info *frame, int regnum,
- struct type *valtype, gdb_byte *out)
+s390_value_from_register (struct gdbarch *gdbarch, struct value *value)
{
- gdb_byte in[8];
- int len = TYPE_LENGTH (valtype);
- gdb_assert (len < 8);
+ int len = TYPE_LENGTH (value_type (value));
+ int regnum = VALUE_REGNUM (value);
- get_frame_register (frame, regnum, in);
- memcpy (out, in, len);
-}
+ default_value_from_register (gdbarch, value);
-static void
-s390_value_to_register (struct frame_info *frame, int regnum,
- struct type *valtype, const gdb_byte *in)
-{
- gdb_byte out[8];
- int len = TYPE_LENGTH (valtype);
- gdb_assert (len < 8);
-
- memset (out, 0, 8);
- memcpy (out, in, len);
- put_frame_register (frame, regnum, out);
+ if (regnum >= S390_F0_REGNUM && regnum <= S390_F15_REGNUM && len < 8)
+ set_value_offset (value, 0);
}
/* Register groups. */
@@ -2411,9 +2391,7 @@ s390_gdbarch_init (struct gdbarch_info i
set_gdbarch_stab_reg_to_regnum (gdbarch, s390_dwarf_reg_to_regnum);
set_gdbarch_dwarf_reg_to_regnum (gdbarch, s390_dwarf_reg_to_regnum);
set_gdbarch_dwarf2_reg_to_regnum (gdbarch, s390_dwarf_reg_to_regnum);
- set_gdbarch_convert_register_p (gdbarch, s390_convert_register_p);
- set_gdbarch_register_to_value (gdbarch, s390_register_to_value);
- set_gdbarch_value_to_register (gdbarch, s390_value_to_register);
+ set_gdbarch_value_from_register (gdbarch, s390_value_from_register);
set_gdbarch_register_reggroup_p (gdbarch, s390_register_reggroup_p);
set_gdbarch_regset_from_core_section (gdbarch,
s390_regset_from_core_section);
diff -urp gdb-orig/gdb/spu-tdep.c gdb-head/gdb/spu-tdep.c
--- gdb-orig/gdb/spu-tdep.c 2006-11-24 15:00:40.000000000 +0100
+++ gdb-head/gdb/spu-tdep.c 2006-12-08 15:28:21.653433624 +0100
@@ -143,37 +143,19 @@ spu_pseudo_register_write (struct gdbarc
/* Value conversion -- access scalar values at the preferred slot. */
-static int
-spu_convert_register_p (int regno, struct type *type)
-{
- return regno < SPU_NUM_GPRS && TYPE_LENGTH (type) < 16;
-}
-
static void
-spu_register_to_value (struct frame_info *frame, int regnum,
- struct type *valtype, gdb_byte *out)
+spu_value_from_register (struct gdbarch *gdbarch, struct value *value)
{
- gdb_byte in[16];
- int len = TYPE_LENGTH (valtype);
- int preferred_slot = len < 4 ? 4 - len : 0;
- gdb_assert (len < 16);
+ int len = TYPE_LENGTH (value_type (value));
+ int regnum = VALUE_REGNUM (value);
- get_frame_register (frame, regnum, in);
- memcpy (out, in + preferred_slot, len);
-}
+ default_value_from_register (gdbarch, value);
-static void
-spu_value_to_register (struct frame_info *frame, int regnum,
- struct type *valtype, const gdb_byte *in)
-{
- gdb_byte out[16];
- int len = TYPE_LENGTH (valtype);
- int preferred_slot = len < 4 ? 4 - len : 0;
- gdb_assert (len < 16);
-
- memset (out, 0, 16);
- memcpy (out + preferred_slot, in, len);
- put_frame_register (frame, regnum, out);
+ if (regnum < SPU_NUM_GPRS && len < 16)
+ {
+ int preferred_slot = len < 4 ? 4 - len : 0;
+ set_value_offset (value, preferred_slot);
+ }
}
/* Register groups. */
@@ -1048,9 +1030,7 @@ spu_gdbarch_init (struct gdbarch_info in
set_gdbarch_register_type (gdbarch, spu_register_type);
set_gdbarch_pseudo_register_read (gdbarch, spu_pseudo_register_read);
set_gdbarch_pseudo_register_write (gdbarch, spu_pseudo_register_write);
- set_gdbarch_convert_register_p (gdbarch, spu_convert_register_p);
- set_gdbarch_register_to_value (gdbarch, spu_register_to_value);
- set_gdbarch_value_to_register (gdbarch, spu_value_to_register);
+ set_gdbarch_value_from_register (gdbarch, spu_value_from_register);
set_gdbarch_register_reggroup_p (gdbarch, spu_register_reggroup_p);
/* Data types. */
diff -urp gdb-orig/gdb/value.h gdb-head/gdb/value.h
--- gdb-orig/gdb/value.h 2006-11-24 17:56:28.000000000 +0100
+++ gdb-head/gdb/value.h 2006-12-08 15:20:29.836407912 +0100
@@ -279,6 +279,9 @@ extern struct value *value_from_string (
extern struct value *value_at (struct type *type, CORE_ADDR addr);
extern struct value *value_at_lazy (struct type *type, CORE_ADDR addr);
+extern void default_value_from_register (struct gdbarch *gdbarch,
+ struct value *value);
+
extern struct value *value_from_register (struct type *type, int regnum,
struct frame_info *frame);
--
Dr. Ulrich Weigand
GNU Toolchain for Linux on System z and Cell BE
Ulrich.Weigand@de.ibm.com