GDB (xrefs)

pretty_printers.py
Go to the documentation of this file.
1 # Pretty-printer commands.
2 # Copyright (C) 2010-2018 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 = 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
167 def 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
186 def 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
205 def 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
213 def 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
221 def 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
279 def 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
316 class 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
339 class 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
362 def register_pretty_printer_commands():
363 """Call from a top level script to install the pretty-printer commands."""
364 InfoPrettyPrinter()
365 EnablePrettyPrinter()
366 DisablePrettyPrinter()
367
368 register_pretty_printer_commands()
gdb.command.pretty_printers.InfoPrettyPrinter.invoke
def invoke(self, arg, from_tty)
Definition: pretty_printers.py:152
gdb.command.pretty_printers.DisablePrettyPrinter.invoke
def invoke(self, arg, from_tty)
Definition: pretty_printers.py:357
gdb.command.pretty_printers.InfoPrettyPrinter.invoke1
def invoke1(self, title, printer_list, obj_name_to_match, object_re, name_re, subname_re)
Definition: pretty_printers.py:146
gdb.command.pretty_printers.InfoPrettyPrinter.enabled_string
def enabled_string(printer)
Definition: pretty_printers.py:103
gdb.command.pretty_printers.DisablePrettyPrinter.__init__
def __init__(self)
Definition: pretty_printers.py:353
gdb.command.pretty_printers.InfoPrettyPrinter
Definition: pretty_printers.py:84
gdb.command.pretty_printers.count_all_enabled_printers
def count_all_enabled_printers()
Definition: pretty_printers.py:186
gdb.command.pretty_printers.do_enable_pretty_printer
def do_enable_pretty_printer(arg, flag)
Definition: pretty_printers.py:279
gdb.command.pretty_printers.parse_printer_regexps
def parse_printer_regexps(arg)
Definition: pretty_printers.py:24
gdb.command.pretty_printers.InfoPrettyPrinter.__init__
def __init__(self)
Definition: pretty_printers.py:98
gdb.command.pretty_printers.show_pretty_printer_enabled_summary
def show_pretty_printer_enabled_summary()
Definition: pretty_printers.py:213
gdb.command.pretty_printers.InfoPrettyPrinter.list_pretty_printers
def list_pretty_printers(self, pretty_printers, name_re, subname_re)
Definition: pretty_printers.py:123
gdb.command.pretty_printers.register_pretty_printer_commands
def register_pretty_printer_commands()
Definition: pretty_printers.py:362
gdb.command.pretty_printers.count_enabled_printers
def count_enabled_printers(pretty_printers)
Definition: pretty_printers.py:167
gdb.command.pretty_printers.do_enable_pretty_printer_1
def do_enable_pretty_printer_1(pretty_printers, name_re, subname_re, flag)
Definition: pretty_printers.py:221
gdb.command.pretty_printers.EnablePrettyPrinter.invoke
def invoke(self, arg, from_tty)
Definition: pretty_printers.py:334
gdb.command.pretty_printers.EnablePrettyPrinter.__init__
def __init__(self)
Definition: pretty_printers.py:330
gdb.command.pretty_printers.InfoPrettyPrinter.printer_name
def printer_name(printer)
Definition: pretty_printers.py:111
gdb.command.pretty_printers.printer_enabled_p
def printer_enabled_p(printer)
Definition: pretty_printers.py:76
gdb.command.pretty_printers.pluralize
def pluralize(text, n, suffix="s")
Definition: pretty_printers.py:205
gdb.command.pretty_printers.EnablePrettyPrinter
Definition: pretty_printers.py:316
return
return
Definition: gnu-nat.c:1871
gdb.command.pretty_printers.DisablePrettyPrinter
Definition: pretty_printers.py:339