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.
This commit is contained in:
parent
983af33b26
commit
cafec44190
14 changed files with 199 additions and 13 deletions
|
@ -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.
|
||||
|
|
12
gdb/NEWS
12
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
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
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:
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {} {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue