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.
This commit is contained in:
Tom Tromey 2012-01-16 19:44:16 +00:00
parent 983af33b26
commit cafec44190
14 changed files with 199 additions and 13 deletions

View file

@ -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> 2012-01-16 Sergio Durigan Junior <sergiodj@redhat.com>
* breakpoint.c (create_sals_from_address_default): New function. * breakpoint.c (create_sals_from_address_default): New function.

View file

@ -13,6 +13,18 @@
* The binary "gdbtui" can no longer be built or installed. * The binary "gdbtui" can no longer be built or installed.
Use "gdb -tui" instead. 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 *** Changes in GDB 7.4
* GDB now handles ambiguous linespecs more consistently; the existing * GDB now handles ambiguous linespecs more consistently; the existing

View file

@ -456,10 +456,41 @@ c_val_print (struct type *type, const gdb_byte *valaddr,
{ {
fputs_filtered (TYPE_FIELD_NAME (type, i), stream); 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; break;
case TYPE_CODE_FLAGS: case TYPE_CODE_FLAGS:

View file

@ -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> 2012-01-13 Jan Kratochvil <jan.kratochvil@redhat.com>
Eli Zaretskii <eliz@gnu.org> Eli Zaretskii <eliz@gnu.org>

View file

@ -24720,6 +24720,13 @@ Utility class for handling multiple printers, all recognized via
regular expressions. regular expressions.
@xref{Writing a Pretty-Printer}, for an example. @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) @item register_pretty_printer (@var{obj}, @var{printer}, @var{replace}=False)
Register @var{printer} with the pretty-printer list of @var{obj}. Register @var{printer} with the pretty-printer list of @var{obj}.
If @var{replace} is @code{True} then any existing copy of the printer If @var{replace} is @code{True} then any existing copy of the printer

View file

@ -7913,6 +7913,8 @@ process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu)
int num_fields = 0; int num_fields = 0;
int unsigned_enum = 1; int unsigned_enum = 1;
char *name; char *name;
int flag_enum = 1;
ULONGEST mask = 0;
child_die = die->child; child_die = die->child;
while (child_die && child_die->tag) 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); sym = new_symbol (child_die, this_type, cu);
if (SYMBOL_VALUE (sym) < 0) 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) 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) if (unsigned_enum)
TYPE_UNSIGNED (this_type) = 1; 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 /* If we are reading an enum from a .debug_types unit, and the enum

View file

@ -290,6 +290,12 @@ enum type_instance_flag_value
#define TYPE_DECLARED_CLASS(t) (TYPE_MAIN_TYPE (t)->flag_declared_class) #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 /* Constant type. If this is set, the corresponding type has a
const modifier. */ const modifier. */
@ -400,6 +406,11 @@ struct main_type
"struct". */ "struct". */
unsigned int flag_declared_class : 1; 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 /* A discriminant telling us which field of the type_specific union
is being used for this type, if any. */ is being used for this type, if any. */
ENUM_BITFIELD(type_specific_kind) type_specific_field : 3; ENUM_BITFIELD(type_specific_kind) type_specific_field : 3;

View file

@ -206,3 +206,53 @@ class RegexpCollectionPrettyPrinter(PrettyPrinter):
# Cannot find a pretty printer. Return None. # Cannot find a pretty printer. Return None.
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

View file

@ -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> 2012-01-16 Pedro Alves <palves@redhat.com>
* lib/gdb.exp (banned_procedures): New variable. * lib/gdb.exp (banned_procedures): New variable.

View file

@ -96,6 +96,10 @@ enum some_volatile_enum { enumvolval1, enumvolval2 };
name. See PR11827. */ name. See PR11827. */
volatile enum some_volatile_enum some_volatile_enum = enumvolval1; 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 /* 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 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 same as the value of the preceding fields in the structure for the

View file

@ -697,6 +697,8 @@ proc test_print_array_constants {} {
proc test_print_enums {} { proc test_print_enums {} {
# Regression test for PR11827. # Regression test for PR11827.
gdb_test "print some_volatile_enum" "enumvolval1" gdb_test "print some_volatile_enum" "enumvolval1"
gdb_test "print three" " = \\\(ONE \\| TWO\\\)"
} }
proc test_printf {} { proc test_printf {} {

View file

@ -17,6 +17,16 @@
#include <string.h> #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 struct function_lookup_test
{ {
int x,y; int x,y;

View file

@ -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>>" \ gdb_test "print ss" " = a=<a=<1> b=<$hex>> b=<a=<2> b=<$hex>>" \
"print ss enabled #1" "print ss enabled #1"
set num_pp 6
gdb_test "disable pretty-printer" \ 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" \ 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" \ 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" \ 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" \ 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;.*" \ 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" \ gdb_test "info pretty-printer global .*function" \
{.*function_lookup_test \[disabled\].*} {.*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" "print ss disabled"
gdb_test "enable pretty-printer global lookup_function_lookup_test" \ 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 # This doesn't enable any printers because each subprinter in the collection
# is still individually disabled. But this is still needed, to enable the # is still individually disabled. But this is still needed, to enable the
# collection itself. # collection itself.
gdb_test "enable pretty-printer global pp-test" \ 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.*" \ 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.*" \ 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" \ gdb_test "info pretty-printer" \
{.*function_lookup_test.*pp-test.*struct ss.*} {.*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>>" \ gdb_test "print ss" " = a=<a=<1> b=<$hex>> b=<a=<2> b=<$hex>>" \
"print ss re-enabled" "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"

View file

@ -67,6 +67,9 @@ def build_pretty_printer():
pp.add_printer('struct ss', '^struct ss$', lambda val: pp_ss(val)) 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('ss', '^ss$', lambda val: pp_ss(val))
pp.add_printer('enum flag_enum', '^flag_enum$',
gdb.printing.FlagEnumerationPrinter('enum flag_enum'))
return pp return pp