gdb
authorTom Tromey <tromey@redhat.com>
Mon, 16 Jan 2012 19:44:16 +0000 (19:44 +0000)
committerTom Tromey <tromey@redhat.com>
Mon, 16 Jan 2012 19:44:16 +0000 (19:44 +0000)
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.

14 files changed:
gdb/ChangeLog
gdb/NEWS
gdb/c-valprint.c
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/dwarf2read.c
gdb/gdbtypes.h
gdb/python/lib/gdb/printing.py
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/printcmds.c
gdb/testsuite/gdb.base/printcmds.exp
gdb/testsuite/gdb.python/py-pp-maint.c
gdb/testsuite/gdb.python/py-pp-maint.exp
gdb/testsuite/gdb.python/py-pp-maint.py

index 70fba10ef6d92ff4fb3c8e7e611553ca9aeae61e..dfd4178e62f01c1e57bc9c0b61e97a8756a57706 100644 (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.
index c5cecccb2e841a2535a2e7bd54507e8301694b71..02082a3f17993dc4672a64f7d27671ca39528e40 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
 * 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
index 9949015d868ad8013c534829e3394361481bf167..82551e9dc93173bf20da0ea4091b31b664fe8b61 100644 (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:
index 8ef5340586b2ec156f6c1490892a79bf20495e8e..fb9ea01e01b168cc7fdb03c350574a06575cfb5b 100644 (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>
 
index 4a8ff7b97b1af12a00ae584193b69a5ef8651b69..de2e39005fbe1d9ef651b71906694414d6cebbfe 100644 (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
index 42dbac342ab64442e3172c375f5f0e951ccd7f74..afb43374526e1c55ffa5266d3a357cec01309fc3 100644 (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
index ddad0dcbdbf6bca93e844cfe09b9efeb7001eee6..2070f0006d9d6f16c5bc772f01d9c7a60f264cbd 100644 (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;
index 98cfd274623300e39b4fbeb35ce96b94ce1458a7..0f399d0949f5468bc19af64adc0a3232ad5e7076 100644 (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
index fdc2bf4ee332d03f67ddb22c1f96847ea2b03db8..abb08b966edf7f14b14a217cbed9b74b3dcf678b 100644 (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.
index d37dfbd87b8347f88a767a27913fe1294b2328ab..743734b4a5c25cc79017743b92c738b0dea7059f 100644 (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
index c932f94e30fbe48735271458eea40b4e75ef2140..08a54b003d716118f4ba34a4c3bcfff5860dedae 100644 (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 {} {
index f65e5f755e3fda14ea6226a36be604553f259c24..e91193abdd038fed34b136e8894b403c1d790076 100644 (file)
 
 #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;
index 3115b56e801747aabde2321c3c76c30abba3efb6..5971a40387ed8e49634445bda14fea5fef9b0a8e 100644 (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"
index c988f8891fa0598630e282668bc5a41505f3070e..1677371b90291ff7847872b52707508d22e6bf2d 100644 (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