summaryrefslogtreecommitdiff
path: root/gdb/findvar.c
diff options
context:
space:
mode:
authorUlrich Weigand <ulrich.weigand@de.ibm.com>2014-04-17 14:01:39 +0200
committerUlrich Weigand <ulrich.weigand@de.ibm.com>2014-04-17 14:01:39 +0200
commit2ed3c037cf8aac5f6dbee5b6c2a1239550a04202 (patch)
tree5c7c719b409ed8d6dae53fe30fcf72eeef4dec0e /gdb/findvar.c
parent40d1a503c43cda6c04a637972e5635d803f46cde (diff)
Use address_from_register in dwarf2-frame.c:read_addr_from_reg
This patch fixes a problem that prevented use of the Dwarf unwinders on SPU, because dwarf2-frame.c common code did not support the situation where the stack and/or frame pointer is maintained in a *vector* register. This is because read_addr_from_reg is hard-coded to assume that such pointers can be read from registers via a simple get_frame_register / unpack_pointer operation. Now, there *is* a routine address_from_register that calls into the appropriate tdep routines to handle pointer values in "weird" registers like on SPU, but it turns out I cannot simply change dwarf2-frame.c to use address_from_register. This is because address_from_register uses value_from_register to create a (temporary) value, and that routine at some point calls get_frame_id in order to set up that value's VALUE_FRAME_ID entry. However, the dwarf2-frame.c read_addr_from_reg routine will be called during early unwinding (to unwind the frame's CFA), at which point the frame's ID is not actually known yet! This would cause an assert. On the other hand, we may notice that VALUE_FRAME_ID is only needed in the value returned by value_from_register if that value is later used as an lvalue. But this is obviously never done to the temporary value used in address_from_register. So, if we could change address_from_register to not call value_from_register but instead accept constructing a value that doesn't have VALUE_FRAME_ID set, things should be fine. To do that, we can change the value_from_register callback to accept a FRAME_ID instead of a FRAME; the only existing uses of the FRAME argument were either to extract its frame ID, or its gdbarch. (To keep a way of getting at the latter, we also change the callback's type from "f" to "m".) Together with the required follow-on changes in the existing value_from_register implementations (including the default one), this seems to fix the problem. As another minor interface cleanup, I've removed the explicit TYPE argument from address_from_register. This routine really always uses a default pointer type, and in the new implementation it -to some extent- relies on that fact, in that it will now no longer handle types that require gdbarch_convert_register_p handling. gdb: 2014-04-17 Ulrich Weigand  <uweigand@de.ibm.com> * gdbarch.sh (value_from_register): Make class "m" instead of "f". Replace FRAME argument with FRAME_ID. * gdbarch.c, gdbarch.h: Regenerate. * findvar.c (default_value_from_register): Add GDBARCH argument; replace FRAME by FRAME_ID. No longer call get_frame_id. (value_from_register): Update call to gdbarch_value_from_register. * value.h (default_value_from_register): Update prototype. * s390-linux-tdep.c (s390_value_from_register): Update interface and call to default_value_from_register. * spu-tdep.c (spu_value_from_register): Likewise. * findvar.c (address_from_register): Remove TYPE argument. Do not call value_from_register; use gdbarch_value_from_register with null_frame_id instead. * value.h (address_from_register): Update prototype. * dwarf2-frame.c (read_addr_from_reg): Use address_from_register. * dwarf2loc.c (dwarf_expr_read_addr_from_reg): Update for address_from_register interface change.
Diffstat (limited to 'gdb/findvar.c')
-rw-r--r--gdb/findvar.c34
1 files changed, 23 insertions, 11 deletions
diff --git a/gdb/findvar.c b/gdb/findvar.c
index 998a799e3b..9390c8a7b8 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -625,15 +625,14 @@ read_var_value (struct symbol *var, struct frame_info *frame)
/* Install default attributes for register values. */
struct value *
-default_value_from_register (struct type *type, int regnum,
- struct frame_info *frame)
+default_value_from_register (struct gdbarch *gdbarch, struct type *type,
+ int regnum, struct frame_id frame_id)
{
- struct gdbarch *gdbarch = get_frame_arch (frame);
int len = TYPE_LENGTH (type);
struct value *value = allocate_value (type);
VALUE_LVAL (value) = lval_register;
- VALUE_FRAME_ID (value) = get_frame_id (frame);
+ VALUE_FRAME_ID (value) = frame_id;
VALUE_REGNUM (value) = regnum;
/* Any structure stored in more than one register will always be
@@ -741,7 +740,8 @@ value_from_register (struct type *type, int regnum, struct frame_info *frame)
else
{
/* Construct the value. */
- v = gdbarch_value_from_register (gdbarch, type, regnum, frame);
+ v = gdbarch_value_from_register (gdbarch, type,
+ regnum, get_frame_id (frame));
/* Get the data. */
read_frame_register_value (v, frame);
@@ -750,18 +750,30 @@ value_from_register (struct type *type, int regnum, struct frame_info *frame)
return v;
}
-/* Return contents of register REGNUM in frame FRAME as address,
- interpreted as value of type TYPE. Will abort if register
- value is not available. */
+/* Return contents of register REGNUM in frame FRAME as address.
+ Will abort if register value is not available. */
CORE_ADDR
-address_from_register (struct type *type, int regnum, struct frame_info *frame)
+address_from_register (int regnum, struct frame_info *frame)
{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct type *type = builtin_type (gdbarch)->builtin_data_ptr;
struct value *value;
CORE_ADDR result;
- value = value_from_register (type, regnum, frame);
- gdb_assert (value);
+ /* This routine may be called during early unwinding, at a time
+ where the ID of FRAME is not yet known. Calling value_from_register
+ would therefore abort in get_frame_id. However, since we only need
+ a temporary value that is never used as lvalue, we actually do not
+ really need to set its VALUE_FRAME_ID. Therefore, we re-implement
+ the core of value_from_register, but use the null_frame_id.
+
+ This works only if we do not require a special conversion routine,
+ which is true for plain pointer types for all current targets. */
+ gdb_assert (!gdbarch_convert_register_p (gdbarch, regnum, type));
+
+ value = gdbarch_value_from_register (gdbarch, type, regnum, null_frame_id);
+ read_frame_register_value (value, frame);
if (value_optimized_out (value))
{