blob: 450c5bf6d53538db1c785cd3de3835dbd0e1ae85 [file] [log] [blame]
Ben Cheng7334f0a2014-04-30 14:28:17 -07001# Frame-filter commands.
2# Copyright (C) 2013-2014 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 frame-filters."""
18
19import sys
20import gdb
21import copy
22from gdb.FrameIterator import FrameIterator
23from gdb.FrameDecorator import FrameDecorator
24import gdb.frames
25import itertools
26
27# GDB Commands.
28class SetFilterPrefixCmd(gdb.Command):
29 """Prefix command for 'set' frame-filter related operations."""
30
31 def __init__(self):
32 super(SetFilterPrefixCmd, self).__init__("set frame-filter",
33 gdb.COMMAND_OBSCURE,
34 gdb.COMPLETE_NONE, True)
35
36class ShowFilterPrefixCmd(gdb.Command):
37 """Prefix command for 'show' frame-filter related operations."""
38 def __init__(self):
39 super(ShowFilterPrefixCmd, self).__init__("show frame-filter",
40 gdb.COMMAND_OBSCURE,
41 gdb.COMPLETE_NONE, True)
42class InfoFrameFilter(gdb.Command):
43 """List all registered Python frame-filters.
44
45 Usage: info frame-filters
46 """
47
48 def __init__(self):
49 super(InfoFrameFilter, self).__init__("info frame-filter",
50 gdb.COMMAND_DATA)
51 @staticmethod
52 def enabled_string(state):
53 """Return "Yes" if filter is enabled, otherwise "No"."""
54 if state:
55 return "Yes"
56 else:
57 return "No"
58
59 def list_frame_filters(self, frame_filters):
60 """ Internal worker function to list and print frame filters
61 in a dictionary.
62
63 Arguments:
64 frame_filters: The name of the dictionary, as
65 specified by GDB user commands.
66 """
67
68 sorted_frame_filters = sorted(frame_filters.items(),
69 key=lambda i: gdb.frames.get_priority(i[1]),
70 reverse=True)
71
72 if len(sorted_frame_filters) == 0:
73 print(" No frame filters registered.")
74 else:
75 print(" Priority Enabled Name")
76 for frame_filter in sorted_frame_filters:
77 name = frame_filter[0]
78 try:
79 priority = '{:<8}'.format(
80 str(gdb.frames.get_priority(frame_filter[1])))
81 enabled = '{:<7}'.format(
82 self.enabled_string(gdb.frames.get_enabled(frame_filter[1])))
83 except Exception:
84 e = sys.exc_info()[1]
85 print(" Error printing filter '"+name+"': "+str(e))
86 else:
87 print(" %s %s %s" % (priority, enabled, name))
88
89 def print_list(self, title, filter_list, blank_line):
90 print(title)
91 self.list_frame_filters(filter_list)
92 if blank_line:
93 print("")
94
95 def invoke(self, arg, from_tty):
96 self.print_list("global frame-filters:", gdb.frame_filters, True)
97
98 cp = gdb.current_progspace()
99 self.print_list("progspace %s frame-filters:" % cp.filename,
100 cp.frame_filters, True)
101
102 for objfile in gdb.objfiles():
103 self.print_list("objfile %s frame-filters:" % objfile.filename,
104 objfile.frame_filters, False)
105
106# Internal enable/disable functions.
107
108def _enable_parse_arg(cmd_name, arg):
109 """ Internal worker function to take an argument from
110 enable/disable and return a tuple of arguments.
111
112 Arguments:
113 cmd_name: Name of the command invoking this function.
114 args: The argument as a string.
115
116 Returns:
117 A tuple containing the dictionary, and the argument, or just
118 the dictionary in the case of "all".
119 """
120
121 argv = gdb.string_to_argv(arg);
122 argc = len(argv)
123 if argv[0] == "all" and argc > 1:
124 raise gdb.GdbError(cmd_name + ": with 'all' " \
125 "you may not specify a filter.")
126 else:
127 if argv[0] != "all" and argc != 2:
128 raise gdb.GdbError(cmd_name + " takes exactly two arguments.")
129
130 return argv
131
132def _do_enable_frame_filter(command_tuple, flag):
133 """Worker for enabling/disabling frame_filters.
134
135 Arguments:
136 command_type: A tuple with the first element being the
137 frame filter dictionary, and the second being
138 the frame filter name.
139 flag: True for Enable, False for Disable.
140 """
141
142 list_op = command_tuple[0]
143 op_list = gdb.frames.return_list(list_op)
144
145 if list_op == "all":
146 for item in op_list:
147 gdb.frames.set_enabled(item, flag)
148 else:
149 frame_filter = command_tuple[1]
150 try:
151 ff = op_list[frame_filter]
152 except KeyError:
153 msg = "frame-filter '" + str(name) + "' not found."
154 raise gdb.GdbError(msg)
155
156 gdb.frames.set_enabled(ff, flag)
157
158def _complete_frame_filter_list(text, word, all_flag):
159 """Worker for frame filter dictionary name completion.
160
161 Arguments:
162 text: The full text of the command line.
163 word: The most recent word of the command line.
164 all_flag: Whether to include the word "all" in completion.
165
166 Returns:
167 A list of suggested frame filter dictionary name completions
168 from text/word analysis. This list can be empty when there
169 are no suggestions for completion.
170 """
171 if all_flag == True:
172 filter_locations = ["all", "global", "progspace"]
173 else:
174 filter_locations = ["global", "progspace"]
175 for objfile in gdb.objfiles():
176 filter_locations.append(objfile.filename)
177
178 # If the user just asked for completions with no completion
179 # hints, just return all the frame filter dictionaries we know
180 # about.
181 if (text == ""):
182 return filter_locations
183
184 # Otherwise filter on what we know.
185 flist = filter(lambda x,y=text:x.startswith(y), filter_locations)
186
187 # If we only have one completion, complete it and return it.
188 if len(flist) == 1:
189 flist[0] = flist[0][len(text)-len(word):]
190
191 # Otherwise, return an empty list, or a list of frame filter
192 # dictionaries that the previous filter operation returned.
193 return flist
194
195def _complete_frame_filter_name(word, printer_dict):
196 """Worker for frame filter name completion.
197
198 Arguments:
199
200 word: The most recent word of the command line.
201
202 printer_dict: The frame filter dictionary to search for frame
203 filter name completions.
204
205 Returns: A list of suggested frame filter name completions
206 from word analysis of the frame filter dictionary. This list
207 can be empty when there are no suggestions for completion.
208 """
209
210 printer_keys = printer_dict.keys()
211 if (word == ""):
212 return printer_keys
213
214 flist = filter(lambda x,y=word:x.startswith(y), printer_keys)
215 return flist
216
217class EnableFrameFilter(gdb.Command):
218 """GDB command to disable the specified frame-filter.
219
220 Usage: enable frame-filter enable DICTIONARY [NAME]
221
222 DICTIONARY is the name of the frame filter dictionary on which to
223 operate. If dictionary is set to "all", perform operations on all
224 dictionaries. Named dictionaries are: "global" for the global
225 frame filter dictionary, "progspace" for the program space's frame
226 filter dictionary. If either all, or the two named dictionaries
227 are not specified, the dictionary name is assumed to be the name
228 of the object-file name.
229
230 NAME matches the name of the frame-filter to operate on. If
231 DICTIONARY is "all", NAME is ignored.
232 """
233 def __init__(self):
234 super(EnableFrameFilter, self).__init__("enable frame-filter",
235 gdb.COMMAND_DATA)
236 def complete(self, text, word):
237 """Completion function for both frame filter dictionary, and
238 frame filter name."""
239 if text.count(" ") == 0:
240 return _complete_frame_filter_list(text, word, True)
241 else:
242 printer_list = gdb.frames.return_list(text.split()[0].rstrip())
243 return _complete_frame_filter_name(word, printer_list)
244
245 def invoke(self, arg, from_tty):
246 command_tuple = _enable_parse_arg("enable frame-filter", arg)
247 _do_enable_frame_filter(command_tuple, True)
248
249
250class DisableFrameFilter(gdb.Command):
251 """GDB command to disable the specified frame-filter.
252
253 Usage: disable frame-filter disable DICTIONARY [NAME]
254
255 DICTIONARY is the name of the frame filter dictionary on which to
256 operate. If dictionary is set to "all", perform operations on all
257 dictionaries. Named dictionaries are: "global" for the global
258 frame filter dictionary, "progspace" for the program space's frame
259 filter dictionary. If either all, or the two named dictionaries
260 are not specified, the dictionary name is assumed to be the name
261 of the object-file name.
262
263 NAME matches the name of the frame-filter to operate on. If
264 DICTIONARY is "all", NAME is ignored.
265 """
266 def __init__(self):
267 super(DisableFrameFilter, self).__init__("disable frame-filter",
268 gdb.COMMAND_DATA)
269
270 def complete(self, text, word):
271 """Completion function for both frame filter dictionary, and
272 frame filter name."""
273 if text.count(" ") == 0:
274 return _complete_frame_filter_list(text, word, True)
275 else:
276 printer_list = gdb.frames.return_list(text.split()[0].rstrip())
277 return _complete_frame_filter_name(word, printer_list)
278
279 def invoke(self, arg, from_tty):
280 command_tuple = _enable_parse_arg("disable frame-filter", arg)
281 _do_enable_frame_filter(command_tuple, False)
282
283class SetFrameFilterPriority(gdb.Command):
284 """GDB command to set the priority of the specified frame-filter.
285
286 Usage: set frame-filter priority DICTIONARY NAME PRIORITY
287
288 DICTIONARY is the name of the frame filter dictionary on which to
289 operate. Named dictionaries are: "global" for the global frame
290 filter dictionary, "progspace" for the program space's framefilter
291 dictionary. If either of these two are not specified, the
292 dictionary name is assumed to be the name of the object-file name.
293
294 NAME matches the name of the frame filter to operate on.
295
296 PRIORITY is the an integer to assign the new priority to the frame
297 filter.
298 """
299
300 def __init__(self):
301 super(SetFrameFilterPriority, self).__init__("set frame-filter " \
302 "priority",
303 gdb.COMMAND_DATA)
304
305 def _parse_pri_arg(self, arg):
306 """Internal worker to parse a priority from a tuple.
307
308 Arguments:
309 arg: Tuple which contains the arguments from the command.
310
311 Returns:
312 A tuple containing the dictionary, name and priority from
313 the arguments.
314
315 Raises:
316 gdb.GdbError: An error parsing the arguments.
317 """
318
319 argv = gdb.string_to_argv(arg);
320 argc = len(argv)
321 if argc != 3:
322 print("set frame-filter priority " \
323 "takes exactly three arguments.")
324 return None
325
326 return argv
327
328 def _set_filter_priority(self, command_tuple):
329 """Internal worker for setting priority of frame-filters, by
330 parsing a tuple and calling _set_priority with the parsed
331 tuple.
332
333 Arguments:
334 command_tuple: Tuple which contains the arguments from the
335 command.
336 """
337
338 list_op = command_tuple[0]
339 frame_filter = command_tuple[1]
340
341 # GDB returns arguments as a string, so convert priority to
342 # a number.
343 priority = int(command_tuple[2])
344
345 op_list = gdb.frames.return_list(list_op)
346
347 try:
348 ff = op_list[frame_filter]
349 except KeyError:
350 msg = "frame-filter '" + str(name) + "' not found."
351 raise gdb.GdbError(msg)
352
353 gdb.frames.set_priority(ff, priority)
354
355 def complete(self, text, word):
356 """Completion function for both frame filter dictionary, and
357 frame filter name."""
358 if text.count(" ") == 0:
359 return _complete_frame_filter_list(text, word, False)
360 else:
361 printer_list = gdb.frames.return_list(text.split()[0].rstrip())
362 return _complete_frame_filter_name(word, printer_list)
363
364 def invoke(self, arg, from_tty):
365 command_tuple = self._parse_pri_arg(arg)
366 if command_tuple != None:
367 self._set_filter_priority(command_tuple)
368
369class ShowFrameFilterPriority(gdb.Command):
370 """GDB command to show the priority of the specified frame-filter.
371
372 Usage: show frame-filter priority DICTIONARY NAME
373
374 DICTIONARY is the name of the frame filter dictionary on which to
375 operate. Named dictionaries are: "global" for the global frame
376 filter dictionary, "progspace" for the program space's framefilter
377 dictionary. If either of these two are not specified, the
378 dictionary name is assumed to be the name of the object-file name.
379
380 NAME matches the name of the frame-filter to operate on.
381 """
382
383 def __init__(self):
384 super(ShowFrameFilterPriority, self).__init__("show frame-filter " \
385 "priority",
386 gdb.COMMAND_DATA)
387
388 def _parse_pri_arg(self, arg):
389 """Internal worker to parse a dictionary and name from a
390 tuple.
391
392 Arguments:
393 arg: Tuple which contains the arguments from the command.
394
395 Returns:
396 A tuple containing the dictionary, and frame filter name.
397
398 Raises:
399 gdb.GdbError: An error parsing the arguments.
400 """
401
402 argv = gdb.string_to_argv(arg);
403 argc = len(argv)
404 if argc != 2:
405 print("show frame-filter priority " \
406 "takes exactly two arguments.")
407 return None
408
409 return argv
410
411 def get_filter_priority(self, frame_filters, name):
412 """Worker for retrieving the priority of frame_filters.
413
414 Arguments:
415 frame_filters: Name of frame filter dictionary.
416 name: object to select printers.
417
418 Returns:
419 The priority of the frame filter.
420
421 Raises:
422 gdb.GdbError: A frame filter cannot be found.
423 """
424
425 op_list = gdb.frames.return_list(frame_filters)
426
427 try:
428 ff = op_list[name]
429 except KeyError:
430 msg = "frame-filter '" + str(name) + "' not found."
431 raise gdb.GdbError(msg)
432
433 return gdb.frames.get_priority(ff)
434
435 def complete(self, text, word):
436 """Completion function for both frame filter dictionary, and
437 frame filter name."""
438
439 if text.count(" ") == 0:
440 return _complete_frame_filter_list(text, word, False)
441 else:
442 printer_list = frame._return_list(text.split()[0].rstrip())
443 return _complete_frame_filter_name(word, printer_list)
444
445 def invoke(self, arg, from_tty):
446 command_tuple = self._parse_pri_arg(arg)
447 if command_tuple == None:
448 return
449 filter_name = command_tuple[1]
450 list_name = command_tuple[0]
451 try:
452 priority = self.get_filter_priority(list_name, filter_name);
453 except Exception:
454 e = sys.exc_info()[1]
455 print("Error printing filter priority for '"+name+"':"+str(e))
456 else:
457 print("Priority of filter '" + filter_name + "' in list '" \
458 + list_name + "' is: " + str(priority))
459
460# Register commands
461SetFilterPrefixCmd()
462ShowFilterPrefixCmd()
463InfoFrameFilter()
464EnableFrameFilter()
465DisableFrameFilter()
466SetFrameFilterPriority()
467ShowFrameFilterPriority()