From 6740f0cc3bd1530e4aeefe856d9cfe5c0ba2098a Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Tue, 18 Feb 2020 17:29:23 -0500 Subject: [PATCH] gdb: allow duplicate enumerators in flag enums I have come across some uses cases where it would be desirable to treat an enum that has duplicate values as a "flag enum". For example, this one here [1]: enum membarrier_cmd { MEMBARRIER_CMD_QUERY = 0, MEMBARRIER_CMD_GLOBAL = (1 << 0), MEMBARRIER_CMD_GLOBAL_EXPEDITED = (1 << 1), MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED = (1 << 2), MEMBARRIER_CMD_PRIVATE_EXPEDITED = (1 << 3), MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED = (1 << 4), MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE = (1 << 5), MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE = (1 << 6), /* Alias for header backward compatibility. */ MEMBARRIER_CMD_SHARED = MEMBARRIER_CMD_GLOBAL, }; The last enumerator is kept for backwards compatibility. Without this patch, this enumeration wouldn't be considered a flag enum, because two enumerators collide. With this patch, it would be considered a flag enum, and the value 3 would be printed as: MEMBARRIER_CMD_GLOBAL | MEMBARRIER_CMD_GLOBAL_EXPEDITED Although if people prefer, we could display both MEMBARRIER_CMD_GLOBAL and MEMBARRIER_CMD_SHARED in the result. It wouldn't be wrong, and could perhaps be useful in case a bit may have multiple meanings (depending on some other bit value). [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/membarrier.h?id=0bf999f9c5e74c7ecf9dafb527146601e5c848b9#n125 gdb/ChangeLog: * dwarf2/read.c (update_enumeration_type_from_children): Allow flag enums to contain duplicate enumerators. * valprint.c (generic_val_print_enum_1): Update comment. gdb/testsuite/ChangeLog: * gdb.base/printcmds.c (enum flag_enum): Add FE_TWO_LEGACY enumerator. --- gdb/ChangeLog | 6 ++++++ gdb/dwarf2/read.c | 5 ----- gdb/testsuite/ChangeLog | 5 +++++ gdb/testsuite/gdb.base/printcmds.c | 7 ++++--- gdb/valprint.c | 7 ++++--- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ca9f3647453..6ea59592fac 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2020-02-18 Simon Marchi + + * dwarf2/read.c (update_enumeration_type_from_children): Allow + flag enums to contain duplicate enumerators. + * valprint.c (generic_val_print_enum_1): Update comment. + 2020-02-18 Simon Marchi * dwarf2/read.c: Include "count-one-bits.h". diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 5a77b62b5a0..ee220ab70b3 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -15495,7 +15495,6 @@ update_enumeration_type_from_children (struct die_info *die, struct die_info *child_die; int unsigned_enum = 1; int flag_enum = 1; - ULONGEST mask = 0; auto_obstack obstack; @@ -15531,10 +15530,6 @@ update_enumeration_type_from_children (struct die_info *die, { if (count_one_bits_ll (value) >= 2) flag_enum = 0; - else if ((mask & value) != 0) - flag_enum = 0; - else - mask |= value; } /* If we already know that the enum type is neither unsigned, nor diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 5aaf5feecdf..4f63dde12a9 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2020-02-18 Simon Marchi + + * gdb.base/printcmds.c (enum flag_enum): Add FE_TWO_LEGACY + enumerator. + 2020-02-18 Simon Marchi * gdb.base/printcmds.c (enum flag_enum): Prefix enumerators with diff --git a/gdb/testsuite/gdb.base/printcmds.c b/gdb/testsuite/gdb.base/printcmds.c index acb3cb3ad25..ed1e26b12a9 100644 --- a/gdb/testsuite/gdb.base/printcmds.c +++ b/gdb/testsuite/gdb.base/printcmds.c @@ -99,9 +99,10 @@ volatile enum some_volatile_enum some_volatile_enum = enumvolval1; /* An enum considered as a "flag enum". */ enum flag_enum { - FE_NONE = 0x00, - FE_ONE = 0x01, - FE_TWO = 0x02, + FE_NONE = 0x00, + FE_ONE = 0x01, + FE_TWO = 0x02, + FE_TWO_LEGACY = 0x02, }; enum flag_enum three = FE_ONE | FE_TWO; diff --git a/gdb/valprint.c b/gdb/valprint.c index 77b9a4993d7..888c9cdb577 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -631,9 +631,10 @@ generic_val_print_enum_1 (struct type *type, LONGEST val, { int first = 1; - /* We have a "flag" enum, so we try to decompose it into - pieces as appropriate. A flag enum has disjoint - constants by definition. */ + /* We have a "flag" enum, so we try to decompose it into pieces as + appropriate. The enum may have multiple enumerators representing + the same bit, in which case we choose to only print the first one + we find. */ fputs_filtered ("(", stream); for (i = 0; i < len; ++i) { -- 2.30.2