gdb: Make the builtin "boolean" type an unsigned type
authorShahab Vahedi <shahab@synopsys.com>
Mon, 19 Jul 2021 14:13:47 +0000 (16:13 +0200)
committerShahab Vahedi <shahab@synopsys.com>
Mon, 2 Aug 2021 11:00:01 +0000 (13:00 +0200)
When printing the fields of a register that is of a custom struct type,
the "unpack_bits_as_long ()" function is used:

    do_val_print (...)
      cp_print_value_fields (...)
        value_field_bitfield (...)
          unpack_value_bitfield (...)
            unpack_bits_as_long (...)

This function may sign-extend the extracted field while returning it:

    val >>= lsbcount;

    if (...)
      {
        valmask = (((ULONGEST) 1) << bitsize) - 1;
        val &= valmask;
        if (!field_type->is_unsigned ())
     if (val & (valmask ^ (valmask >> 1)))
         val |= ~valmask;
      }

    return val;

lsbcount:   Number of lower bits to get rid of.
bitsize:    The bit length of the field to be extracted.
val:        The register value.
field_type: The type of field that is being handled.

While the logic here is correct, there is a problem when it is
handling "field_type"s of "boolean".  Those types are NOT marked
as "unsigned" and therefore they end up being sign extended.
Although this is not a problem for "false" (0), it definitely
causes trouble for "true".

This patch constructs the builtin boolean type as such that it is
marked as an "unsigned" entity.

The issue tackled here was first encountered for arc-elf32 target
running on an x86_64 machine.  The unit-test introduced in this change
has passed for all the targets (--enable-targets=all) running on the
same x86_64 host.

Fixes: https://sourceware.org/PR28104
gdb/cp-valprint.c
gdb/gdbtypes.c

index 6c0449458698dfc06b9a5fb380f89f7e8bf3ea76..7442ec0743e1bafcb41eba747b2ee8562ed8cd73 100644 (file)
@@ -38,6 +38,8 @@
 #include "gdbsupport/byte-vector.h"
 #include "gdbarch.h"
 #include "cli/cli-style.h"
+#include "gdbsupport/selftest.h"
+#include "selftest-arch.h"
 
 static struct obstack dont_print_vb_obstack;
 static struct obstack dont_print_statmem_obstack;
@@ -715,11 +717,77 @@ cp_print_class_member (const gdb_byte *valaddr, struct type *type,
     fprintf_filtered (stream, "%ld", (long) val);
 }
 
+#if GDB_SELF_TEST
+
+/* Test printing of TYPE_CODE_STRUCT values.  */
+
+static void
+test_print_fields (gdbarch *arch)
+{
+  struct field *f;
+  type *uint8_type = builtin_type (arch)->builtin_uint8;
+  type *bool_type = builtin_type (arch)->builtin_bool;
+  type *the_struct = arch_composite_type (arch, NULL, TYPE_CODE_STRUCT);
+  TYPE_LENGTH (the_struct) = 4;
+
+  /* Value:  1110 1001
+     Fields: C-BB B-A- */
+  if (gdbarch_byte_order (arch) == BFD_ENDIAN_LITTLE)
+    {
+      f = append_composite_type_field_raw (the_struct, "A", bool_type);
+      SET_FIELD_BITPOS (*f, 1);
+      FIELD_BITSIZE (*f) = 1;
+      f = append_composite_type_field_raw (the_struct, "B", uint8_type);
+      SET_FIELD_BITPOS (*f, 3);
+      FIELD_BITSIZE (*f) = 3;
+      f = append_composite_type_field_raw (the_struct, "C", bool_type);
+      SET_FIELD_BITPOS (*f, 7);
+      FIELD_BITSIZE (*f) = 1;
+    }
+  /* According to the logic commented in "make_gdb_type_struct ()" of
+   * target-descriptions.c, bit positions are numbered differently for
+   * little and big endians.  */
+  else
+    {
+      f = append_composite_type_field_raw (the_struct, "A", bool_type);
+      SET_FIELD_BITPOS (*f, 30);
+      FIELD_BITSIZE (*f) = 1;
+      f = append_composite_type_field_raw (the_struct, "B", uint8_type);
+      SET_FIELD_BITPOS (*f, 26);
+      FIELD_BITSIZE (*f) = 3;
+      f = append_composite_type_field_raw (the_struct, "C", bool_type);
+      SET_FIELD_BITPOS (*f, 24);
+      FIELD_BITSIZE (*f) = 1;
+    }
+
+  value *val = allocate_value (the_struct);
+  gdb_byte *contents = value_contents_writeable (val);
+  store_unsigned_integer (contents, TYPE_LENGTH (value_enclosing_type (val)),
+                         gdbarch_byte_order (arch), 0xe9);
+
+  string_file out;
+  struct value_print_options opts;
+  get_no_prettyformat_print_options (&opts);
+  cp_print_value_fields(val, &out, 0, &opts, NULL, 0);
+  SELF_CHECK (out.string () == "{A = false, B = 5, C = true}");
+
+  out.clear();
+  opts.format = 'x';
+  cp_print_value_fields(val, &out, 0, &opts, NULL, 0);
+  SELF_CHECK (out.string () == "{A = 0x0, B = 0x5, C = 0x1}");
+}
+
+#endif
+
 
 void _initialize_cp_valprint ();
 void
 _initialize_cp_valprint ()
 {
+#if GDB_SELF_TEST
+  selftests::register_test_foreach_arch ("print-fields", test_print_fields);
+#endif
+
   obstack_begin (&dont_print_stat_array_obstack,
                 32 * sizeof (struct type *));
   obstack_begin (&dont_print_statmem_obstack,
index 5ba0e8d0eb9a035d58a7a7d72d10b5e25f59cdff..74ad5d6f7fef9f63da01806cf8ff1e183de4bdeb 100644 (file)
@@ -6101,7 +6101,7 @@ gdbtypes_post_init (struct gdbarch *gdbarch)
   builtin_type->builtin_string
     = arch_type (gdbarch, TYPE_CODE_STRING, TARGET_CHAR_BIT, "string");
   builtin_type->builtin_bool
-    = arch_type (gdbarch, TYPE_CODE_BOOL, TARGET_CHAR_BIT, "bool");
+    = arch_boolean_type (gdbarch, TARGET_CHAR_BIT, 1, "bool");
 
   /* The following three are about decimal floating point types, which
      are 32-bits, 64-bits and 128-bits respectively.  */