| # Frame-filter commands. |
| # Copyright (C) 2013-2014 Free Software Foundation, Inc. |
| |
| # This program is free software; you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation; either version 3 of the License, or |
| # (at your option) any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| |
| """GDB commands for working with frame-filters.""" |
| |
| import sys |
| import gdb |
| import copy |
| from gdb.FrameIterator import FrameIterator |
| from gdb.FrameDecorator import FrameDecorator |
| import gdb.frames |
| import itertools |
| |
| # GDB Commands. |
| class SetFilterPrefixCmd(gdb.Command): |
| """Prefix command for 'set' frame-filter related operations.""" |
| |
| def __init__(self): |
| super(SetFilterPrefixCmd, self).__init__("set frame-filter", |
| gdb.COMMAND_OBSCURE, |
| gdb.COMPLETE_NONE, True) |
| |
| class ShowFilterPrefixCmd(gdb.Command): |
| """Prefix command for 'show' frame-filter related operations.""" |
| def __init__(self): |
| super(ShowFilterPrefixCmd, self).__init__("show frame-filter", |
| gdb.COMMAND_OBSCURE, |
| gdb.COMPLETE_NONE, True) |
| class InfoFrameFilter(gdb.Command): |
| """List all registered Python frame-filters. |
| |
| Usage: info frame-filters |
| """ |
| |
| def __init__(self): |
| super(InfoFrameFilter, self).__init__("info frame-filter", |
| gdb.COMMAND_DATA) |
| @staticmethod |
| def enabled_string(state): |
| """Return "Yes" if filter is enabled, otherwise "No".""" |
| if state: |
| return "Yes" |
| else: |
| return "No" |
| |
| def list_frame_filters(self, frame_filters): |
| """ Internal worker function to list and print frame filters |
| in a dictionary. |
| |
| Arguments: |
| frame_filters: The name of the dictionary, as |
| specified by GDB user commands. |
| """ |
| |
| sorted_frame_filters = sorted(frame_filters.items(), |
| key=lambda i: gdb.frames.get_priority(i[1]), |
| reverse=True) |
| |
| if len(sorted_frame_filters) == 0: |
| print(" No frame filters registered.") |
| else: |
| print(" Priority Enabled Name") |
| for frame_filter in sorted_frame_filters: |
| name = frame_filter[0] |
| try: |
| priority = '{:<8}'.format( |
| str(gdb.frames.get_priority(frame_filter[1]))) |
| enabled = '{:<7}'.format( |
| self.enabled_string(gdb.frames.get_enabled(frame_filter[1]))) |
| except Exception: |
| e = sys.exc_info()[1] |
| print(" Error printing filter '"+name+"': "+str(e)) |
| else: |
| print(" %s %s %s" % (priority, enabled, name)) |
| |
| def print_list(self, title, filter_list, blank_line): |
| print(title) |
| self.list_frame_filters(filter_list) |
| if blank_line: |
| print("") |
| |
| def invoke(self, arg, from_tty): |
| self.print_list("global frame-filters:", gdb.frame_filters, True) |
| |
| cp = gdb.current_progspace() |
| self.print_list("progspace %s frame-filters:" % cp.filename, |
| cp.frame_filters, True) |
| |
| for objfile in gdb.objfiles(): |
| self.print_list("objfile %s frame-filters:" % objfile.filename, |
| objfile.frame_filters, False) |
| |
| # Internal enable/disable functions. |
| |
| def _enable_parse_arg(cmd_name, arg): |
| """ Internal worker function to take an argument from |
| enable/disable and return a tuple of arguments. |
| |
| Arguments: |
| cmd_name: Name of the command invoking this function. |
| args: The argument as a string. |
| |
| Returns: |
| A tuple containing the dictionary, and the argument, or just |
| the dictionary in the case of "all". |
| """ |
| |
| argv = gdb.string_to_argv(arg); |
| argc = len(argv) |
| if argv[0] == "all" and argc > 1: |
| raise gdb.GdbError(cmd_name + ": with 'all' " \ |
| "you may not specify a filter.") |
| else: |
| if argv[0] != "all" and argc != 2: |
| raise gdb.GdbError(cmd_name + " takes exactly two arguments.") |
| |
| return argv |
| |
| def _do_enable_frame_filter(command_tuple, flag): |
| """Worker for enabling/disabling frame_filters. |
| |
| Arguments: |
| command_type: A tuple with the first element being the |
| frame filter dictionary, and the second being |
| the frame filter name. |
| flag: True for Enable, False for Disable. |
| """ |
| |
| list_op = command_tuple[0] |
| op_list = gdb.frames.return_list(list_op) |
| |
| if list_op == "all": |
| for item in op_list: |
| gdb.frames.set_enabled(item, flag) |
| else: |
| frame_filter = command_tuple[1] |
| try: |
| ff = op_list[frame_filter] |
| except KeyError: |
| msg = "frame-filter '" + str(name) + "' not found." |
| raise gdb.GdbError(msg) |
| |
| gdb.frames.set_enabled(ff, flag) |
| |
| def _complete_frame_filter_list(text, word, all_flag): |
| """Worker for frame filter dictionary name completion. |
| |
| Arguments: |
| text: The full text of the command line. |
| word: The most recent word of the command line. |
| all_flag: Whether to include the word "all" in completion. |
| |
| Returns: |
| A list of suggested frame filter dictionary name completions |
| from text/word analysis. This list can be empty when there |
| are no suggestions for completion. |
| """ |
| if all_flag == True: |
| filter_locations = ["all", "global", "progspace"] |
| else: |
| filter_locations = ["global", "progspace"] |
| for objfile in gdb.objfiles(): |
| filter_locations.append(objfile.filename) |
| |
| # If the user just asked for completions with no completion |
| # hints, just return all the frame filter dictionaries we know |
| # about. |
| if (text == ""): |
| return filter_locations |
| |
| # Otherwise filter on what we know. |
| flist = filter(lambda x,y=text:x.startswith(y), filter_locations) |
| |
| # If we only have one completion, complete it and return it. |
| if len(flist) == 1: |
| flist[0] = flist[0][len(text)-len(word):] |
| |
| # Otherwise, return an empty list, or a list of frame filter |
| # dictionaries that the previous filter operation returned. |
| return flist |
| |
| def _complete_frame_filter_name(word, printer_dict): |
| """Worker for frame filter name completion. |
| |
| Arguments: |
| |
| word: The most recent word of the command line. |
| |
| printer_dict: The frame filter dictionary to search for frame |
| filter name completions. |
| |
| Returns: A list of suggested frame filter name completions |
| from word analysis of the frame filter dictionary. This list |
| can be empty when there are no suggestions for completion. |
| """ |
| |
| printer_keys = printer_dict.keys() |
| if (word == ""): |
| return printer_keys |
| |
| flist = filter(lambda x,y=word:x.startswith(y), printer_keys) |
| return flist |
| |
| class EnableFrameFilter(gdb.Command): |
| """GDB command to disable the specified frame-filter. |
| |
| Usage: enable frame-filter enable DICTIONARY [NAME] |
| |
| DICTIONARY is the name of the frame filter dictionary on which to |
| operate. If dictionary is set to "all", perform operations on all |
| dictionaries. Named dictionaries are: "global" for the global |
| frame filter dictionary, "progspace" for the program space's frame |
| filter dictionary. If either all, or the two named dictionaries |
| are not specified, the dictionary name is assumed to be the name |
| of the object-file name. |
| |
| NAME matches the name of the frame-filter to operate on. If |
| DICTIONARY is "all", NAME is ignored. |
| """ |
| def __init__(self): |
| super(EnableFrameFilter, self).__init__("enable frame-filter", |
| gdb.COMMAND_DATA) |
| def complete(self, text, word): |
| """Completion function for both frame filter dictionary, and |
| frame filter name.""" |
| if text.count(" ") == 0: |
| return _complete_frame_filter_list(text, word, True) |
| else: |
| printer_list = gdb.frames.return_list(text.split()[0].rstrip()) |
| return _complete_frame_filter_name(word, printer_list) |
| |
| def invoke(self, arg, from_tty): |
| command_tuple = _enable_parse_arg("enable frame-filter", arg) |
| _do_enable_frame_filter(command_tuple, True) |
| |
| |
| class DisableFrameFilter(gdb.Command): |
| """GDB command to disable the specified frame-filter. |
| |
| Usage: disable frame-filter disable DICTIONARY [NAME] |
| |
| DICTIONARY is the name of the frame filter dictionary on which to |
| operate. If dictionary is set to "all", perform operations on all |
| dictionaries. Named dictionaries are: "global" for the global |
| frame filter dictionary, "progspace" for the program space's frame |
| filter dictionary. If either all, or the two named dictionaries |
| are not specified, the dictionary name is assumed to be the name |
| of the object-file name. |
| |
| NAME matches the name of the frame-filter to operate on. If |
| DICTIONARY is "all", NAME is ignored. |
| """ |
| def __init__(self): |
| super(DisableFrameFilter, self).__init__("disable frame-filter", |
| gdb.COMMAND_DATA) |
| |
| def complete(self, text, word): |
| """Completion function for both frame filter dictionary, and |
| frame filter name.""" |
| if text.count(" ") == 0: |
| return _complete_frame_filter_list(text, word, True) |
| else: |
| printer_list = gdb.frames.return_list(text.split()[0].rstrip()) |
| return _complete_frame_filter_name(word, printer_list) |
| |
| def invoke(self, arg, from_tty): |
| command_tuple = _enable_parse_arg("disable frame-filter", arg) |
| _do_enable_frame_filter(command_tuple, False) |
| |
| class SetFrameFilterPriority(gdb.Command): |
| """GDB command to set the priority of the specified frame-filter. |
| |
| Usage: set frame-filter priority DICTIONARY NAME PRIORITY |
| |
| DICTIONARY is the name of the frame filter dictionary on which to |
| operate. Named dictionaries are: "global" for the global frame |
| filter dictionary, "progspace" for the program space's framefilter |
| dictionary. If either of these two are not specified, the |
| dictionary name is assumed to be the name of the object-file name. |
| |
| NAME matches the name of the frame filter to operate on. |
| |
| PRIORITY is the an integer to assign the new priority to the frame |
| filter. |
| """ |
| |
| def __init__(self): |
| super(SetFrameFilterPriority, self).__init__("set frame-filter " \ |
| "priority", |
| gdb.COMMAND_DATA) |
| |
| def _parse_pri_arg(self, arg): |
| """Internal worker to parse a priority from a tuple. |
| |
| Arguments: |
| arg: Tuple which contains the arguments from the command. |
| |
| Returns: |
| A tuple containing the dictionary, name and priority from |
| the arguments. |
| |
| Raises: |
| gdb.GdbError: An error parsing the arguments. |
| """ |
| |
| argv = gdb.string_to_argv(arg); |
| argc = len(argv) |
| if argc != 3: |
| print("set frame-filter priority " \ |
| "takes exactly three arguments.") |
| return None |
| |
| return argv |
| |
| def _set_filter_priority(self, command_tuple): |
| """Internal worker for setting priority of frame-filters, by |
| parsing a tuple and calling _set_priority with the parsed |
| tuple. |
| |
| Arguments: |
| command_tuple: Tuple which contains the arguments from the |
| command. |
| """ |
| |
| list_op = command_tuple[0] |
| frame_filter = command_tuple[1] |
| |
| # GDB returns arguments as a string, so convert priority to |
| # a number. |
| priority = int(command_tuple[2]) |
| |
| op_list = gdb.frames.return_list(list_op) |
| |
| try: |
| ff = op_list[frame_filter] |
| except KeyError: |
| msg = "frame-filter '" + str(name) + "' not found." |
| raise gdb.GdbError(msg) |
| |
| gdb.frames.set_priority(ff, priority) |
| |
| def complete(self, text, word): |
| """Completion function for both frame filter dictionary, and |
| frame filter name.""" |
| if text.count(" ") == 0: |
| return _complete_frame_filter_list(text, word, False) |
| else: |
| printer_list = gdb.frames.return_list(text.split()[0].rstrip()) |
| return _complete_frame_filter_name(word, printer_list) |
| |
| def invoke(self, arg, from_tty): |
| command_tuple = self._parse_pri_arg(arg) |
| if command_tuple != None: |
| self._set_filter_priority(command_tuple) |
| |
| class ShowFrameFilterPriority(gdb.Command): |
| """GDB command to show the priority of the specified frame-filter. |
| |
| Usage: show frame-filter priority DICTIONARY NAME |
| |
| DICTIONARY is the name of the frame filter dictionary on which to |
| operate. Named dictionaries are: "global" for the global frame |
| filter dictionary, "progspace" for the program space's framefilter |
| dictionary. If either of these two are not specified, the |
| dictionary name is assumed to be the name of the object-file name. |
| |
| NAME matches the name of the frame-filter to operate on. |
| """ |
| |
| def __init__(self): |
| super(ShowFrameFilterPriority, self).__init__("show frame-filter " \ |
| "priority", |
| gdb.COMMAND_DATA) |
| |
| def _parse_pri_arg(self, arg): |
| """Internal worker to parse a dictionary and name from a |
| tuple. |
| |
| Arguments: |
| arg: Tuple which contains the arguments from the command. |
| |
| Returns: |
| A tuple containing the dictionary, and frame filter name. |
| |
| Raises: |
| gdb.GdbError: An error parsing the arguments. |
| """ |
| |
| argv = gdb.string_to_argv(arg); |
| argc = len(argv) |
| if argc != 2: |
| print("show frame-filter priority " \ |
| "takes exactly two arguments.") |
| return None |
| |
| return argv |
| |
| def get_filter_priority(self, frame_filters, name): |
| """Worker for retrieving the priority of frame_filters. |
| |
| Arguments: |
| frame_filters: Name of frame filter dictionary. |
| name: object to select printers. |
| |
| Returns: |
| The priority of the frame filter. |
| |
| Raises: |
| gdb.GdbError: A frame filter cannot be found. |
| """ |
| |
| op_list = gdb.frames.return_list(frame_filters) |
| |
| try: |
| ff = op_list[name] |
| except KeyError: |
| msg = "frame-filter '" + str(name) + "' not found." |
| raise gdb.GdbError(msg) |
| |
| return gdb.frames.get_priority(ff) |
| |
| def complete(self, text, word): |
| """Completion function for both frame filter dictionary, and |
| frame filter name.""" |
| |
| if text.count(" ") == 0: |
| return _complete_frame_filter_list(text, word, False) |
| else: |
| printer_list = frame._return_list(text.split()[0].rstrip()) |
| return _complete_frame_filter_name(word, printer_list) |
| |
| def invoke(self, arg, from_tty): |
| command_tuple = self._parse_pri_arg(arg) |
| if command_tuple == None: |
| return |
| filter_name = command_tuple[1] |
| list_name = command_tuple[0] |
| try: |
| priority = self.get_filter_priority(list_name, filter_name); |
| except Exception: |
| e = sys.exc_info()[1] |
| print("Error printing filter priority for '"+name+"':"+str(e)) |
| else: |
| print("Priority of filter '" + filter_name + "' in list '" \ |
| + list_name + "' is: " + str(priority)) |
| |
| # Register commands |
| SetFilterPrefixCmd() |
| ShowFilterPrefixCmd() |
| InfoFrameFilter() |
| EnableFrameFilter() |
| DisableFrameFilter() |
| SetFrameFilterPriority() |
| ShowFrameFilterPriority() |