GDB (API)
|
00001 # Pretty-printer commands. 00002 # Copyright (C) 2010-2013 Free Software Foundation, Inc. 00003 00004 # This program is free software; you can redistribute it and/or modify 00005 # it under the terms of the GNU General Public License as published by 00006 # the Free Software Foundation; either version 3 of the License, or 00007 # (at your option) any later version. 00008 # 00009 # This program is distributed in the hope that it will be useful, 00010 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 # GNU General Public License for more details. 00013 # 00014 # You should have received a copy of the GNU General Public License 00015 # along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 00017 """GDB commands for working with pretty-printers.""" 00018 00019 import copy 00020 import gdb 00021 import re 00022 00023 00024 def parse_printer_regexps(arg): 00025 """Internal utility to parse a pretty-printer command argv. 00026 00027 Arguments: 00028 arg: The arguments to the command. The format is: 00029 [object-regexp [name-regexp]]. 00030 Individual printers in a collection are named as 00031 printer-name;subprinter-name. 00032 00033 Returns: 00034 The result is a 3-tuple of compiled regular expressions, except that 00035 the resulting compiled subprinter regexp is None if not provided. 00036 00037 Raises: 00038 SyntaxError: an error processing ARG 00039 """ 00040 00041 argv = gdb.string_to_argv(arg); 00042 argc = len(argv) 00043 object_regexp = "" # match everything 00044 name_regexp = "" # match everything 00045 subname_regexp = None 00046 if argc > 3: 00047 raise SyntaxError("too many arguments") 00048 if argc >= 1: 00049 object_regexp = argv[0] 00050 if argc >= 2: 00051 name_subname = argv[1].split(";", 1) 00052 name_regexp = name_subname[0] 00053 if len(name_subname) == 2: 00054 subname_regexp = name_subname[1] 00055 # That re.compile raises SyntaxError was determined empirically. 00056 # We catch it and reraise it to provide a slightly more useful 00057 # error message for the user. 00058 try: 00059 object_re = re.compile(object_regexp) 00060 except SyntaxError: 00061 raise SyntaxError("invalid object regexp: %s" % object_regexp) 00062 try: 00063 name_re = re.compile (name_regexp) 00064 except SyntaxError: 00065 raise SyntaxError("invalid name regexp: %s" % name_regexp) 00066 if subname_regexp is not None: 00067 try: 00068 subname_re = re.compile(subname_regexp) 00069 except SyntaxError: 00070 raise SyntaxError("invalid subname regexp: %s" % subname_regexp) 00071 else: 00072 subname_re = None 00073 return(object_re, name_re, subname_re) 00074 00075 00076 def printer_enabled_p(printer): 00077 """Internal utility to see if printer (or subprinter) is enabled.""" 00078 if hasattr(printer, "enabled"): 00079 return printer.enabled 00080 else: 00081 return True 00082 00083 00084 class InfoPrettyPrinter(gdb.Command): 00085 """GDB command to list all registered pretty-printers. 00086 00087 Usage: info pretty-printer [object-regexp [name-regexp]] 00088 00089 OBJECT-REGEXP is a regular expression matching the objects to list. 00090 Objects are "global", the program space's file, and the objfiles within 00091 that program space. 00092 00093 NAME-REGEXP matches the name of the pretty-printer. 00094 Individual printers in a collection are named as 00095 printer-name;subprinter-name. 00096 """ 00097 00098 def __init__ (self): 00099 super(InfoPrettyPrinter, self).__init__("info pretty-printer", 00100 gdb.COMMAND_DATA) 00101 00102 @staticmethod 00103 def enabled_string(printer): 00104 """Return "" if PRINTER is enabled, otherwise " [disabled]".""" 00105 if printer_enabled_p(printer): 00106 return "" 00107 else: 00108 return " [disabled]" 00109 00110 @staticmethod 00111 def printer_name(printer): 00112 """Return the printer's name.""" 00113 if hasattr(printer, "name"): 00114 return printer.name 00115 if hasattr(printer, "__name__"): 00116 return printer.__name__ 00117 # This "shouldn't happen", but the public API allows for 00118 # direct additions to the pretty-printer list, and we shouldn't 00119 # crash because someone added a bogus printer. 00120 # Plus we want to give the user a way to list unknown printers. 00121 return "unknown" 00122 00123 def list_pretty_printers(self, pretty_printers, name_re, subname_re): 00124 """Print a list of pretty-printers.""" 00125 # A potential enhancement is to provide an option to list printers in 00126 # "lookup order" (i.e. unsorted). 00127 sorted_pretty_printers = sorted (copy.copy(pretty_printers), 00128 key = self.printer_name) 00129 for printer in sorted_pretty_printers: 00130 name = self.printer_name(printer) 00131 enabled = self.enabled_string(printer) 00132 if name_re.match(name): 00133 print (" %s%s" % (name, enabled)) 00134 if (hasattr(printer, "subprinters") and 00135 printer.subprinters is not None): 00136 sorted_subprinters = sorted (copy.copy(printer.subprinters), 00137 key = self.printer_name) 00138 for subprinter in sorted_subprinters: 00139 if (not subname_re or 00140 subname_re.match(subprinter.name)): 00141 print (" %s%s" % 00142 (subprinter.name, 00143 self.enabled_string(subprinter))) 00144 00145 def invoke1(self, title, printer_list, 00146 obj_name_to_match, object_re, name_re, subname_re): 00147 """Subroutine of invoke to simplify it.""" 00148 if printer_list and object_re.match(obj_name_to_match): 00149 print (title) 00150 self.list_pretty_printers(printer_list, name_re, subname_re) 00151 00152 def invoke(self, arg, from_tty): 00153 """GDB calls this to perform the command.""" 00154 (object_re, name_re, subname_re) = parse_printer_regexps(arg) 00155 self.invoke1("global pretty-printers:", gdb.pretty_printers, 00156 "global", object_re, name_re, subname_re) 00157 cp = gdb.current_progspace() 00158 self.invoke1("progspace %s pretty-printers:" % cp.filename, 00159 cp.pretty_printers, "progspace", 00160 object_re, name_re, subname_re) 00161 for objfile in gdb.objfiles(): 00162 self.invoke1(" objfile %s pretty-printers:" % objfile.filename, 00163 objfile.pretty_printers, objfile.filename, 00164 object_re, name_re, subname_re) 00165 00166 00167 def count_enabled_printers(pretty_printers): 00168 """Return a 2-tuple of number of enabled and total printers.""" 00169 enabled = 0 00170 total = 0 00171 for printer in pretty_printers: 00172 if (hasattr(printer, "subprinters") 00173 and printer.subprinters is not None): 00174 if printer_enabled_p(printer): 00175 for subprinter in printer.subprinters: 00176 if printer_enabled_p(subprinter): 00177 enabled += 1 00178 total += len(printer.subprinters) 00179 else: 00180 if printer_enabled_p(printer): 00181 enabled += 1 00182 total += 1 00183 return (enabled, total) 00184 00185 00186 def count_all_enabled_printers(): 00187 """Return a 2-tuble of the enabled state and total number of all printers. 00188 This includes subprinters. 00189 """ 00190 enabled_count = 0 00191 total_count = 0 00192 (t_enabled, t_total) = count_enabled_printers(gdb.pretty_printers) 00193 enabled_count += t_enabled 00194 total_count += t_total 00195 (t_enabled, t_total) = count_enabled_printers(gdb.current_progspace().pretty_printers) 00196 enabled_count += t_enabled 00197 total_count += t_total 00198 for objfile in gdb.objfiles(): 00199 (t_enabled, t_total) = count_enabled_printers(objfile.pretty_printers) 00200 enabled_count += t_enabled 00201 total_count += t_total 00202 return (enabled_count, total_count) 00203 00204 00205 def pluralize(text, n, suffix="s"): 00206 """Return TEXT pluralized if N != 1.""" 00207 if n != 1: 00208 return "%s%s" % (text, suffix) 00209 else: 00210 return text 00211 00212 00213 def show_pretty_printer_enabled_summary(): 00214 """Print the number of printers enabled/disabled. 00215 We count subprinters individually. 00216 """ 00217 (enabled_count, total_count) = count_all_enabled_printers() 00218 print ("%d of %d printers enabled" % (enabled_count, total_count)) 00219 00220 00221 def do_enable_pretty_printer_1 (pretty_printers, name_re, subname_re, flag): 00222 """Worker for enabling/disabling pretty-printers. 00223 00224 Arguments: 00225 pretty_printers: list of pretty-printers 00226 name_re: regular-expression object to select printers 00227 subname_re: regular expression object to select subprinters or None 00228 if all are affected 00229 flag: True for Enable, False for Disable 00230 00231 Returns: 00232 The number of printers affected. 00233 This is just for informational purposes for the user. 00234 """ 00235 total = 0 00236 for printer in pretty_printers: 00237 if (hasattr(printer, "name") and name_re.match(printer.name) or 00238 hasattr(printer, "__name__") and name_re.match(printer.__name__)): 00239 if (hasattr(printer, "subprinters") and 00240 printer.subprinters is not None): 00241 if not subname_re: 00242 # Only record printers that change state. 00243 if printer_enabled_p(printer) != flag: 00244 for subprinter in printer.subprinters: 00245 if printer_enabled_p(subprinter): 00246 total += 1 00247 # NOTE: We preserve individual subprinter settings. 00248 printer.enabled = flag 00249 else: 00250 # NOTE: Whether this actually disables the subprinter 00251 # depends on whether the printer's lookup function supports 00252 # the "enable" API. We can only assume it does. 00253 for subprinter in printer.subprinters: 00254 if subname_re.match(subprinter.name): 00255 # Only record printers that change state. 00256 if (printer_enabled_p(printer) and 00257 printer_enabled_p(subprinter) != flag): 00258 total += 1 00259 subprinter.enabled = flag 00260 else: 00261 # This printer has no subprinters. 00262 # If the user does "disable pretty-printer .* .* foo" 00263 # should we disable printers that don't have subprinters? 00264 # How do we apply "foo" in this context? Since there is no 00265 # "foo" subprinter it feels like we should skip this printer. 00266 # There's still the issue of how to handle 00267 # "disable pretty-printer .* .* .*", and every other variation 00268 # that can match everything. For now punt and only support 00269 # "disable pretty-printer .* .*" (i.e. subname is elided) 00270 # to disable everything. 00271 if not subname_re: 00272 # Only record printers that change state. 00273 if printer_enabled_p(printer) != flag: 00274 total += 1 00275 printer.enabled = flag 00276 return total 00277 00278 00279 def do_enable_pretty_printer (arg, flag): 00280 """Internal worker for enabling/disabling pretty-printers.""" 00281 (object_re, name_re, subname_re) = parse_printer_regexps(arg) 00282 00283 total = 0 00284 if object_re.match("global"): 00285 total += do_enable_pretty_printer_1(gdb.pretty_printers, 00286 name_re, subname_re, flag) 00287 cp = gdb.current_progspace() 00288 if object_re.match("progspace"): 00289 total += do_enable_pretty_printer_1(cp.pretty_printers, 00290 name_re, subname_re, flag) 00291 for objfile in gdb.objfiles(): 00292 if object_re.match(objfile.filename): 00293 total += do_enable_pretty_printer_1(objfile.pretty_printers, 00294 name_re, subname_re, flag) 00295 00296 if flag: 00297 state = "enabled" 00298 else: 00299 state = "disabled" 00300 print ("%d %s %s" % (total, pluralize("printer", total), state)) 00301 00302 # Print the total list of printers currently enabled/disabled. 00303 # This is to further assist the user in determining whether the result 00304 # is expected. Since we use regexps to select it's useful. 00305 show_pretty_printer_enabled_summary() 00306 00307 00308 # Enable/Disable one or more pretty-printers. 00309 # 00310 # This is intended for use when a broken pretty-printer is shipped/installed 00311 # and the user wants to disable that printer without disabling all the other 00312 # printers. 00313 # 00314 # A useful addition would be -v (verbose) to show each printer affected. 00315 00316 class EnablePrettyPrinter (gdb.Command): 00317 """GDB command to enable the specified pretty-printer. 00318 00319 Usage: enable pretty-printer [object-regexp [name-regexp]] 00320 00321 OBJECT-REGEXP is a regular expression matching the objects to examine. 00322 Objects are "global", the program space's file, and the objfiles within 00323 that program space. 00324 00325 NAME-REGEXP matches the name of the pretty-printer. 00326 Individual printers in a collection are named as 00327 printer-name;subprinter-name. 00328 """ 00329 00330 def __init__(self): 00331 super(EnablePrettyPrinter, self).__init__("enable pretty-printer", 00332 gdb.COMMAND_DATA) 00333 00334 def invoke(self, arg, from_tty): 00335 """GDB calls this to perform the command.""" 00336 do_enable_pretty_printer(arg, True) 00337 00338 00339 class DisablePrettyPrinter (gdb.Command): 00340 """GDB command to disable the specified pretty-printer. 00341 00342 Usage: disable pretty-printer [object-regexp [name-regexp]] 00343 00344 OBJECT-REGEXP is a regular expression matching the objects to examine. 00345 Objects are "global", the program space's file, and the objfiles within 00346 that program space. 00347 00348 NAME-REGEXP matches the name of the pretty-printer. 00349 Individual printers in a collection are named as 00350 printer-name;subprinter-name. 00351 """ 00352 00353 def __init__(self): 00354 super(DisablePrettyPrinter, self).__init__("disable pretty-printer", 00355 gdb.COMMAND_DATA) 00356 00357 def invoke(self, arg, from_tty): 00358 """GDB calls this to perform the command.""" 00359 do_enable_pretty_printer(arg, False) 00360 00361 00362 def register_pretty_printer_commands(): 00363 """Call from a top level script to install the pretty-printer commands.""" 00364 InfoPrettyPrinter() 00365 EnablePrettyPrinter() 00366 DisablePrettyPrinter() 00367 00368 register_pretty_printer_commands()