From 3e87153251d9a117182decbe57dd7d9d2a47c2b3 Mon Sep 17 00:00:00 2001 From: Luis Machado Date: Fri, 3 Oct 2014 08:21:33 -0300 Subject: [PATCH] MIPS bit field failures in gdb.base/store.exp On MIPS64 little endian, attempting an assignment to a bit field that lives in a register yields the wrong result. It just corrupts the data in the register depending on the specific position of the bit field inside the structure. FAIL: gdb.base/store.exp: f_1.j FAIL: gdb.base/store.exp: f_1.k FAIL: gdb.base/store.exp: F_1.i FAIL: gdb.base/store.exp: F_1.j FAIL: gdb.base/store.exp: F_1.k FAIL: gdb.base/store.exp: f_2.j FAIL: gdb.base/store.exp: f_2.k FAIL: gdb.base/store.exp: F_2.i FAIL: gdb.base/store.exp: F_2.j FAIL: gdb.base/store.exp: F_2.k FAIL: gdb.base/store.exp: f_3.j FAIL: gdb.base/store.exp: f_3.k FAIL: gdb.base/store.exp: F_3.i FAIL: gdb.base/store.exp: F_3.j FAIL: gdb.base/store.exp: F_3.k FAIL: gdb.base/store.exp: f_4.j FAIL: gdb.base/store.exp: f_4.k FAIL: gdb.base/store.exp: F_4.i FAIL: gdb.base/store.exp: F_4.j FAIL: gdb.base/store.exp: F_4.k === gdb Summary === Now, GDB knows how to do bit field assignment properly, but MIPS is one of those architectures that uses a hook for the register-to-value conversion. Although we can properly tell when the type being passed is a structure or union, we cannot tell when it is a bit field, because the bit field data lives in a value structure. Such data only lives in a "type" structure when the parent structure is being referenced, thus you can collect them from the flds_bnds members. A bit field type structure looks pretty much the same as any other primitive type like int or char, so we can't distinguish them. Forcing more fields into the type structure wouldn't help much, because the type structs are shared. 2014-10-03 Luis Machado * valops.c (value_assign): Check for bit field assignments before calling architecture-specific register value conversion functions. --- gdb/ChangeLog | 6 ++++ gdb/valops.c | 84 ++++++++++++++++++++++++++------------------------- 2 files changed, 49 insertions(+), 41 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 748efe9f2a2..e4004fe4a64 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2014-10-03 Luis Machado + + * valops.c (value_assign): Check for bit field assignments + before calling architecture-specific register value + conversion functions. + 2014-10-03 Pierre Muller * dbxread.c (read_dbx_symtab): Also ignore N_BNSYM/N_ENSYM. diff --git a/gdb/valops.c b/gdb/valops.c index e1decf05fd1..f1779074943 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -1112,52 +1112,54 @@ value_assign (struct value *toval, struct value *fromval) error (_("Value being assigned to is no longer active.")); gdbarch = get_frame_arch (frame); - if (gdbarch_convert_register_p (gdbarch, VALUE_REGNUM (toval), type)) + + if (value_bitsize (toval)) { - /* If TOVAL is a special machine register requiring - conversion of program values to a special raw - format. */ - gdbarch_value_to_register (gdbarch, frame, - VALUE_REGNUM (toval), type, - value_contents (fromval)); + struct value *parent = value_parent (toval); + int offset = value_offset (parent) + value_offset (toval); + int changed_len; + gdb_byte buffer[sizeof (LONGEST)]; + int optim, unavail; + + changed_len = (value_bitpos (toval) + + value_bitsize (toval) + + HOST_CHAR_BIT - 1) + / HOST_CHAR_BIT; + + 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); + + if (!get_frame_register_bytes (frame, value_reg, offset, + changed_len, buffer, + &optim, &unavail)) + { + if (optim) + throw_error (OPTIMIZED_OUT_ERROR, + _("value has been optimized out")); + if (unavail) + throw_error (NOT_AVAILABLE_ERROR, + _("value is not available")); + } + + modify_field (type, buffer, value_as_long (fromval), + value_bitpos (toval), value_bitsize (toval)); + + put_frame_register_bytes (frame, value_reg, offset, + changed_len, buffer); } else { - if (value_bitsize (toval)) + if (gdbarch_convert_register_p (gdbarch, VALUE_REGNUM (toval), + type)) { - struct value *parent = value_parent (toval); - int offset = value_offset (parent) + value_offset (toval); - int changed_len; - gdb_byte buffer[sizeof (LONGEST)]; - int optim, unavail; - - changed_len = (value_bitpos (toval) - + value_bitsize (toval) - + HOST_CHAR_BIT - 1) - / HOST_CHAR_BIT; - - 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); - - if (!get_frame_register_bytes (frame, value_reg, offset, - changed_len, buffer, - &optim, &unavail)) - { - if (optim) - throw_error (OPTIMIZED_OUT_ERROR, - _("value has been optimized out")); - if (unavail) - throw_error (NOT_AVAILABLE_ERROR, - _("value is not available")); - } - - modify_field (type, buffer, value_as_long (fromval), - value_bitpos (toval), value_bitsize (toval)); - - put_frame_register_bytes (frame, value_reg, offset, - changed_len, buffer); + /* If TOVAL is a special machine register requiring + conversion of program values to a special raw + format. */ + gdbarch_value_to_register (gdbarch, frame, + VALUE_REGNUM (toval), type, + value_contents (fromval)); } else { -- 2.30.2