Home | History | Annotate | Download | only in command
      1 # 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 
     19 import sys
     20 import gdb
     21 import copy
     22 from gdb.FrameIterator import FrameIterator
     23 from gdb.FrameDecorator import FrameDecorator
     24 import gdb.frames
     25 import itertools
     26 
     27 # GDB Commands.
     28 class 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 
     36 class 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)
     42 class 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 
    108 def _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 
    132 def _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 
    158 def _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 
    195 def _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 
    217 class 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 
    250 class 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 
    283 class 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 
    369 class 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
    461 SetFilterPrefixCmd()
    462 ShowFilterPrefixCmd()
    463 InfoFrameFilter()
    464 EnableFrameFilter()
    465 DisableFrameFilter()
    466 SetFrameFilterPriority()
    467 ShowFrameFilterPriority()
    468