diff options
author | Shahab Vahedi <shahab@synopsys.com> | 2021-07-16 16:49:15 +0200 |
---|---|---|
committer | Shahab Vahedi <shahab@synopsys.com> | 2021-07-26 14:34:01 +0200 |
commit | c9bd98593b785d9bf5f39c7aa74ed0226a23b830 (patch) | |
tree | 290b6b9add1408d1855454b00415462698ce9f53 | |
parent | 0264bf6fe3028a89c9a6a7b49c489831eb33f506 (diff) | |
download | gdb-c9bd98593b785d9bf5f39c7aa74ed0226a23b830.zip gdb-c9bd98593b785d9bf5f39c7aa74ed0226a23b830.tar.gz gdb-c9bd98593b785d9bf5f39c7aa74ed0226a23b830.tar.bz2 |
gdb: Fix numerical field extraction for target description "flags"
The "val_print_type_code_flags ()" function is responsible for
extraction of fields for "flags" data type. These data types are
used when describing a custom register type in a target description
XML. The logic used for the extraction though is not sound:
unsigned field_len = TYPE_FIELD_BITSIZE (type, field);
ULONGEST field_val
= val >> (TYPE_FIELD_BITPOS (type, field) - field_len + 1);
TYPE_FIELD_BITSIZE: The bit length of the field to be extracted.
TYPE_FIELD_BITPOS: The starting position of the field; 0 is LSB.
val: The register value.
Imagine you have a field that starts at position 1 and its length
is 4 bits. According to the third line of the code snippet the
shifting right would become "val >> -2", or "val >> 0xfff...fe"
to be precise. That will result in a "field_val" of 0.
The correct extraction should be:
ULONGEST field_val = val >> TYPE_FIELD_BITPOS (type, field);
The rest of the algorithm that masks out the higher bits is OK.
Co-Authored-By: Simon Marchi <simon.marchi@efficios.com>
-rw-r--r-- | gdb/valprint.c | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/gdb/valprint.c b/gdb/valprint.c index fa2b64e..324055d 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -43,6 +43,8 @@ #include "c-lang.h" #include "cp-abi.h" #include "inferior.h" +#include "gdbsupport/selftest.h" +#include "selftest-arch.h" /* Maximum number of wchars returned from wchar_iterate. */ #define MAX_WCHARS 4 @@ -1221,8 +1223,7 @@ val_print_type_code_flags (struct type *type, struct value *original_value, else { unsigned field_len = TYPE_FIELD_BITSIZE (type, field); - ULONGEST field_val - = val >> (TYPE_FIELD_BITPOS (type, field) - field_len + 1); + ULONGEST field_val = val >> TYPE_FIELD_BITPOS (type, field); if (field_len < sizeof (ULONGEST) * TARGET_CHAR_BIT) field_val &= ((ULONGEST) 1 << field_len) - 1; @@ -3137,10 +3138,41 @@ make_value_print_options_def_group (value_print_options *opts) return {{value_print_option_defs}, opts}; } +#if GDB_SELF_TEST + +/* Test printing of TYPE_CODE_FLAGS values. */ + +static void +test_print_flags (gdbarch *arch) +{ + type *flags_type = arch_flags_type (arch, "test_type", 32); + type *field_type = builtin_type (arch)->builtin_uint32; + + /* Value: 1010 1010 + Fields: CCCB BAAA */ + append_flags_type_field (flags_type, 0, 3, field_type, "A"); + append_flags_type_field (flags_type, 3, 2, field_type, "B"); + append_flags_type_field (flags_type, 5, 3, field_type, "C"); + + value *val = allocate_value (flags_type); + gdb_byte *contents = value_contents_writeable (val); + store_unsigned_integer (contents, 4, gdbarch_byte_order (arch), 0xaa); + + string_file out; + val_print_type_code_flags (flags_type, val, 0, &out); + SELF_CHECK (out.string () == "[ A=2 B=1 C=5 ]"); +} + +#endif + void _initialize_valprint (); void _initialize_valprint () { +#if GDB_SELF_TEST + selftests::register_test_foreach_arch ("print-flags", test_print_flags); +#endif + cmd_list_element *cmd; cmd_list_element *set_print_cmd |