diff options
author | Daniel Jacobowitz <drow@false.org> | 2009-07-21 18:15:32 +0000 |
---|---|---|
committer | Daniel Jacobowitz <drow@false.org> | 2009-07-21 18:15:32 +0000 |
commit | 4ea48cc1cd4875e570047f5aff70387018a56645 (patch) | |
tree | 35e518fe24754a9342c08045ba1718d8e0c44f81 /gdb/value.c | |
parent | 828d3400fb1a9914ab16ee05dfe2647af8c566c5 (diff) | |
download | gdb-4ea48cc1cd4875e570047f5aff70387018a56645.zip gdb-4ea48cc1cd4875e570047f5aff70387018a56645.tar.gz gdb-4ea48cc1cd4875e570047f5aff70387018a56645.tar.bz2 |
gdb/
* valops.c (value_fetch_lazy): Handle bitfields explicitly.
(value_assign): Remove unnecessary FIXME. Honor the container
type of bitfields if possible.
* value.c (struct value): Add parent field.
(value_parent): New function.
(value_free): Free the parent also.
(value_copy): Copy the parent also.
(value_primitive_field): Do not read the contents of a lazy
value to create a child bitfield value. Set bitpos and offset
according to the container type if possible.
(unpack_bits_as_long): Rename from unpack_field_as_long. Take
field_type, bitpos, and bitsize instead of type and fieldno.
(unpack_field_as_long): Use unpack_bits_as_long.
* value.h (value_parent, unpack_bits_as_long): New prototypes.
Diffstat (limited to 'gdb/value.c')
-rw-r--r-- | gdb/value.c | 77 |
1 files changed, 60 insertions, 17 deletions
diff --git a/gdb/value.c b/gdb/value.c index 904bd5e..65a5aa9 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -108,6 +108,11 @@ struct value gdbarch_bits_big_endian=1 targets, it is the position of the MSB. */ int bitpos; + /* Only used for bitfields; the containing value. This allows a + single read from the target when displaying multiple + bitfields. */ + struct value *parent; + /* Frame register value is relative to. This will be described in the lval enum above as "lval_register". */ struct frame_id frame_id; @@ -398,6 +403,12 @@ set_value_bitsize (struct value *value, int bit) value->bitsize = bit; } +struct value * +value_parent (struct value *value) +{ + return value->parent; +} + gdb_byte * value_contents_raw (struct value *value) { @@ -617,6 +628,11 @@ value_free (struct value *val) if (val->reference_count > 0) return; + /* If there's an associated parent value, drop our reference to + it. */ + if (val->parent != NULL) + value_free (val->parent); + if (VALUE_LVAL (val) == lval_computed) { struct lval_funcs *funcs = val->location.computed.funcs; @@ -739,6 +755,9 @@ value_copy (struct value *arg) TYPE_LENGTH (value_enclosing_type (arg))); } + val->parent = arg->parent; + if (val->parent) + value_incref (val->parent); if (VALUE_LVAL (val) == lval_computed) { struct lval_funcs *funcs = val->location.computed.funcs; @@ -1861,15 +1880,28 @@ value_primitive_field (struct value *arg1, int offset, if (TYPE_FIELD_BITSIZE (arg_type, fieldno)) { - v = value_from_longest (type, - unpack_field_as_long (arg_type, - value_contents (arg1) - + offset, - fieldno)); - v->bitpos = TYPE_FIELD_BITPOS (arg_type, fieldno) % 8; + /* Create a new value for the bitfield, with bitpos and bitsize + set. If possible, arrange offset and bitpos so that we can + do a single aligned read of the size of the containing type. + Otherwise, adjust offset to the byte containing the first + bit. Assume that the address, offset, and embedded offset + are sufficiently aligned. */ + int bitpos = TYPE_FIELD_BITPOS (arg_type, fieldno); + int container_bitsize = TYPE_LENGTH (type) * 8; + + v = allocate_value_lazy (type); v->bitsize = TYPE_FIELD_BITSIZE (arg_type, fieldno); - v->offset = value_offset (arg1) + offset - + TYPE_FIELD_BITPOS (arg_type, fieldno) / 8; + if ((bitpos % container_bitsize) + v->bitsize <= container_bitsize + && TYPE_LENGTH (type) <= (int) sizeof (LONGEST)) + v->bitpos = bitpos % container_bitsize; + else + v->bitpos = bitpos % 8; + v->offset = value_offset (arg1) + value_embedded_offset (arg1) + + (bitpos - v->bitpos) / 8; + v->parent = arg1; + value_incref (v->parent); + if (!value_lazy (arg1)) + value_fetch_lazy (v); } else if (fieldno < TYPE_N_BASECLASSES (arg_type)) { @@ -1994,8 +2026,9 @@ value_fn_field (struct value **arg1p, struct fn_field *f, int j, struct type *ty } -/* Unpack a field FIELDNO of the specified TYPE, from the anonymous object at - VALADDR. +/* Unpack a bitfield of the specified FIELD_TYPE, from the anonymous + object at VALADDR. The bitfield starts at BITPOS bits and contains + BITSIZE bits. Extracting bits depends on endianness of the machine. Compute the number of least significant bits to discard. For big endian machines, @@ -2009,24 +2042,21 @@ value_fn_field (struct value **arg1p, struct fn_field *f, int j, struct type *ty If the field is signed, we also do sign extension. */ LONGEST -unpack_field_as_long (struct type *type, const gdb_byte *valaddr, int fieldno) +unpack_bits_as_long (struct type *field_type, const gdb_byte *valaddr, + int bitpos, int bitsize) { - enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type)); + enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (field_type)); ULONGEST val; ULONGEST valmask; - int bitpos = TYPE_FIELD_BITPOS (type, fieldno); - int bitsize = TYPE_FIELD_BITSIZE (type, fieldno); int lsbcount; - struct type *field_type; val = extract_unsigned_integer (valaddr + bitpos / 8, sizeof (val), byte_order); - field_type = TYPE_FIELD_TYPE (type, fieldno); CHECK_TYPEDEF (field_type); /* Extract bits. See comment above. */ - if (gdbarch_bits_big_endian (get_type_arch (type))) + if (gdbarch_bits_big_endian (get_type_arch (field_type))) lsbcount = (sizeof val * 8 - bitpos % 8 - bitsize); else lsbcount = (bitpos % 8); @@ -2050,6 +2080,19 @@ unpack_field_as_long (struct type *type, const gdb_byte *valaddr, int fieldno) return (val); } +/* Unpack a field FIELDNO of the specified TYPE, from the anonymous object at + VALADDR. See unpack_bits_as_long for more details. */ + +LONGEST +unpack_field_as_long (struct type *type, const gdb_byte *valaddr, int fieldno) +{ + int bitpos = TYPE_FIELD_BITPOS (type, fieldno); + int bitsize = TYPE_FIELD_BITSIZE (type, fieldno); + struct type *field_type = TYPE_FIELD_TYPE (type, fieldno); + + return unpack_bits_as_long (field_type, valaddr, bitpos, bitsize); +} + /* Modify the value of a bitfield. ADDR points to a block of memory in target byte order; the bitfield starts in the byte pointed to. FIELDVAL is the desired value of the field, in host byte order. BITPOS and BITSIZE |