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>
* 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.
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

View File

@ -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:

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>
Eli Zaretskii <eliz@gnu.org>

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

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>
* lib/gdb.exp (banned_procedures): New variable.

View File

@ -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

View File

@ -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 {} {

View File

@ -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;

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>>" \
"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"

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('ss', '^ss$', lambda val: pp_ss(val))
pp.add_printer('enum flag_enum', '^flag_enum$',
gdb.printing.FlagEnumerationPrinter('enum flag_enum'))
return pp