aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Tromey <tromey@redhat.com>2012-01-16 19:44:16 +0000
committerTom Tromey <tromey@redhat.com>2012-01-16 19:44:16 +0000
commitcafec441901459c36ad92f1cd9eef648534ea53b (patch)
tree4cd1a43ea2f36c655c39948c0b0e163874bb2e24
parent983af33b2623508a921372f02abee87aad9c8915 (diff)
downloadgdb-cafec441901459c36ad92f1cd9eef648534ea53b.zip
gdb-cafec441901459c36ad92f1cd9eef648534ea53b.tar.gz
gdb-cafec441901459c36ad92f1cd9eef648534ea53b.tar.bz2
gdb
PR python/13281: * gdbtypes.h (TYPE_FLAG_ENUM): New macro. (struct main_type) <flag_flag_enum>: New field. * dwarf2read.c (process_enumeration_scope): Detect "flag" enums. * NEWS: Add entries. * c-valprint.c (c_val_print) <TYPE_CODE_ENUM>: Handle "flag" enums. * python/lib/gdb/printing.py (_EnumInstance): New class. (FlagEnumerationPrinter): Likewise. gdb/doc * gdb.texinfo (gdb.printing): Document FlagEnumerationPrinter. gdb/testsuite * gdb.base/printcmds.c (enum flag_enum): New. (three): New global. * gdb.base/printcmds.exp (test_print_enums): Add test for flag enum printing. * gdb.python/py-pp-maint.py (build_pretty_printer): Instantiate FlagEnumerationPrinter. * gdb.python/py-pp-maint.exp: Add tests for FlagEnumerationPrinter. * gdb.python/py-pp-maint.c (enum flag_enum): New. (fval): New global.
-rw-r--r--gdb/ChangeLog12
-rw-r--r--gdb/NEWS12
-rw-r--r--gdb/c-valprint.c35
-rw-r--r--gdb/doc/ChangeLog4
-rw-r--r--gdb/doc/gdb.texinfo7
-rw-r--r--gdb/dwarf2read.c13
-rw-r--r--gdb/gdbtypes.h11
-rw-r--r--gdb/python/lib/gdb/printing.py50
-rw-r--r--gdb/testsuite/ChangeLog12
-rw-r--r--gdb/testsuite/gdb.base/printcmds.c4
-rw-r--r--gdb/testsuite/gdb.base/printcmds.exp2
-rw-r--r--gdb/testsuite/gdb.python/py-pp-maint.c10
-rw-r--r--gdb/testsuite/gdb.python/py-pp-maint.exp37
-rw-r--r--gdb/testsuite/gdb.python/py-pp-maint.py3
14 files changed, 199 insertions, 13 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 70fba10..dfd4178 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,15 @@
+2012-01-16 Tom Tromey <tromey@redhat.com>
+
+ PR python/13281:
+ * gdbtypes.h (TYPE_FLAG_ENUM): New macro.
+ (struct main_type) <flag_flag_enum>: New field.
+ * dwarf2read.c (process_enumeration_scope): Detect "flag" enums.
+ * NEWS: Add entries.
+ * c-valprint.c (c_val_print) <TYPE_CODE_ENUM>: Handle "flag"
+ enums.
+ * python/lib/gdb/printing.py (_EnumInstance): New class.
+ (FlagEnumerationPrinter): Likewise.
+
2012-01-16 Sergio Durigan Junior <sergiodj@redhat.com>
* breakpoint.c (create_sals_from_address_default): New function.
diff --git a/gdb/NEWS b/gdb/NEWS
index c5ceccc..02082a3 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -13,6 +13,18 @@
* The binary "gdbtui" can no longer be built or installed.
Use "gdb -tui" instead.
+* GDB will now print "flag" enums specially. A flag enum is one where
+ all the enumerator values have no bits in common when pairwise
+ "and"ed. When printing a value whose type is a flag enum, GDB will
+ show all the constants, e.g., for enum E { ONE = 1, TWO = 2}:
+ (gdb) print (enum E) 3
+ $1 = (ONE | TWO)
+
+* Python scripting
+
+ ** A new class, gdb.printing.FlagEnumerationPrinter, can be used to
+ apply "flag enum"-style pretty-printing to any enum.
+
*** Changes in GDB 7.4
* GDB now handles ambiguous linespecs more consistently; the existing
diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c
index 9949015..82551e9 100644
--- a/gdb/c-valprint.c
+++ b/gdb/c-valprint.c
@@ -456,10 +456,41 @@ c_val_print (struct type *type, const gdb_byte *valaddr,
{
fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
}
- else
+ else if (TYPE_FLAG_ENUM (type))
{
- print_longest (stream, 'd', 0, 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. */
+ fputs_filtered ("(", stream);
+ for (i = 0; i < len; ++i)
+ {
+ QUIT;
+
+ if ((val & TYPE_FIELD_BITPOS (type, i)) != 0)
+ {
+ if (!first)
+ fputs_filtered (" | ", stream);
+ first = 0;
+
+ val &= ~TYPE_FIELD_BITPOS (type, i);
+ fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
+ }
+ }
+
+ if (first || val != 0)
+ {
+ if (!first)
+ fputs_filtered (" | ", stream);
+ fputs_filtered ("unknown: ", stream);
+ print_longest (stream, 'd', 0, val);
+ }
+
+ fputs_filtered (")", stream);
}
+ else
+ print_longest (stream, 'd', 0, val);
break;
case TYPE_CODE_FLAGS:
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 8ef5340..fb9ea01 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,7 @@
+2012-01-16 Tom Tromey <tromey@redhat.com>
+
+ * gdb.texinfo (gdb.printing): Document FlagEnumerationPrinter.
+
2012-01-13 Jan Kratochvil <jan.kratochvil@redhat.com>
Eli Zaretskii <eliz@gnu.org>
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 4a8ff7b..de2e390 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -24720,6 +24720,13 @@ Utility class for handling multiple printers, all recognized via
regular expressions.
@xref{Writing a Pretty-Printer}, for an example.
+@item FlagEnumerationPrinter (@var{name})
+A pretty-printer which handles printing of @code{enum} values. Unlike
+@value{GDBN}'s built-in @code{enum} printing, this printer attempts to
+work properly when there is some overlap between the enumeration
+constants. @var{name} is the name of the printer and also the name of
+the @code{enum} type to look up.
+
@item register_pretty_printer (@var{obj}, @var{printer}, @var{replace}=False)
Register @var{printer} with the pretty-printer list of @var{obj}.
If @var{replace} is @code{True} then any existing copy of the printer
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 42dbac3..afb4337 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -7913,6 +7913,8 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu)
int num_fields = 0;
int unsigned_enum = 1;
char *name;
+ int flag_enum = 1;
+ ULONGEST mask = 0;
child_die = die->child;
while (child_die && child_die->tag)
@@ -7928,7 +7930,14 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu)
{
sym = new_symbol (child_die, this_type, cu);
if (SYMBOL_VALUE (sym) < 0)
- unsigned_enum = 0;
+ {
+ unsigned_enum = 0;
+ flag_enum = 0;
+ }
+ else if ((mask & SYMBOL_VALUE (sym)) != 0)
+ flag_enum = 0;
+ else
+ mask |= SYMBOL_VALUE (sym);
if ((num_fields % DW_FIELD_ALLOC_CHUNK) == 0)
{
@@ -7961,6 +7970,8 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu)
}
if (unsigned_enum)
TYPE_UNSIGNED (this_type) = 1;
+ if (flag_enum)
+ TYPE_FLAG_ENUM (this_type) = 1;
}
/* If we are reading an enum from a .debug_types unit, and the enum
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index ddad0dc..2070f00 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -290,6 +290,12 @@ enum type_instance_flag_value
#define TYPE_DECLARED_CLASS(t) (TYPE_MAIN_TYPE (t)->flag_declared_class)
+/* True if this type is a "flag" enum. A flag enum is one where all
+ the values are pairwise disjoint when "and"ed together. This
+ affects how enum values are printed. */
+
+#define TYPE_FLAG_ENUM(t) (TYPE_MAIN_TYPE (t)->flag_flag_enum)
+
/* Constant type. If this is set, the corresponding type has a
const modifier. */
@@ -400,6 +406,11 @@ struct main_type
"struct". */
unsigned int flag_declared_class : 1;
+ /* True if this is an enum type with disjoint values. This affects
+ how the enum is printed. */
+
+ unsigned int flag_flag_enum : 1;
+
/* A discriminant telling us which field of the type_specific union
is being used for this type, if any. */
ENUM_BITFIELD(type_specific_kind) type_specific_field : 3;
diff --git a/gdb/python/lib/gdb/printing.py b/gdb/python/lib/gdb/printing.py
index 98cfd27..0f399d0 100644
--- a/gdb/python/lib/gdb/printing.py
+++ b/gdb/python/lib/gdb/printing.py
@@ -206,3 +206,53 @@ class RegexpCollectionPrettyPrinter(PrettyPrinter):
# Cannot find a pretty printer. Return None.
return None
+
+# A helper class for printing enum types. This class is instantiated
+# with a list of enumerators to print a particular Value.
+class _EnumInstance:
+ def __init__(self, enumerators, val):
+ self.enumerators = enumerators
+ self.val = val
+
+ def to_string(self):
+ flag_list = []
+ v = long(self.val)
+ any_found = False
+ for (e_name, e_value) in self.enumerators:
+ if v & e_value != 0:
+ flag_list.append(e_name)
+ v = v & ~e_value
+ any_found = True
+ if not any_found or v != 0:
+ # Leftover value.
+ flag_list.append('<unknown: 0x%x>' % v)
+ return "0x%x [%s]" % (self.val, " | ".join(flag_list))
+
+class FlagEnumerationPrinter(PrettyPrinter):
+ """A pretty-printer which can be used to print a flag-style enumeration.
+ A flag-style enumeration is one where the enumerators are or'd
+ together to create values. The new printer will print these
+ symbolically using '|' notation. The printer must be registered
+ manually. This printer is most useful when an enum is flag-like,
+ but has some overlap. GDB's built-in printing will not handle
+ this case, but this printer will attempt to."""
+
+ def __init__(self, enum_type):
+ super(FlagEnumerationPrinter, self).__init__(enum_type)
+ self.initialized = False
+
+ def __call__(self, val):
+ if not self.initialized:
+ self.initialized = True
+ flags = gdb.lookup_type(self.name)
+ self.enumerators = []
+ for field in flags.fields():
+ self.enumerators.append((field.name, field.bitpos))
+ # Sorting the enumerators by value usually does the right
+ # thing.
+ self.enumerators.sort(key = lambda x: x.bitpos)
+
+ if self.enabled:
+ return _EnumInstance(self.enumerators, val)
+ else:
+ return None
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index fdc2bf4..abb08b9 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,15 @@
+2012-01-16 Tom Tromey <tromey@redhat.com>
+
+ * gdb.base/printcmds.c (enum flag_enum): New.
+ (three): New global.
+ * gdb.base/printcmds.exp (test_print_enums): Add test for flag
+ enum printing.
+ * gdb.python/py-pp-maint.py (build_pretty_printer): Instantiate
+ FlagEnumerationPrinter.
+ * gdb.python/py-pp-maint.exp: Add tests for FlagEnumerationPrinter.
+ * gdb.python/py-pp-maint.c (enum flag_enum): New.
+ (fval): New global.
+
2012-01-16 Pedro Alves <palves@redhat.com>
* lib/gdb.exp (banned_procedures): New variable.
diff --git a/gdb/testsuite/gdb.base/printcmds.c b/gdb/testsuite/gdb.base/printcmds.c
index d37dfbd..743734b 100644
--- a/gdb/testsuite/gdb.base/printcmds.c
+++ b/gdb/testsuite/gdb.base/printcmds.c
@@ -96,6 +96,10 @@ enum some_volatile_enum { enumvolval1, enumvolval2 };
name. See PR11827. */
volatile enum some_volatile_enum some_volatile_enum = enumvolval1;
+enum flag_enum { ONE = 1, TWO = 2 };
+
+enum flag_enum three = ONE | TWO;
+
/* A structure with an embedded array at an offset > 0. The array has
all elements with the same repeating value, which must not be the
same as the value of the preceding fields in the structure for the
diff --git a/gdb/testsuite/gdb.base/printcmds.exp b/gdb/testsuite/gdb.base/printcmds.exp
index c932f94..08a54b0 100644
--- a/gdb/testsuite/gdb.base/printcmds.exp
+++ b/gdb/testsuite/gdb.base/printcmds.exp
@@ -697,6 +697,8 @@ proc test_print_array_constants {} {
proc test_print_enums {} {
# Regression test for PR11827.
gdb_test "print some_volatile_enum" "enumvolval1"
+
+ gdb_test "print three" " = \\\(ONE \\| TWO\\\)"
}
proc test_printf {} {
diff --git a/gdb/testsuite/gdb.python/py-pp-maint.c b/gdb/testsuite/gdb.python/py-pp-maint.c
index f65e5f7..e91193a 100644
--- a/gdb/testsuite/gdb.python/py-pp-maint.c
+++ b/gdb/testsuite/gdb.python/py-pp-maint.c
@@ -17,6 +17,16 @@
#include <string.h>
+enum flag_enum
+ {
+ FLAG_1 = 1,
+ FLAG_2 = 2,
+ FLAG_3 = 4,
+ ALL = FLAG_1 | FLAG_2 | FLAG_3
+ };
+
+enum flag_enum fval;
+
struct function_lookup_test
{
int x,y;
diff --git a/gdb/testsuite/gdb.python/py-pp-maint.exp b/gdb/testsuite/gdb.python/py-pp-maint.exp
index 3115b56..5971a40 100644
--- a/gdb/testsuite/gdb.python/py-pp-maint.exp
+++ b/gdb/testsuite/gdb.python/py-pp-maint.exp
@@ -70,23 +70,25 @@ gdb_test "print flt" " = x=<42> y=<43>" \
gdb_test "print ss" " = a=<a=<1> b=<$hex>> b=<a=<2> b=<$hex>>" \
"print ss enabled #1"
+set num_pp 6
+
gdb_test "disable pretty-printer" \
- "5 printers disabled.*0 of 5 printers enabled"
+ "$num_pp printers disabled.*0 of $num_pp printers enabled"
gdb_test "enable pretty-printer" \
- "5 printers enabled.*5 of 5 printers enabled"
+ "$num_pp printers enabled.*$num_pp of $num_pp printers enabled"
gdb_test "disable pretty-printer global" \
- "5 printers disabled.*0 of 5 printers enabled"
+ "$num_pp printers disabled.*0 of $num_pp printers enabled"
gdb_test "enable pretty-printer" \
- "5 printers enabled.*5 of 5 printers enabled"
+ "$num_pp printers enabled.*$num_pp of $num_pp printers enabled"
gdb_test "disable pretty-printer global lookup_function_lookup_test" \
- "1 printer disabled.*4 of 5 printers enabled"
+ "1 printer disabled.*[expr $num_pp - 1] of $num_pp printers enabled"
gdb_test "disable pretty-printer global pp-test;.*" \
- "4 printers disabled.*0 of 5 printers enabled"
+ "[expr $num_pp - 1] printers disabled.*0 of $num_pp printers enabled"
gdb_test "info pretty-printer global .*function" \
{.*function_lookup_test \[disabled\].*}
@@ -101,19 +103,22 @@ gdb_test "print ss" " = {a = {a = 1, b = $hex}, b = {a = 2, b = $hex}}" \
"print ss disabled"
gdb_test "enable pretty-printer global lookup_function_lookup_test" \
- "1 printer enabled.*1 of 5 printers enabled"
+ "1 printer enabled.*1 of $num_pp printers enabled"
# This doesn't enable any printers because each subprinter in the collection
# is still individually disabled. But this is still needed, to enable the
# collection itself.
gdb_test "enable pretty-printer global pp-test" \
- "0 printers enabled.*1 of 5 printers enabled"
+ "0 printers enabled.*1 of $num_pp printers enabled"
gdb_test "enable pretty-printer global pp-test;.*ss.*" \
- "2 printers enabled.*3 of 5 printers enabled"
+ "2 printers enabled.*[expr $num_pp - 3] of $num_pp printers enabled"
gdb_test "enable pretty-printer global pp-test;.*s.*" \
- "2 printers enabled.*5 of 5 printers enabled"
+ "2 printers enabled.*[expr $num_pp - 1] of $num_pp printers enabled"
+
+gdb_test "enable pretty-printer global pp-test;.*" \
+ "1 printer enabled.*$num_pp of $num_pp printers enabled"
gdb_test "info pretty-printer" \
{.*function_lookup_test.*pp-test.*struct ss.*}
@@ -123,3 +128,15 @@ gdb_test "print flt" " = x=<42> y=<43>" \
gdb_test "print ss" " = a=<a=<1> b=<$hex>> b=<a=<2> b=<$hex>>" \
"print ss re-enabled"
+
+gdb_test "print (enum flag_enum) (FLAG_1)" \
+ " = 0x1 .FLAG_1." \
+ "print FLAG_1"
+
+gdb_test "print (enum flag_enum) (FLAG_1 | FLAG_3)" \
+ " = 0x5 .FLAG_1 | FLAG_3." \
+ "print FLAG_1 | FLAG_3"
+
+gdb_test "print (enum flag_enum) (4 + 8)" \
+ " = 0xc .FLAG_1 | <unknown: 0x8>." \
+ "print FLAG_1 | 8"
diff --git a/gdb/testsuite/gdb.python/py-pp-maint.py b/gdb/testsuite/gdb.python/py-pp-maint.py
index c988f88..1677371 100644
--- a/gdb/testsuite/gdb.python/py-pp-maint.py
+++ b/gdb/testsuite/gdb.python/py-pp-maint.py
@@ -67,6 +67,9 @@ def build_pretty_printer():
pp.add_printer('struct ss', '^struct ss$', lambda val: pp_ss(val))
pp.add_printer('ss', '^ss$', lambda val: pp_ss(val))
+ pp.add_printer('enum flag_enum', '^flag_enum$',
+ gdb.printing.FlagEnumerationPrinter('enum flag_enum'))
+
return pp