Home | History | Annotate | Download | only in gdb
      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 """Internal functions for working with frame-filters."""
     18 
     19 import gdb
     20 from gdb.FrameIterator import FrameIterator
     21 from gdb.FrameDecorator import FrameDecorator
     22 import itertools
     23 import collections
     24 
     25 def get_priority(filter_item):
     26     """ Internal worker function to return the frame-filter's priority
     27     from a frame filter object.  This is a fail free function as it is
     28     used in sorting and filtering.  If a badly implemented frame
     29     filter does not implement the priority attribute, return zero
     30     (otherwise sorting/filtering will fail and prevent other frame
     31     filters from executing).
     32 
     33     Arguments:
     34         filter_item: An object conforming to the frame filter
     35                      interface.
     36 
     37     Returns:
     38         The priority of the frame filter from the "priority"
     39         attribute, or zero.
     40     """
     41     # Do not fail here, as the sort will fail.  If a filter has not
     42     # (incorrectly) set a priority, set it to zero.
     43     return getattr(filter_item, "priority", 0)
     44 
     45 def set_priority(filter_item, priority):
     46     """ Internal worker function to set the frame-filter's priority.
     47 
     48     Arguments:
     49         filter_item: An object conforming to the frame filter
     50                      interface.
     51         priority: The priority to assign as an integer.
     52     """
     53 
     54     filter_item.priority = priority
     55 
     56 def get_enabled(filter_item):
     57     """ Internal worker function to return a filter's enabled state
     58     from a frame filter object.  This is a fail free function as it is
     59     used in sorting and filtering.  If a badly implemented frame
     60     filter does not implement the enabled attribute, return False
     61     (otherwise sorting/filtering will fail and prevent other frame
     62     filters from executing).
     63 
     64     Arguments:
     65         filter_item: An object conforming to the frame filter
     66                      interface.
     67 
     68     Returns:
     69         The enabled state of the frame filter from the "enabled"
     70         attribute, or False.
     71     """
     72 
     73     # If the filter class is badly implemented when called from the
     74     # Python filter command, do not cease filter operations, just set
     75     # enabled to False.
     76     return getattr(filter_item, "enabled", False)
     77 
     78 def set_enabled(filter_item, state):
     79     """ Internal Worker function to set the frame-filter's enabled
     80     state.
     81 
     82     Arguments:
     83         filter_item: An object conforming to the frame filter
     84                      interface.
     85         state: True or False, depending on desired state.
     86     """
     87 
     88     filter_item.enabled = state
     89 
     90 def return_list(name):
     91     """ Internal Worker function to return the frame filter
     92     dictionary, depending on the name supplied as an argument.  If the
     93     name is not "all", "global" or "progspace", it is assumed to name
     94     an object-file.
     95 
     96     Arguments:
     97         name: The name of the list, as specified by GDB user commands.
     98 
     99     Returns:
    100         A dictionary object for a single specified dictionary, or a
    101         list containing all the items for "all"
    102 
    103     Raises:
    104         gdb.GdbError:  A dictionary of that name cannot be found.
    105     """
    106 
    107     # If all dictionaries are wanted in the case of "all" we
    108     # cannot return a combined dictionary as keys() may clash in
    109     # between different dictionaries.  As we just want all the frame
    110     # filters to enable/disable them all, just return the combined
    111     # items() as a chained iterator of dictionary values.
    112     if name == "all":
    113         glob = gdb.frame_filters.values()
    114         prog = gdb.current_progspace().frame_filters.values()
    115         return_iter = itertools.chain(glob, prog)
    116         for objfile in gdb.objfiles():
    117             return_iter = itertools.chain(return_iter, objfile.frame_filters.values())
    118 
    119         return return_iter
    120 
    121     if name == "global":
    122         return gdb.frame_filters
    123     else:
    124         if name == "progspace":
    125             cp = gdb.current_progspace()
    126             return cp.frame_filters
    127         else:
    128             for objfile in gdb.objfiles():
    129                 if name == objfile.filename:
    130                     return objfile.frame_filters
    131 
    132     msg = "Cannot find frame-filter dictionary for '" + name + "'"
    133     raise gdb.GdbError(msg)
    134 
    135 def _sort_list():
    136     """ Internal Worker function to merge all known frame-filter
    137     lists, prune any filters with the state set to "disabled", and
    138     sort the list on the frame-filter's "priority" attribute.
    139 
    140     Returns:
    141         sorted_list: A sorted, pruned list of frame filters to
    142                      execute.
    143     """
    144 
    145     all_filters = return_list("all")
    146     sorted_frame_filters = sorted(all_filters, key = get_priority,
    147                                   reverse = True)
    148 
    149     sorted_frame_filters = filter(get_enabled,
    150                                   sorted_frame_filters)
    151 
    152     return sorted_frame_filters
    153 
    154 def execute_frame_filters(frame, frame_low, frame_high):
    155     """ Internal function called from GDB that will execute the chain
    156     of frame filters.  Each filter is executed in priority order.
    157     After the execution completes, slice the iterator to frame_low -
    158     frame_high range.
    159 
    160     Arguments:
    161         frame: The initial frame.
    162 
    163         frame_low: The low range of the slice.  If this is a negative
    164         integer then it indicates a backward slice (ie bt -4) which
    165         counts backward from the last frame in the backtrace.
    166 
    167         frame_high: The high range of the slice.  If this is -1 then
    168         it indicates all frames until the end of the stack from
    169         frame_low.
    170 
    171     Returns:
    172         frame_iterator: The sliced iterator after all frame
    173         filters have had a change to execute, or None if no frame
    174         filters are registered.
    175     """
    176 
    177     # Get a sorted list of frame filters.
    178     sorted_list = list(_sort_list())
    179 
    180     # Check to see if there are any frame-filters.  If not, just
    181     # return None and let default backtrace printing occur.
    182     if len(sorted_list) == 0:
    183         return None
    184 
    185     frame_iterator = FrameIterator(frame)
    186 
    187     # Apply a basic frame decorator to all gdb.Frames.  This unifies
    188     # the interface.  Python 3.x moved the itertools.imap
    189     # functionality to map(), so check if it is available.
    190     if hasattr(itertools,"imap"):
    191         frame_iterator = itertools.imap(FrameDecorator, frame_iterator)
    192     else:
    193         frame_iterator = map(FrameDecorator, frame_iterator)
    194 
    195     for ff in sorted_list:
    196         frame_iterator = ff.filter(frame_iterator)
    197 
    198     # Slicing
    199 
    200     # Is this a slice from the end of the backtrace, ie bt -2?
    201     if frame_low < 0:
    202         count = 0
    203         slice_length = abs(frame_low)
    204         # We cannot use MAXLEN argument for deque as it is 2.6 onwards
    205         # and some GDB versions might be < 2.6.
    206         sliced = collections.deque()
    207 
    208         for frame_item in frame_iterator:
    209             if count >= slice_length:
    210                 sliced.popleft();
    211             count = count + 1
    212             sliced.append(frame_item)
    213 
    214         return iter(sliced)
    215 
    216     # -1 for frame_high means until the end of the backtrace.  Set to
    217     # None if that is the case, to indicate to itertools.islice to
    218     # slice to the end of the iterator.
    219     if frame_high == -1:
    220         frame_high = None
    221     else:
    222         # As frames start from 0, add one to frame_high so islice
    223         # correctly finds the end
    224         frame_high = frame_high + 1;
    225 
    226     sliced = itertools.islice(frame_iterator, frame_low, frame_high)
    227 
    228     return sliced
    229