Home | History | Annotate | Download | only in command
      1 # Pretty-printer commands.
      2 # Copyright (C) 2010, 2011 Free Software Foundation, Inc.
      3 
      4 # This program is free software; you can redistribute it and/or modify
      5 # it under the terms of the GNU General Public License as published by
      6 # the Free Software Foundation; either version 3 of the License, or
      7 # (at your option) any later version.
      8 #
      9 # This program is distributed in the hope that it will be useful,
     10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 # GNU General Public License for more details.
     13 #
     14 # You should have received a copy of the GNU General Public License
     15 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16 
     17 """GDB commands for working with pretty-printers."""
     18 
     19 import copy
     20 import gdb
     21 import re
     22 
     23 
     24 def parse_printer_regexps(arg):
     25     """Internal utility to parse a pretty-printer command argv.
     26 
     27     Arguments:
     28         arg: The arguments to the command.  The format is:
     29              [object-regexp [name-regexp]].
     30              Individual printers in a collection are named as
     31              printer-name;subprinter-name.
     32 
     33     Returns:
     34         The result is a 3-tuple of compiled regular expressions, except that
     35         the resulting compiled subprinter regexp is None if not provided.
     36 
     37     Raises:
     38         SyntaxError: an error processing ARG
     39     """
     40 
     41     argv = gdb.string_to_argv(arg);
     42     argc = len(argv)
     43     object_regexp = ""  # match everything
     44     name_regexp = ""  # match everything
     45     subname_regexp = None
     46     if argc > 3:
     47         raise SyntaxError("too many arguments")
     48     if argc >= 1:
     49         object_regexp = argv[0]
     50     if argc >= 2:
     51         name_subname = argv[1].split(";", 1)
     52         name_regexp = name_subname[0]
     53         if len(name_subname) == 2:
     54             subname_regexp = name_subname[1]
     55     # That re.compile raises SyntaxError was determined empirically.
     56     # We catch it and reraise it to provide a slightly more useful
     57     # error message for the user.
     58     try:
     59         object_re = re.compile(object_regexp)
     60     except SyntaxError:
     61         raise SyntaxError("invalid object regexp: %s" % object_regexp)
     62     try:
     63         name_re = re.compile (name_regexp)
     64     except SyntaxError:
     65         raise SyntaxError("invalid name regexp: %s" % name_regexp)
     66     if subname_regexp is not None:
     67         try:
     68             subname_re = re.compile(subname_regexp)
     69         except SyntaxError:
     70             raise SyntaxError("invalid subname regexp: %s" % subname_regexp)
     71     else:
     72         subname_re = None
     73     return(object_re, name_re, subname_re)
     74 
     75 
     76 def printer_enabled_p(printer):
     77     """Internal utility to see if printer (or subprinter) is enabled."""
     78     if hasattr(printer, "enabled"):
     79         return printer.enabled
     80     else:
     81         return True
     82 
     83 
     84 class InfoPrettyPrinter(gdb.Command):
     85     """GDB command to list all registered pretty-printers.
     86 
     87     Usage: info pretty-printer [object-regexp [name-regexp]]
     88 
     89     OBJECT-REGEXP is a regular expression matching the objects to list.
     90     Objects are "global", the program space's file, and the objfiles within
     91     that program space.
     92 
     93     NAME-REGEXP matches the name of the pretty-printer.
     94     Individual printers in a collection are named as
     95     printer-name;subprinter-name.
     96     """
     97 
     98     def __init__ (self):
     99         super(InfoPrettyPrinter, self).__init__("info pretty-printer",
    100                                                  gdb.COMMAND_DATA)
    101 
    102     @staticmethod
    103     def enabled_string(printer):
    104         """Return "" if PRINTER is enabled, otherwise " [disabled]"."""
    105         if printer_enabled_p(printer):
    106             return ""
    107         else:
    108             return " [disabled]"
    109 
    110     @staticmethod
    111     def printer_name(printer):
    112         """Return the printer's name."""
    113         if hasattr(printer, "name"):
    114             return printer.name
    115         if hasattr(printer, "__name__"):
    116             return printer.__name__
    117         # This "shouldn't happen", but the public API allows for
    118         # direct additions to the pretty-printer list, and we shouldn't
    119         # crash because someone added a bogus printer.
    120         # Plus we want to give the user a way to list unknown printers.
    121         return "unknown"
    122 
    123     def list_pretty_printers(self, pretty_printers, name_re, subname_re):
    124         """Print a list of pretty-printers."""
    125         # A potential enhancement is to provide an option to list printers in
    126         # "lookup order" (i.e. unsorted).
    127         sorted_pretty_printers = copy.copy(pretty_printers)
    128         sorted_pretty_printers.sort(lambda x, y:
    129                                         cmp(self.printer_name(x),
    130                                             self.printer_name(y)))
    131         for printer in sorted_pretty_printers:
    132             name = self.printer_name(printer)
    133             enabled = self.enabled_string(printer)
    134             if name_re.match(name):
    135                 print "  %s%s" % (name, enabled)
    136                 if (hasattr(printer, "subprinters") and
    137                     printer.subprinters is not None):
    138                     sorted_subprinters = copy.copy(printer.subprinters)
    139                     sorted_subprinters.sort(lambda x, y:
    140                                                 cmp(self.printer_name(x),
    141                                                     self.printer_name(y)))
    142                     for subprinter in sorted_subprinters:
    143                         if (not subname_re or
    144                             subname_re.match(subprinter.name)):
    145                             print ("    %s%s" %
    146                                    (subprinter.name,
    147                                     self.enabled_string(subprinter)))
    148 
    149     def invoke1(self, title, printer_list,
    150                 obj_name_to_match, object_re, name_re, subname_re):
    151         """"Subroutine of invoke to simplify it."""
    152         if printer_list and object_re.match(obj_name_to_match):
    153             print title
    154             self.list_pretty_printers(printer_list, name_re, subname_re)
    155 
    156     def invoke(self, arg, from_tty):
    157         """GDB calls this to perform the command."""
    158         (object_re, name_re, subname_re) = parse_printer_regexps(arg)
    159         self.invoke1("global pretty-printers:", gdb.pretty_printers,
    160                      "global", object_re, name_re, subname_re)
    161         cp = gdb.current_progspace()
    162         self.invoke1("progspace %s pretty-printers:" % cp.filename,
    163                      cp.pretty_printers, "progspace",
    164                      object_re, name_re, subname_re)
    165         for objfile in gdb.objfiles():
    166             self.invoke1("  objfile %s pretty-printers:" % objfile.filename,
    167                          objfile.pretty_printers, objfile.filename,
    168                          object_re, name_re, subname_re)
    169 
    170 
    171 def count_enabled_printers(pretty_printers):
    172     """Return a 2-tuple of number of enabled and total printers."""
    173     enabled = 0
    174     total = 0
    175     for printer in pretty_printers:
    176         if (hasattr(printer, "subprinters")
    177             and printer.subprinters is not None):
    178             if printer_enabled_p(printer):
    179                 for subprinter in printer.subprinters:
    180                     if printer_enabled_p(subprinter):
    181                         enabled += 1
    182             total += len(printer.subprinters)
    183         else:
    184             if printer_enabled_p(printer):
    185                 enabled += 1
    186             total += 1
    187     return (enabled, total)
    188 
    189 
    190 def count_all_enabled_printers():
    191     """Return a 2-tuble of the enabled state and total number of all printers.
    192     This includes subprinters.
    193     """
    194     enabled_count = 0
    195     total_count = 0
    196     (t_enabled, t_total) = count_enabled_printers(gdb.pretty_printers)
    197     enabled_count += t_enabled
    198     total_count += t_total
    199     (t_enabled, t_total) = count_enabled_printers(gdb.current_progspace().pretty_printers)
    200     enabled_count += t_enabled
    201     total_count += t_total
    202     for objfile in gdb.objfiles():
    203         (t_enabled, t_total) = count_enabled_printers(objfile.pretty_printers)
    204         enabled_count += t_enabled
    205         total_count += t_total
    206     return (enabled_count, total_count)
    207 
    208 
    209 def pluralize(text, n, suffix="s"):
    210     """Return TEXT pluralized if N != 1."""
    211     if n != 1:
    212         return "%s%s" % (text, suffix)
    213     else:
    214         return text
    215 
    216 
    217 def show_pretty_printer_enabled_summary():
    218     """Print the number of printers enabled/disabled.
    219     We count subprinters individually.
    220     """
    221     (enabled_count, total_count) = count_all_enabled_printers()
    222     print "%d of %d printers enabled" % (enabled_count, total_count)
    223 
    224 
    225 def do_enable_pretty_printer_1 (pretty_printers, name_re, subname_re, flag):
    226     """Worker for enabling/disabling pretty-printers.
    227 
    228     Arguments:
    229         pretty_printers: list of pretty-printers
    230         name_re: regular-expression object to select printers
    231         subname_re: regular expression object to select subprinters or None
    232                     if all are affected
    233         flag: True for Enable, False for Disable
    234 
    235     Returns:
    236         The number of printers affected.
    237         This is just for informational purposes for the user.
    238     """
    239     total = 0
    240     for printer in pretty_printers:
    241         if (hasattr(printer, "name") and name_re.match(printer.name) or
    242             hasattr(printer, "__name__") and name_re.match(printer.__name__)):
    243             if (hasattr(printer, "subprinters") and
    244                 printer.subprinters is not None):
    245                 if not subname_re:
    246                     # Only record printers that change state.
    247                     if printer_enabled_p(printer) != flag:
    248                         for subprinter in printer.subprinters:
    249                             if printer_enabled_p(subprinter):
    250                                 total += 1
    251                     # NOTE: We preserve individual subprinter settings.
    252                     printer.enabled = flag
    253                 else:
    254                     # NOTE: Whether this actually disables the subprinter
    255                     # depends on whether the printer's lookup function supports
    256                     # the "enable" API.  We can only assume it does.
    257                     for subprinter in printer.subprinters:
    258                         if subname_re.match(subprinter.name):
    259                             # Only record printers that change state.
    260                            if (printer_enabled_p(printer) and
    261                                printer_enabled_p(subprinter) != flag):
    262                                total += 1
    263                            subprinter.enabled = flag
    264             else:
    265                 # This printer has no subprinters.
    266                 # If the user does "disable pretty-printer .* .* foo"
    267                 # should we disable printers that don't have subprinters?
    268                 # How do we apply "foo" in this context?  Since there is no
    269                 # "foo" subprinter it feels like we should skip this printer.
    270                 # There's still the issue of how to handle
    271                 # "disable pretty-printer .* .* .*", and every other variation
    272                 # that can match everything.  For now punt and only support
    273                 # "disable pretty-printer .* .*" (i.e. subname is elided)
    274                 # to disable everything.
    275                 if not subname_re:
    276                     # Only record printers that change state.
    277                     if printer_enabled_p(printer) != flag:
    278                         total += 1
    279                     printer.enabled = flag
    280     return total
    281 
    282 
    283 def do_enable_pretty_printer (arg, flag):
    284     """Internal worker for enabling/disabling pretty-printers."""
    285     (object_re, name_re, subname_re) = parse_printer_regexps(arg)
    286 
    287     total = 0
    288     if object_re.match("global"):
    289         total += do_enable_pretty_printer_1(gdb.pretty_printers,
    290                                             name_re, subname_re, flag)
    291     cp = gdb.current_progspace()
    292     if object_re.match("progspace"):
    293         total += do_enable_pretty_printer_1(cp.pretty_printers,
    294                                             name_re, subname_re, flag)
    295     for objfile in gdb.objfiles():
    296         if object_re.match(objfile.filename):
    297             total += do_enable_pretty_printer_1(objfile.pretty_printers,
    298                                                 name_re, subname_re, flag)
    299 
    300     if flag:
    301         state = "enabled"
    302     else:
    303         state = "disabled"
    304     print "%d %s %s" % (total, pluralize("printer", total), state)
    305 
    306     # Print the total list of printers currently enabled/disabled.
    307     # This is to further assist the user in determining whether the result
    308     # is expected.  Since we use regexps to select it's useful.
    309     show_pretty_printer_enabled_summary()
    310 
    311 
    312 # Enable/Disable one or more pretty-printers.
    313 #
    314 # This is intended for use when a broken pretty-printer is shipped/installed
    315 # and the user wants to disable that printer without disabling all the other
    316 # printers.
    317 #
    318 # A useful addition would be -v (verbose) to show each printer affected.
    319 
    320 class EnablePrettyPrinter (gdb.Command):
    321     """GDB command to enable the specified pretty-printer.
    322 
    323     Usage: enable pretty-printer [object-regexp [name-regexp]]
    324 
    325     OBJECT-REGEXP is a regular expression matching the objects to examine.
    326     Objects are "global", the program space's file, and the objfiles within
    327     that program space.
    328 
    329     NAME-REGEXP matches the name of the pretty-printer.
    330     Individual printers in a collection are named as
    331     printer-name;subprinter-name.
    332     """
    333 
    334     def __init__(self):
    335         super(EnablePrettyPrinter, self).__init__("enable pretty-printer",
    336                                                    gdb.COMMAND_DATA)
    337 
    338     def invoke(self, arg, from_tty):
    339         """GDB calls this to perform the command."""
    340         do_enable_pretty_printer(arg, True)
    341 
    342 
    343 class DisablePrettyPrinter (gdb.Command):
    344     """GDB command to disable the specified pretty-printer.
    345 
    346     Usage: disable pretty-printer [object-regexp [name-regexp]]
    347 
    348     OBJECT-REGEXP is a regular expression matching the objects to examine.
    349     Objects are "global", the program space's file, and the objfiles within
    350     that program space.
    351 
    352     NAME-REGEXP matches the name of the pretty-printer.
    353     Individual printers in a collection are named as
    354     printer-name;subprinter-name.
    355     """
    356 
    357     def __init__(self):
    358         super(DisablePrettyPrinter, self).__init__("disable pretty-printer",
    359                                                    gdb.COMMAND_DATA)
    360 
    361     def invoke(self, arg, from_tty):
    362         """GDB calls this to perform the command."""
    363         do_enable_pretty_printer(arg, False)
    364 
    365 
    366 def register_pretty_printer_commands():
    367     """Call from a top level script to install the pretty-printer commands."""
    368     InfoPrettyPrinter()
    369     EnablePrettyPrinter()
    370     DisablePrettyPrinter()
    371