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