1# Pretty-printer commands. 2# Copyright (C) 2010-2013 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 = sorted (copy.copy(pretty_printers), 128 key = self.printer_name) 129 for printer in sorted_pretty_printers: 130 name = self.printer_name(printer) 131 enabled = self.enabled_string(printer) 132 if name_re.match(name): 133 print (" %s%s" % (name, enabled)) 134 if (hasattr(printer, "subprinters") and 135 printer.subprinters is not None): 136 sorted_subprinters = sorted (copy.copy(printer.subprinters), 137 key = self.printer_name) 138 for subprinter in sorted_subprinters: 139 if (not subname_re or 140 subname_re.match(subprinter.name)): 141 print (" %s%s" % 142 (subprinter.name, 143 self.enabled_string(subprinter))) 144 145 def invoke1(self, title, printer_list, 146 obj_name_to_match, object_re, name_re, subname_re): 147 """Subroutine of invoke to simplify it.""" 148 if printer_list and object_re.match(obj_name_to_match): 149 print (title) 150 self.list_pretty_printers(printer_list, name_re, subname_re) 151 152 def invoke(self, arg, from_tty): 153 """GDB calls this to perform the command.""" 154 (object_re, name_re, subname_re) = parse_printer_regexps(arg) 155 self.invoke1("global pretty-printers:", gdb.pretty_printers, 156 "global", object_re, name_re, subname_re) 157 cp = gdb.current_progspace() 158 self.invoke1("progspace %s pretty-printers:" % cp.filename, 159 cp.pretty_printers, "progspace", 160 object_re, name_re, subname_re) 161 for objfile in gdb.objfiles(): 162 self.invoke1(" objfile %s pretty-printers:" % objfile.filename, 163 objfile.pretty_printers, objfile.filename, 164 object_re, name_re, subname_re) 165 166 167def count_enabled_printers(pretty_printers): 168 """Return a 2-tuple of number of enabled and total printers.""" 169 enabled = 0 170 total = 0 171 for printer in pretty_printers: 172 if (hasattr(printer, "subprinters") 173 and printer.subprinters is not None): 174 if printer_enabled_p(printer): 175 for subprinter in printer.subprinters: 176 if printer_enabled_p(subprinter): 177 enabled += 1 178 total += len(printer.subprinters) 179 else: 180 if printer_enabled_p(printer): 181 enabled += 1 182 total += 1 183 return (enabled, total) 184 185 186def count_all_enabled_printers(): 187 """Return a 2-tuble of the enabled state and total number of all printers. 188 This includes subprinters. 189 """ 190 enabled_count = 0 191 total_count = 0 192 (t_enabled, t_total) = count_enabled_printers(gdb.pretty_printers) 193 enabled_count += t_enabled 194 total_count += t_total 195 (t_enabled, t_total) = count_enabled_printers(gdb.current_progspace().pretty_printers) 196 enabled_count += t_enabled 197 total_count += t_total 198 for objfile in gdb.objfiles(): 199 (t_enabled, t_total) = count_enabled_printers(objfile.pretty_printers) 200 enabled_count += t_enabled 201 total_count += t_total 202 return (enabled_count, total_count) 203 204 205def pluralize(text, n, suffix="s"): 206 """Return TEXT pluralized if N != 1.""" 207 if n != 1: 208 return "%s%s" % (text, suffix) 209 else: 210 return text 211 212 213def show_pretty_printer_enabled_summary(): 214 """Print the number of printers enabled/disabled. 215 We count subprinters individually. 216 """ 217 (enabled_count, total_count) = count_all_enabled_printers() 218 print ("%d of %d printers enabled" % (enabled_count, total_count)) 219 220 221def do_enable_pretty_printer_1 (pretty_printers, name_re, subname_re, flag): 222 """Worker for enabling/disabling pretty-printers. 223 224 Arguments: 225 pretty_printers: list of pretty-printers 226 name_re: regular-expression object to select printers 227 subname_re: regular expression object to select subprinters or None 228 if all are affected 229 flag: True for Enable, False for Disable 230 231 Returns: 232 The number of printers affected. 233 This is just for informational purposes for the user. 234 """ 235 total = 0 236 for printer in pretty_printers: 237 if (hasattr(printer, "name") and name_re.match(printer.name) or 238 hasattr(printer, "__name__") and name_re.match(printer.__name__)): 239 if (hasattr(printer, "subprinters") and 240 printer.subprinters is not None): 241 if not subname_re: 242 # Only record printers that change state. 243 if printer_enabled_p(printer) != flag: 244 for subprinter in printer.subprinters: 245 if printer_enabled_p(subprinter): 246 total += 1 247 # NOTE: We preserve individual subprinter settings. 248 printer.enabled = flag 249 else: 250 # NOTE: Whether this actually disables the subprinter 251 # depends on whether the printer's lookup function supports 252 # the "enable" API. We can only assume it does. 253 for subprinter in printer.subprinters: 254 if subname_re.match(subprinter.name): 255 # Only record printers that change state. 256 if (printer_enabled_p(printer) and 257 printer_enabled_p(subprinter) != flag): 258 total += 1 259 subprinter.enabled = flag 260 else: 261 # This printer has no subprinters. 262 # If the user does "disable pretty-printer .* .* foo" 263 # should we disable printers that don't have subprinters? 264 # How do we apply "foo" in this context? Since there is no 265 # "foo" subprinter it feels like we should skip this printer. 266 # There's still the issue of how to handle 267 # "disable pretty-printer .* .* .*", and every other variation 268 # that can match everything. For now punt and only support 269 # "disable pretty-printer .* .*" (i.e. subname is elided) 270 # to disable everything. 271 if not subname_re: 272 # Only record printers that change state. 273 if printer_enabled_p(printer) != flag: 274 total += 1 275 printer.enabled = flag 276 return total 277 278 279def do_enable_pretty_printer (arg, flag): 280 """Internal worker for enabling/disabling pretty-printers.""" 281 (object_re, name_re, subname_re) = parse_printer_regexps(arg) 282 283 total = 0 284 if object_re.match("global"): 285 total += do_enable_pretty_printer_1(gdb.pretty_printers, 286 name_re, subname_re, flag) 287 cp = gdb.current_progspace() 288 if object_re.match("progspace"): 289 total += do_enable_pretty_printer_1(cp.pretty_printers, 290 name_re, subname_re, flag) 291 for objfile in gdb.objfiles(): 292 if object_re.match(objfile.filename): 293 total += do_enable_pretty_printer_1(objfile.pretty_printers, 294 name_re, subname_re, flag) 295 296 if flag: 297 state = "enabled" 298 else: 299 state = "disabled" 300 print ("%d %s %s" % (total, pluralize("printer", total), state)) 301 302 # Print the total list of printers currently enabled/disabled. 303 # This is to further assist the user in determining whether the result 304 # is expected. Since we use regexps to select it's useful. 305 show_pretty_printer_enabled_summary() 306 307 308# Enable/Disable one or more pretty-printers. 309# 310# This is intended for use when a broken pretty-printer is shipped/installed 311# and the user wants to disable that printer without disabling all the other 312# printers. 313# 314# A useful addition would be -v (verbose) to show each printer affected. 315 316class EnablePrettyPrinter (gdb.Command): 317 """GDB command to enable the specified pretty-printer. 318 319 Usage: enable pretty-printer [object-regexp [name-regexp]] 320 321 OBJECT-REGEXP is a regular expression matching the objects to examine. 322 Objects are "global", the program space's file, and the objfiles within 323 that program space. 324 325 NAME-REGEXP matches the name of the pretty-printer. 326 Individual printers in a collection are named as 327 printer-name;subprinter-name. 328 """ 329 330 def __init__(self): 331 super(EnablePrettyPrinter, self).__init__("enable pretty-printer", 332 gdb.COMMAND_DATA) 333 334 def invoke(self, arg, from_tty): 335 """GDB calls this to perform the command.""" 336 do_enable_pretty_printer(arg, True) 337 338 339class DisablePrettyPrinter (gdb.Command): 340 """GDB command to disable the specified pretty-printer. 341 342 Usage: disable pretty-printer [object-regexp [name-regexp]] 343 344 OBJECT-REGEXP is a regular expression matching the objects to examine. 345 Objects are "global", the program space's file, and the objfiles within 346 that program space. 347 348 NAME-REGEXP matches the name of the pretty-printer. 349 Individual printers in a collection are named as 350 printer-name;subprinter-name. 351 """ 352 353 def __init__(self): 354 super(DisablePrettyPrinter, self).__init__("disable pretty-printer", 355 gdb.COMMAND_DATA) 356 357 def invoke(self, arg, from_tty): 358 """GDB calls this to perform the command.""" 359 do_enable_pretty_printer(arg, False) 360 361 362def register_pretty_printer_commands(): 363 """Call from a top level script to install the pretty-printer commands.""" 364 InfoPrettyPrinter() 365 EnablePrettyPrinter() 366 DisablePrettyPrinter() 367 368register_pretty_printer_commands() 369