]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/python/lib/gdb/command/pretty_printers.py
gas: introduce .errif and .warnif
[thirdparty/binutils-gdb.git] / gdb / python / lib / gdb / command / pretty_printers.py
CommitLineData
7b51bc51 1# Pretty-printer commands.
d01e8234 2# Copyright (C) 2010-2025 Free Software Foundation, Inc.
7b51bc51
DE
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
7b51bc51
DE
20import re
21
c2cf30e7
TT
22import gdb
23
7b51bc51
DE
24
25def parse_printer_regexps(arg):
26 """Internal utility to parse a pretty-printer command argv.
27
28 Arguments:
29 arg: The arguments to the command. The format is:
30 [object-regexp [name-regexp]].
31 Individual printers in a collection are named as
4e04c971 32 printer-name;subprinter-name.
7b51bc51
DE
33
34 Returns:
35 The result is a 3-tuple of compiled regular expressions, except that
36 the resulting compiled subprinter regexp is None if not provided.
37
38 Raises:
39 SyntaxError: an error processing ARG
40 """
41
13123da8 42 argv = gdb.string_to_argv(arg)
7b51bc51
DE
43 argc = len(argv)
44 object_regexp = "" # match everything
45 name_regexp = "" # match everything
46 subname_regexp = None
47 if argc > 3:
48 raise SyntaxError("too many arguments")
49 if argc >= 1:
50 object_regexp = argv[0]
51 if argc >= 2:
4e04c971 52 name_subname = argv[1].split(";", 1)
7b51bc51
DE
53 name_regexp = name_subname[0]
54 if len(name_subname) == 2:
55 subname_regexp = name_subname[1]
56 # That re.compile raises SyntaxError was determined empirically.
57 # We catch it and reraise it to provide a slightly more useful
58 # error message for the user.
59 try:
60 object_re = re.compile(object_regexp)
61 except SyntaxError:
62 raise SyntaxError("invalid object regexp: %s" % object_regexp)
63 try:
13123da8 64 name_re = re.compile(name_regexp)
7b51bc51
DE
65 except SyntaxError:
66 raise SyntaxError("invalid name regexp: %s" % name_regexp)
67 if subname_regexp is not None:
68 try:
69 subname_re = re.compile(subname_regexp)
70 except SyntaxError:
71 raise SyntaxError("invalid subname regexp: %s" % subname_regexp)
72 else:
73 subname_re = None
13123da8 74 return (object_re, name_re, subname_re)
7b51bc51
DE
75
76
77def printer_enabled_p(printer):
78 """Internal utility to see if printer (or subprinter) is enabled."""
79 if hasattr(printer, "enabled"):
80 return printer.enabled
81 else:
82 return True
83
84
85class InfoPrettyPrinter(gdb.Command):
86 """GDB command to list all registered pretty-printers.
87
13123da8 88 Usage: info pretty-printer [OBJECT-REGEXP [NAME-REGEXP]]
7b51bc51 89
13123da8
SM
90 OBJECT-REGEXP is a regular expression matching the objects to list.
91 Objects are "global", the program space's file, and the objfiles within
92 that program space.
7b51bc51 93
13123da8
SM
94 NAME-REGEXP matches the name of the pretty-printer.
95 Individual printers in a collection are named as
96 printer-name;subprinter-name."""
7b51bc51 97
13123da8
SM
98 def __init__(self):
99 super(InfoPrettyPrinter, self).__init__("info pretty-printer", gdb.COMMAND_DATA)
7b51bc51
DE
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).
13123da8
SM
126 sorted_pretty_printers = sorted(
127 copy.copy(pretty_printers), key=self.printer_name
128 )
7b51bc51
DE
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):
13123da8
SM
133 print(" %s%s" % (name, enabled))
134 if hasattr(printer, "subprinters") and printer.subprinters is not None:
135 sorted_subprinters = sorted(
136 copy.copy(printer.subprinters), key=self.printer_name
137 )
7b51bc51 138 for subprinter in sorted_subprinters:
13123da8
SM
139 if not subname_re or subname_re.match(subprinter.name):
140 print(
141 " %s%s"
142 % (subprinter.name, self.enabled_string(subprinter))
143 )
144
145 def invoke1(
146 self, title, printer_list, obj_name_to_match, object_re, name_re, subname_re
147 ):
75c8c9d7 148 """Subroutine of invoke to simplify it."""
7b51bc51 149 if printer_list and object_re.match(obj_name_to_match):
13123da8 150 print(title)
7b51bc51
DE
151 self.list_pretty_printers(printer_list, name_re, subname_re)
152
153 def invoke(self, arg, from_tty):
154 """GDB calls this to perform the command."""
155 (object_re, name_re, subname_re) = parse_printer_regexps(arg)
13123da8
SM
156 self.invoke1(
157 "global pretty-printers:",
158 gdb.pretty_printers,
159 "global",
160 object_re,
161 name_re,
162 subname_re,
163 )
7b51bc51 164 cp = gdb.current_progspace()
13123da8
SM
165 self.invoke1(
166 "progspace %s pretty-printers:" % cp.filename,
167 cp.pretty_printers,
168 "progspace",
169 object_re,
170 name_re,
171 subname_re,
172 )
7b51bc51 173 for objfile in gdb.objfiles():
13123da8
SM
174 self.invoke1(
175 "objfile %s pretty-printers:" % objfile.filename,
176 objfile.pretty_printers,
177 objfile.filename,
178 object_re,
179 name_re,
180 subname_re,
181 )
7b51bc51
DE
182
183
184def count_enabled_printers(pretty_printers):
185 """Return a 2-tuple of number of enabled and total printers."""
186 enabled = 0
187 total = 0
188 for printer in pretty_printers:
13123da8 189 if hasattr(printer, "subprinters") and printer.subprinters is not None:
7b51bc51
DE
190 if printer_enabled_p(printer):
191 for subprinter in printer.subprinters:
192 if printer_enabled_p(subprinter):
193 enabled += 1
194 total += len(printer.subprinters)
195 else:
196 if printer_enabled_p(printer):
197 enabled += 1
198 total += 1
199 return (enabled, total)
200
201
202def count_all_enabled_printers():
203 """Return a 2-tuble of the enabled state and total number of all printers.
204 This includes subprinters.
205 """
206 enabled_count = 0
207 total_count = 0
208 (t_enabled, t_total) = count_enabled_printers(gdb.pretty_printers)
209 enabled_count += t_enabled
210 total_count += t_total
13123da8
SM
211 (t_enabled, t_total) = count_enabled_printers(
212 gdb.current_progspace().pretty_printers
213 )
7b51bc51
DE
214 enabled_count += t_enabled
215 total_count += t_total
216 for objfile in gdb.objfiles():
217 (t_enabled, t_total) = count_enabled_printers(objfile.pretty_printers)
218 enabled_count += t_enabled
219 total_count += t_total
220 return (enabled_count, total_count)
221
222
223def pluralize(text, n, suffix="s"):
224 """Return TEXT pluralized if N != 1."""
225 if n != 1:
226 return "%s%s" % (text, suffix)
227 else:
228 return text
229
230
231def show_pretty_printer_enabled_summary():
232 """Print the number of printers enabled/disabled.
233 We count subprinters individually.
234 """
235 (enabled_count, total_count) = count_all_enabled_printers()
13123da8 236 print("%d of %d printers enabled" % (enabled_count, total_count))
7b51bc51
DE
237
238
13123da8 239def do_enable_pretty_printer_1(pretty_printers, name_re, subname_re, flag):
7b51bc51
DE
240 """Worker for enabling/disabling pretty-printers.
241
242 Arguments:
243 pretty_printers: list of pretty-printers
244 name_re: regular-expression object to select printers
245 subname_re: regular expression object to select subprinters or None
246 if all are affected
247 flag: True for Enable, False for Disable
248
249 Returns:
250 The number of printers affected.
251 This is just for informational purposes for the user.
252 """
253 total = 0
254 for printer in pretty_printers:
13123da8
SM
255 if (
256 hasattr(printer, "name")
257 and name_re.match(printer.name)
258 or hasattr(printer, "__name__")
259 and name_re.match(printer.__name__)
260 ):
261 if hasattr(printer, "subprinters") and printer.subprinters is not None:
7b51bc51
DE
262 if not subname_re:
263 # Only record printers that change state.
264 if printer_enabled_p(printer) != flag:
265 for subprinter in printer.subprinters:
266 if printer_enabled_p(subprinter):
267 total += 1
268 # NOTE: We preserve individual subprinter settings.
269 printer.enabled = flag
270 else:
271 # NOTE: Whether this actually disables the subprinter
272 # depends on whether the printer's lookup function supports
273 # the "enable" API. We can only assume it does.
274 for subprinter in printer.subprinters:
275 if subname_re.match(subprinter.name):
276 # Only record printers that change state.
13123da8
SM
277 if (
278 printer_enabled_p(printer)
279 and printer_enabled_p(subprinter) != flag
280 ):
281 total += 1
282 subprinter.enabled = flag
7b51bc51
DE
283 else:
284 # This printer has no subprinters.
285 # If the user does "disable pretty-printer .* .* foo"
286 # should we disable printers that don't have subprinters?
287 # How do we apply "foo" in this context? Since there is no
288 # "foo" subprinter it feels like we should skip this printer.
289 # There's still the issue of how to handle
290 # "disable pretty-printer .* .* .*", and every other variation
291 # that can match everything. For now punt and only support
292 # "disable pretty-printer .* .*" (i.e. subname is elided)
293 # to disable everything.
294 if not subname_re:
295 # Only record printers that change state.
296 if printer_enabled_p(printer) != flag:
297 total += 1
298 printer.enabled = flag
299 return total
300
301
13123da8 302def do_enable_pretty_printer(arg, flag):
7b51bc51
DE
303 """Internal worker for enabling/disabling pretty-printers."""
304 (object_re, name_re, subname_re) = parse_printer_regexps(arg)
305
306 total = 0
307 if object_re.match("global"):
13123da8
SM
308 total += do_enable_pretty_printer_1(
309 gdb.pretty_printers, name_re, subname_re, flag
310 )
7b51bc51
DE
311 cp = gdb.current_progspace()
312 if object_re.match("progspace"):
13123da8
SM
313 total += do_enable_pretty_printer_1(
314 cp.pretty_printers, name_re, subname_re, flag
315 )
7b51bc51
DE
316 for objfile in gdb.objfiles():
317 if object_re.match(objfile.filename):
13123da8
SM
318 total += do_enable_pretty_printer_1(
319 objfile.pretty_printers, name_re, subname_re, flag
320 )
7b51bc51
DE
321
322 if flag:
323 state = "enabled"
324 else:
325 state = "disabled"
13123da8 326 print("%d %s %s" % (total, pluralize("printer", total), state))
7b51bc51
DE
327
328 # Print the total list of printers currently enabled/disabled.
329 # This is to further assist the user in determining whether the result
330 # is expected. Since we use regexps to select it's useful.
331 show_pretty_printer_enabled_summary()
332
333
334# Enable/Disable one or more pretty-printers.
335#
336# This is intended for use when a broken pretty-printer is shipped/installed
337# and the user wants to disable that printer without disabling all the other
338# printers.
339#
340# A useful addition would be -v (verbose) to show each printer affected.
341
13123da8
SM
342
343class EnablePrettyPrinter(gdb.Command):
7b51bc51
DE
344 """GDB command to enable the specified pretty-printer.
345
13123da8 346 Usage: enable pretty-printer [OBJECT-REGEXP [NAME-REGEXP]]
7b51bc51 347
13123da8
SM
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.
7b51bc51 351
13123da8
SM
352 NAME-REGEXP matches the name of the pretty-printer.
353 Individual printers in a collection are named as
354 printer-name;subprinter-name."""
7b51bc51
DE
355
356 def __init__(self):
13123da8
SM
357 super(EnablePrettyPrinter, self).__init__(
358 "enable pretty-printer", gdb.COMMAND_DATA
359 )
7b51bc51
DE
360
361 def invoke(self, arg, from_tty):
362 """GDB calls this to perform the command."""
363 do_enable_pretty_printer(arg, True)
364
365
13123da8 366class DisablePrettyPrinter(gdb.Command):
7b51bc51
DE
367 """GDB command to disable the specified pretty-printer.
368
13123da8 369 Usage: disable pretty-printer [OBJECT-REGEXP [NAME-REGEXP]]
7b51bc51 370
13123da8
SM
371 OBJECT-REGEXP is a regular expression matching the objects to examine.
372 Objects are "global", the program space's file, and the objfiles within
373 that program space.
7b51bc51 374
13123da8
SM
375 NAME-REGEXP matches the name of the pretty-printer.
376 Individual printers in a collection are named as
377 printer-name;subprinter-name."""
7b51bc51
DE
378
379 def __init__(self):
13123da8
SM
380 super(DisablePrettyPrinter, self).__init__(
381 "disable pretty-printer", gdb.COMMAND_DATA
382 )
7b51bc51
DE
383
384 def invoke(self, arg, from_tty):
385 """GDB calls this to perform the command."""
386 do_enable_pretty_printer(arg, False)
387
388
389def register_pretty_printer_commands():
390 """Call from a top level script to install the pretty-printer commands."""
391 InfoPrettyPrinter()
392 EnablePrettyPrinter()
393 DisablePrettyPrinter()
5e239b84 394
13123da8 395
5e239b84 396register_pretty_printer_commands()