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