gdb/
authorDaniel Jacobowitz <drow@false.org>
Tue, 21 Jul 2009 18:15:32 +0000 (18:15 +0000)
committerDaniel Jacobowitz <drow@false.org>
Tue, 21 Jul 2009 18:15:32 +0000 (18:15 +0000)
* 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.

gdb/ChangeLog
gdb/valops.c
gdb/value.c
gdb/value.h

index 37555d135744ed93dfc47f24c01e9e874b095ab2..161d275c83bc8ea340711fb488177dd201839a38 100644 (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.
index 2d20b4153a101870244e2d36912b75e75208c112..5e5c4edeb30bfdcca4194df09f719b29693e6191 100644 (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);
index 904bd5ea9e8ca5387a74715c2d38f720b2a7066d..65a5aa93745ef21b99a9c3f3efda05a1ddccf283 100644 (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
 }
 
 \f
-/* 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
index 039e160bfe748a309c8f62703314b327a9efc6dd..29ad783d429e955e904e8fec93e6eda325667ae8 100644 (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);
This page took 0.035623 seconds and 4 git commands to generate.