* 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.
This commit is contained in:
Daniel Jacobowitz 2009-07-21 18:15:32 +00:00
parent 828d3400fb
commit 4ea48cc1cd
4 changed files with 114 additions and 20 deletions

View File

@ -1,3 +1,21 @@
2009-07-21 Daniel Jacobowitz <dan@codesourcery.com>
Vladimir Prus <vladimir@codesourcery.com>
* 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.
2009-07-21 Daniel Jacobowitz <dan@codesourcery.com>
* value.c (struct value): Add reference_count field.

View File

@ -632,7 +632,25 @@ value_fetch_lazy (struct value *val)
{
gdb_assert (value_lazy (val));
allocate_value_contents (val);
if (VALUE_LVAL (val) == lval_memory)
if (value_bitsize (val))
{
/* To read a lazy bitfield, read the entire enclosing value. This
prevents reading the same block of (possibly volatile) memory once
per bitfield. It would be even better to read only the containing
word, but we have no way to record that just specific bits of a
value have been fetched. */
struct type *type = check_typedef (value_type (val));
enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
struct value *parent = value_parent (val);
LONGEST offset = value_offset (val);
LONGEST num = unpack_bits_as_long (value_type (val),
value_contents (parent) + offset,
value_bitpos (val),
value_bitsize (val));
int length = TYPE_LENGTH (type);
store_signed_integer (value_contents_raw (val), length, byte_order, num);
}
else if (VALUE_LVAL (val) == lval_memory)
{
CORE_ADDR addr = value_address (val);
int length = TYPE_LENGTH (check_typedef (value_enclosing_type (val)));
@ -800,13 +818,20 @@ value_assign (struct value *toval, struct value *fromval)
if (value_bitsize (toval))
{
/* We assume that the argument to read_memory is in units
of host chars. FIXME: Is that correct? */
changed_len = (value_bitpos (toval)
+ value_bitsize (toval)
+ HOST_CHAR_BIT - 1)
/ HOST_CHAR_BIT;
/* If we can read-modify-write exactly the size of the
containing type (e.g. short or int) then do so. This
is safer for volatile bitfields mapped to hardware
registers. */
if (changed_len < TYPE_LENGTH (type)
&& TYPE_LENGTH (type) <= (int) sizeof (LONGEST)
&& ((LONGEST) value_address (toval) % TYPE_LENGTH (type)) == 0)
changed_len = TYPE_LENGTH (type);
if (changed_len > (int) sizeof (LONGEST))
error (_("Can't handle bitfields which don't fit in a %d bit word."),
(int) sizeof (LONGEST) * HOST_CHAR_BIT);

View File

@ -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

View File

@ -76,6 +76,12 @@ extern void set_value_bitsize (struct value *, int bit);
extern int value_bitpos (struct value *);
extern void set_value_bitpos (struct value *, int bit);
/* Only used for bitfields; the containing value. This allows a
single read from the target when displaying multiple
bitfields. */
struct value *value_parent (struct value *);
/* Describes offset of a value within lval of a structure in bytes.
If lval == lval_memory, this is an offset to the address. If lval
== lval_register, this is a further offset from location.address
@ -329,6 +335,8 @@ extern LONGEST unpack_long (struct type *type, const gdb_byte *valaddr);
extern DOUBLEST unpack_double (struct type *type, const gdb_byte *valaddr,
int *invp);
extern CORE_ADDR unpack_pointer (struct type *type, const gdb_byte *valaddr);
LONGEST unpack_bits_as_long (struct type *field_type, const gdb_byte *valaddr,
int bitpos, int bitsize);
extern LONGEST unpack_field_as_long (struct type *type,
const gdb_byte *valaddr,
int fieldno);