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