aboutsummaryrefslogtreecommitdiff
path: root/gdb/valops.c
diff options
context:
space:
mode:
authorDaniel Jacobowitz <drow@false.org>2009-07-21 18:15:32 +0000
committerDaniel Jacobowitz <drow@false.org>2009-07-21 18:15:32 +0000
commit4ea48cc1cd4875e570047f5aff70387018a56645 (patch)
tree35e518fe24754a9342c08045ba1718d8e0c44f81 /gdb/valops.c
parent828d3400fb1a9914ab16ee05dfe2647af8c566c5 (diff)
downloadgdb-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/valops.c')
-rw-r--r--gdb/valops.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/gdb/valops.c b/gdb/valops.c
index 2d20b41..5e5c4ed 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -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);