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 19import copy 20import gdb 21import re 22 23 24def 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 76def 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 84class 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 171def 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 190def 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 209def 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 217def 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 225def 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 283def 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 320class 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 343class 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 366def register_pretty_printer_commands(): 367 """Call from a top level script to install the pretty-printer commands.""" 368 InfoPrettyPrinter() 369 EnablePrettyPrinter() 370 DisablePrettyPrinter() 371