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