This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Handle bitfields inside inner structs for internalvars


Hi,

<https://bugzilla.redhat.com/show_bug.cgi?id=903734>

(The bug is marked as private, I believe you won't be able to see it.)

This is a very specific bug.  It occurs when one tries to set the value
of an internal variable's bitfield which is declared inside an inner
structure, i.e., a structure declared inside another.  For example:

    struct foo
      {
        int a;
        struct
          {
            unsigned int b : 1;
          } inner;
      };

Now, consider that we create an internal variable out of this structure:

    (gdb) set $p = (struct foo) {0}
    (gdb) print $p
    $1 = {a = 0, inner = {b = 0}}

Now, if we try to set the bitfield `b':

    (gdb) set $p.inner.b = 1
    (gdb) p $p
    $2 = {a = 1, inner = {b = 0}}

This happens because of some miscalculations of offsets inside
gdb/valops.c:value_assign: GDB forgets to add the offset of the `inner'
struct to the offset of the bitfield, thus setting the wrong field.

The patch below fixes it, and includes some new tests for this specific
scenario.  I ran a regression test on my Fedora 16 box (x86, x86_64 with
and without -m32, gdbserver for both), and found no regressions.

OK to apply?

-- 
Sergio

gdb/
2013-02-06  Sergio Durigan Junior  <sergiodj@redhat.com>

	* valops.c (value_assign): Handling bitfield offset in
	`lval_internalvar_component' case.

gdb/testsuite/
2013-02-06  Sergio Durigan Junior  <sergiodj@redhat.com>

	* gdb.base/bitfields.c (struct internalvartest): New declaration.
	* gdb.base/bitfields.exp (bitfield_internalvar): New function.

---
 gdb/testsuite/gdb.base/bitfields.c   |   16 ++++++++++++++++
 gdb/testsuite/gdb.base/bitfields.exp |   26 ++++++++++++++++++++++++++
 gdb/valops.c                         |   17 ++++++++++++-----
 3 files changed, 54 insertions(+), 5 deletions(-)

diff --git a/gdb/testsuite/gdb.base/bitfields.c b/gdb/testsuite/gdb.base/bitfields.c
index ed1634c..3a6b76f 100644
--- a/gdb/testsuite/gdb.base/bitfields.c
+++ b/gdb/testsuite/gdb.base/bitfields.c
@@ -23,6 +23,22 @@ struct fields
   signed char	sc    ;
 } flags;
 
+struct internalvartest
+{
+  unsigned int a : 1;
+  struct
+    {
+      unsigned int b : 1;
+      struct
+	{
+	  unsigned int c : 1;
+	  signed int   d : 1;
+	} deep;
+      signed int   e : 1;
+    } inner;
+  signed int   f : 1;
+} dummy_internalvartest;
+
 void break1 ()
 {
 }
diff --git a/gdb/testsuite/gdb.base/bitfields.exp b/gdb/testsuite/gdb.base/bitfields.exp
index 9095736..c2e1c63 100644
--- a/gdb/testsuite/gdb.base/bitfields.exp
+++ b/gdb/testsuite/gdb.base/bitfields.exp
@@ -245,6 +245,31 @@ proc bitfield_at_offset {} {
     gdb_test "print container.two.u3" ".* = 3"
 }
 
+proc bitfield_internalvar {} {
+    global gdb_prompt
+
+    # First, we create an internal var holding an instance of
+    # the struct (zeroed out).
+    gdb_test "set \$myvar = \(struct internalvartest\) \{0\}" "" \
+      "set internal var"
+
+    # Now, we set the proper bits.
+    gdb_test_no_output "set \$myvar.a = 0"
+    gdb_test_no_output "set \$myvar.inner.b = 1"
+    gdb_test_no_output "set \$myvar.inner.deep.c = 0"
+    gdb_test_no_output "set \$myvar.inner.deep.d = -1"
+    gdb_test_no_output "set \$myvar.inner.e = 1"
+    gdb_test_no_output "set \$myvar.f = 1"
+
+    # Here comes the true testing.
+    gdb_test "print \$myvar.a" "\\$\[0-9\]\+ = 0"
+    gdb_test "print \$myvar.inner.b" "\\$\[0-9\]\+ = 1"
+    gdb_test "print \$myvar.inner.deep.c" "\\$\[0-9\]\+ = 0"
+    gdb_test "print \$myvar.inner.deep.d" "\\$\[0-9\]\+ = -1"
+    gdb_test "print \$myvar.inner.e" "\\$\[0-9\]\+ = -1"
+    gdb_test "print \$myvar.f" "\\$\[0-9\]\+ = -1"
+}
+
 gdb_start
 gdb_reinitialize_dir $srcdir/$subdir
 gdb_load ${binfile}
@@ -256,3 +281,4 @@ bitfield_containment
 bitfield_unsignedness
 bitfield_signedness
 bitfield_at_offset
+bitfield_internalvar
diff --git a/gdb/valops.c b/gdb/valops.c
index 2132f3e..625e8d6 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1233,11 +1233,18 @@ value_assign (struct value *toval, struct value *fromval)
 				   VALUE_INTERNALVAR (toval));
 
     case lval_internalvar_component:
-      set_internalvar_component (VALUE_INTERNALVAR (toval),
-				 value_offset (toval),
-				 value_bitpos (toval),
-				 value_bitsize (toval),
-				 fromval);
+      {
+	int offset = value_offset (toval);
+
+	if (value_bitsize (toval))
+	  offset += value_offset (value_parent (toval));
+
+	set_internalvar_component (VALUE_INTERNALVAR (toval),
+				   offset,
+				   value_bitpos (toval),
+				   value_bitsize (toval),
+				   fromval);
+      }
       break;
 
     case lval_memory:
-- 
1.7.7.6


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]