[patch][python] 1 of 5 - Frame filter Python C code changes.

Phil Muldoon pmuldoon@redhat.com
Fri Nov 30 14:31:00 GMT 2012


This email and patch covers the python/ changes for Python Frame Filters.

2012-11-30  Phil Muldoon  <pmuldoon@redhat.com>

	* python/python.h: Add new frame filter constants, and flag enum.
	(apply_frame_filter): Add definition.
	* python/python.c (apply_frame_filter): New non-Python
	enabled function.
	* python/py-utils.c (py_xdecref): New function.
	(make_cleanup_py_xdecref): Ditto.
	* python/py-objfile.c: Declare frame_filters dictionary.
	(objfpy_dealloc): Add frame_filters dealloc.
	(objfpy_new): Initialize frame_filters attribute.
	(objfile_to_objfile_object): Ditto.
	(objfpy_get_frame_filters): New function.
	(objfpy_set_frame_filters): New function.
	* python/py-progspace.c: Declare frame_filters dictionary.
	(pspy_dealloc): Add frame_filters dealloc.
	(pspy_new): Initialize frame_filters attribute.
	(pspacee_to_pspace_object): Ditto.
	(pspy_get_frame_filters): New function.
	(pspy_set_frame_filters): New function.
	* python/py-framefilter.c: New file.
	* python/lib/gdb/command/frame_filters.py: New file.
	* python/lib/gdb/__init__.py: Initialize global frame_filters
	dictionary
	* python/lib/gdb/FrameWrapper.py: New file.
	* python/lib/gdb/FrameIterator.py: New file.
	* python/lib/gdb/BaseFrameWrapper.py: New file.
--

diff --git a/gdb/python/lib/gdb/BaseFrameWrapper.py b/gdb/python/lib/gdb/BaseFrameWrapper.py
new file mode 100644
index 0000000..c96a7df
--- /dev/null
+++ b/gdb/python/lib/gdb/BaseFrameWrapper.py
@@ -0,0 +1,293 @@
+# Copyright (C) 2012 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/>.
+
+import gdb
+from gdb.FrameWrapper import FrameWrapper
+
+class BaseFrameWrapper(FrameWrapper):
+    """Basic implementation of a Frame Wrapper"""
+
+    """ This base frame wrapper wraps a frame or another frame
+    wrapper, and provides convenience methods.  If this object is
+    wrapping a frame wrapper, defer to that wrapped object's method if
+    it has one.  This allows for frame wrappers that have sub-classed
+    BaseFrameWrapper, but also wrap other frame wrappers on the same
+    frame to correctly execute.
+
+    E.g
+
+    If the result of frame filters running means we have one gdb.Frame
+    wrapped by multiple frame wrappers, all sub-classed from
+    BaseFrameWrapper:
+
+    Wrapper1(Wrapper2(BaseFrameWrapper(gdb.Frame)))
+
+    In this case we have two frame wrappers, both of which are
+    sub-classed from BaseFrameWrapper.  If Wrapper1 just overrides the
+    'function' method, then all of the other methods are carried out
+    by the super-class BaseFrameWrapper.  But Wrapper2 may have
+    overriden other methods, so BaseFrameWrapper will look at the
+    'base' parameter and defer to that class's methods.  And so on,
+    down the chain."""
+
+    # 'base' can refer to a gdb.Frame or another frame filter.  In
+    # the latter case, the child class will have called the super
+    # method and base will be an object conforming to the Frame Filter
+    # class.
+    def __init__(self, base):
+        super(BaseFrameWrapper, self).__init__(base)
+        self.base = base
+
+    @staticmethod
+    def is_limited_frame(frame):
+        """Internal utility to determine if the frame is special or
+        limited."""
+        sal = frame.find_sal()
+
+        if (not sal.symtab or not sal.symtab.filename
+            or frame == gdb.DUMMY_FRAME
+            or frame == gdb.SIGTRAMP_FRAME):
+
+            return True
+
+        return False
+
+    def elided(self):
+        """Return any elided frames that this class might be
+        wrapping, or None."""
+        if hasattr(self.base, "elided"):
+            return self.base.elided()
+
+        return None
+
+    def function(self):
+        """ Return the name of the frame's function, first determining
+        if it is a special frame.  If not, try to determine filename
+        from GDB's frame internal function API.  Finally, if a name
+        cannot be determined return the address."""
+
+        if not isinstance(self.base, gdb.Frame):
+            if hasattr(self.base, "function"):
+                return self.base.function()
+
+        frame = self.inferior_frame()
+
+        if frame.type() == gdb.DUMMY_FRAME:
+            return "<function called from gdb>"
+        elif frame.type() == gdb.SIGTRAMP_FRAME:
+            return "<signal handler called>"
+
+        func = frame.function()
+        sal = frame.find_sal()
+        pc = frame.pc()
+
+        if func == None:
+            unknown =  format(" 0x%08x in" % pc)
+            return unknown
+
+        return str(func)
+
+    def address(self):
+        """ Return the address of the frame's pc"""
+
+        if hasattr(self.base, "address"):
+            return self.base.address()
+
+        frame = self.inferior_frame()
+        return frame.pc()
+
+    def filename(self):
+        """ Return the filename associated with this frame, detecting
+        and returning the appropriate library name is this is a shared
+        library."""
+
+        if hasattr(self.base, "filename"):
+            return self.base.filename()
+
+        frame = self.inferior_frame()
+        sal = frame.find_sal()
+        if (not sal.symtab or not sal.symtab.filename):
+            pc = frame.pc()
+            return gdb.solib_name(pc)
+        else:
+            return sal.symtab.filename
+
+    def frame_args(self):
+        """ Return an iterator of frame arguments for this frame, if
+        any.  The iterator contains objects conforming with the
+        Symbol/Value interface.  If there are no frame arguments, or
+        if this frame is deemed to be a special case, return None."""
+
+        if hasattr(self.base, "frame_args"):
+            return self.base.frame_args()
+
+        frame = self.inferior_frame()
+        if self.is_limited_frame(frame):
+            return None
+
+        args = FrameVars(frame)
+        return args.fetch_frame_args()
+
+    def frame_locals(self):
+        """ Return an iterator of local variables for this frame, if
+        any.  The iterator contains objects conforming with the
+        Symbol/Value interface.  If there are no frame locals, or if
+        this frame is deemed to be a special case, return None."""
+
+        if hasattr(self.base, "frame_locals"):
+            return self.base.frame_locals()
+
+        frame = self.inferior_frame()
+        if self.is_limited_frame(frame):
+            return None
+
+        args = FrameVars(frame)
+        return args.fetch_frame_locals()
+
+    def line(self):
+        """ Return line number information associated with the frame's
+        pc.  If symbol table/line information does not exist, or if
+        this frame is deemed to be a special case, return None"""
+
+        if hasattr(self.base, "line"):
+            return self.base.line()
+
+        frame = self.inferior_frame()
+        if self.is_limited_frame(frame):
+            return None
+
+        sal = frame.find_sal()
+        if (sal):
+            return sal.line
+        else:
+            return None
+
+    def inferior_frame(self):
+        """ Return the gdb.Frame underpinning this frame wrapper."""
+
+        # If 'base' is a frame wrapper, we want to call its inferior
+        # frame method.  If 'base' is a gdb.Frame, just return that.
+        if hasattr(self.base, "inferior_frame"):
+            return self.base.inferior_frame()
+        return self.base
+
+class BaseSymValueWrapper():
+    """A container class conforming to the Symbol/Value interface
+    which holds frame locals or frame arguments."""
+    def __init__(self, symbol, value):
+        self.sym = symbol
+        self.val = value
+
+    def value(self):
+        """ Return the value associated with this symbol, or None"""
+        return self.val
+
+    def symbol(self):
+        """ Return the symbol, or Python text, associated with this
+        symbol, or None"""
+        return self.sym
+
+class FrameVars():
+
+    """Utility class to fetch and store frame local variables, or
+    frame arguments."""
+
+    def __init__(self,frame):
+        self.frame = frame
+
+    @staticmethod
+    def fetch_b(sym):
+        """ Local utility method to determine if according to Symbol
+        type whether it should be included in the iterator.  Not all
+        symbols are fetched, and only symbols that return
+        True from this method should be fetched."""
+
+        # SYM may be a string instead of a symbol in the case of
+        # synthetic local arguments or locals.  If that is the case,
+        # always fetch.
+        if isinstance(sym, basestring):
+            return True
+
+        sym_type = sym.addr_class
+
+        return {
+            gdb.SYMBOL_LOC_STATIC: True,
+            gdb.SYMBOL_LOC_REGISTER: True,
+            gdb.SYMBOL_LOC_ARG: True,
+            gdb.SYMBOL_LOC_REF_ARG: True,
+            gdb.SYMBOL_LOC_LOCAL: True,
+	    gdb.SYMBOL_LOC_REGPARM_ADDR: True,
+	    gdb.SYMBOL_LOC_COMPUTED: True
+          }.get(sym_type, False)
+
+    def fetch_frame_locals(self):
+        """Public utility method to fetch frame local variables for
+        the stored frame.  Frame arguments are not fetched.  If there
+        are not frame local variables, return None."""
+        lvars = []
+        try:
+            block = self.frame.block()
+        except:
+            return None
+
+        for sym in block:
+            if sym.is_argument:
+                continue;
+            if self.fetch_b(sym):
+                lvars.append(BaseSymValueWrapper(sym, None))
+
+        if len(lvars) == 0:
+            return None
+
+        return iter(lvars)
+
+    def fetch_frame_args(self):
+        """Public utility method to fetch frame argument for the
+        stored frame.  Frame arguments are the only type fetched.  If
+        there are no frame arguments variables, return None."""
+
+        args = []
+        try:
+            block = self.frame.block()
+        except:
+            return None
+
+        for sym in block:
+            if not sym.is_argument:
+                continue;
+            args.append(BaseSymValueWrapper(sym,None))
+
+        if len(args) == 0:
+            return None
+
+        return iter(args)
+
+    def get_value(self, sym, block):
+        """Public utility method to fetch a value from a symbol."""
+        if len(sym.linkage_name):
+            nsym, is_field_of_this = gdb.lookup_symbol(sym.linkage_name, block)
+            if nsym != None:
+                if nsym.addr_class != gdb.SYMBOL_LOC_REGISTER:
+                    sym = nsym
+
+        try:
+            val = sym.value(self.frame)
+
+        except RuntimeError, text:
+            val = text
+        if val == None:
+            val = "???"
+
+        return val
diff --git a/gdb/python/lib/gdb/FrameIterator.py b/gdb/python/lib/gdb/FrameIterator.py
new file mode 100644
index 0000000..ddc9087
--- /dev/null
+++ b/gdb/python/lib/gdb/FrameIterator.py
@@ -0,0 +1,53 @@
+# Copyright (C) 2012 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/>.
+
+import gdb
+import itertools
+
+class FrameIterator(object):
+    """A gdb.Frame iterator.  Iterates over gdb.Frames or objects that
+    conform to that interface."""
+
+    def __init__ (self, frame_obj):
+        """Initialize a FrameIterator.
+
+        Arguments:
+            frame_obj the starting frame."""
+
+        super(FrameIterator, self).__init__()
+        self.frame = frame_obj
+
+    def __iter__ (self):
+        return self
+
+    def __getitem__(self,index):
+        """__getitem__ implementation.
+
+        Arguments:
+            index: A specific index to fetch."""
+
+        return next(itertools.islice(self.frame,index,index+1))
+
+    def next (self):
+        """__next__ implementation.
+
+        Returns:
+            The next oldest frame."""
+
+        result = self.frame
+        if result is None:
+            raise StopIteration
+        self.frame = result.older ()
+        return result
diff --git a/gdb/python/lib/gdb/FrameWrapper.py b/gdb/python/lib/gdb/FrameWrapper.py
new file mode 100644
index 0000000..4db9a43
--- /dev/null
+++ b/gdb/python/lib/gdb/FrameWrapper.py
@@ -0,0 +1,155 @@
+# Copyright (C) 2012 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/>.
+
+import gdb
+
+class FrameWrapper (object):
+    """Interface for a Frame Wrapper."""
+
+    """ A frame wrapper wraps a frame and provides additional and
+    convenience methods. """
+    def __init__(self, frame):
+        super(FrameWrapper, self).__init__()
+        self.frame = frame
+
+    def elided (self):
+        """ The elided method groups frames together in a
+        hierarchical system.  An example would be an interpreter call
+        that occurs over many frames but might be better represented
+        as a group of frames distinct from the other frames.
+
+        Arguments: None
+
+        Returns: The elided function must return an iterator that
+                 contains the frames that are being elided, or None.
+                 Elided frames are indented from normal frames in a
+                 backtrace, to show affinity with the frame that
+                 elided them.  Note that it is the frame filter's task
+                 to filter out the elided frames from the source
+                 iterator, and also to provide the iterator of elided
+                 frames in this function.  If this function returns a
+                 None, no frames will be elided.
+        """
+
+        pass
+
+    def function (self):
+        """ The name of the function in the frame.
+
+        Arguments: None.
+
+        Returns: A string describing the function.  If this function
+                 returns None, no data will be displayed for this
+                 field at printing.
+        """
+        pass
+
+    def address (self):
+        """ The address of the frame.
+
+        Arguments: None.
+
+        Returns: A numeric integer type of sufficient size to describe
+                 the address of the frame, or None.  If this function
+                 returns a None, no data will be displayed for this
+                 field at printing.
+        """
+
+        pass
+
+    def filename (self):
+        """ The filename associated with the function of this frame.
+
+        Arguments: None.
+
+        Returns: A string containing the filename, and optionally, the
+                 path to the filename of the frame, or None.  If this
+                 function returns a None, no data will be displayed
+                 for this field at printing.
+        """
+
+        pass
+
+    def line (self):
+        """ The line number associated with the current position
+        within the function addressed by this frame.
+
+        Arguments: None.
+
+        Returns: An integer type representing the line number, or
+                 None.  If this function returns a None, no data will
+                 be displayed for this field at printing.
+        """
+
+        pass
+
+    def frame_args (self):
+        """ The arguments of the function in this frame.
+
+        Arguments: None.
+
+        Returns: An iterator that conforms to the Python iterator
+                 protocol, or None.  If this method returns a None,
+                 instead of an iterator, then no data will be printed
+                 for frame arguments.  If this method returns an
+                 iterator, it must contain objects that implement two
+                 methods, described here.
+
+                 The object must implement an argument method which
+                 takes no parameters and must return a gdb.Symbol or a
+                 Python string.  It must also implement a value method
+                 which takes no parameters and which must return a
+                 gdb.Value, a Python value, or None.  If the value
+                 method returns a None, and the argument method
+                 returns a gdb.Symbol, GDB will look-up and print the
+                 value of the gdb.Symbol automatically.  If the
+                 argument method contains a string, then the value
+                 method must not return a None.
+        """
+        pass
+
+    def frame_locals (self):
+        """ The local variables of the function in this frame.
+
+        Arguments: None.
+
+        Returns: An iterator that conforms to the Python iterator
+                 protocol, or None.  If this method returns a None,
+                 instead of an iterator, then no data will be printed
+                 for frame locals.  If this method returns an
+                 iterator, it must contain objects that implement two
+                 methods, described here.
+
+                 The object must implement an argument method which
+                 takes no parameters and must return a gdb.Symbol or a
+                 Python string.  It must also implement a value method
+                 which takes no parameters and which must return a
+                 gdb.Value, a Python value, or None.  If the value
+                 method returns a None, and the argument method
+                 returns a gdb.Symbol, GDB will look-up and print the
+                 value of the gdb.Symbol automatically.  If the
+                 argument method contains a string, then the value
+                 method must not return a None.
+        """
+        pass
+
+    def frame (self):
+        """ The gdb.Frame that this wrapper is wrapping.
+
+        Arguments: None.
+
+        Returns: The gdb.Frame that this wrapper is wrapping.
+        """
+        pass
diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py
index 0671526..a1c661d 100644
--- a/gdb/python/lib/gdb/__init__.py
+++ b/gdb/python/lib/gdb/__init__.py
@@ -72,6 +72,8 @@ pretty_printers = []
 
 # Initial type printers.
 type_printers = []
+# Initial frame filters.
+frame_filters = {}
 
 # Convenience variable to GDB's python directory
 PYTHONDIR = os.path.dirname(os.path.dirname(__file__))
diff --git a/gdb/python/lib/gdb/command/frame_filters.py b/gdb/python/lib/gdb/command/frame_filters.py
new file mode 100644
index 0000000..fc115b0
--- /dev/null
+++ b/gdb/python/lib/gdb/command/frame_filters.py
@@ -0,0 +1,621 @@
+# Frame-filter commands.
+# Copyright (C) 2012 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 gdb
+import copy
+from gdb.FrameIterator import FrameIterator
+from gdb.BaseFrameWrapper import BaseFrameWrapper
+import itertools
+
+def _parse_arg(cmd_name, arg):
+    """ Internal worker function to take an argument 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.
+    """
+
+    argv = gdb.string_to_argv(arg);
+    argc = len(argv)
+    if argc != 2:
+        raise gdb.GdbError(cmd_name + " takes exactly two arguments.")
+
+    object_list = argv[0]
+    argument = argv[1]
+
+    return(object_list, argument)
+
+def _get_sort_priority(filter_item):
+    """ Internal worker function to return the frame-filter's priority
+    from a frame filter tuple object.
+
+    Arguments:
+        filter_item: A tuple, with the first element being the name,
+                     and the second being the frame-filter object.
+
+    Returns:
+        The priority of the frame filter from the "priority"
+        attribute.
+    """
+    # Do not fail here, as the sort will fail.  If a filter has not
+    # (incorrectly) set a priority, set it to zero.
+    if hasattr(filter_item[1], "priority"):
+        return filter_item[1].priority
+    else:
+        return 0
+
+def _get_priority(filter_item):
+    """ Internal worker function to return the frame-filter's priority.
+
+    Arguments:
+        filter_item: An object conforming to the frame filter
+        interface.
+
+    Returns:
+        The priority of the frame filter from the "priority"
+        attribute.
+
+    Raises:
+        gdb.GdbError: When the priority attribute has not been
+                      implemented.
+    """
+    if hasattr(filter_item, "priority"):
+        return filter_item.priority
+    else:
+        raise gdb.GdbError("Cannot find class attribute 'priority'")
+
+def _set_priority(filter_item, priority):
+    """ Internal worker function to set the frame-filter's priority.
+
+    Arguments:
+        filter_item: An object conforming to the frame filter
+                     interface.
+        priority: The priority to assign as an integer.
+
+    Raises:
+        gdb.GdbError: When the priority attribute has not been
+                      implemented.
+    """
+
+    if hasattr(filter_item, "priority"):
+        filter_item.priority = priority
+    else:
+        raise gdb.GdbError("Cannot find class attribute 'priority'")
+
+def _get_enabled(filter_item):
+    """ Internal worker function to return the frame-filter's enabled
+    state.
+
+    Arguments:
+        filter_item: An object conforming to the frame filter
+                     interface.
+
+    Returns:
+        The enabled state of the frame filter from the "enabled"
+        attribute.
+
+    Raises:
+        gdb.GdbError: When the enabled attribute has not been
+                      implemented.
+    """
+
+    if hasattr(filter_item, "enabled"):
+        return filter_item.enabled
+    else:
+        raise gdb.GdbError("Cannot find class attribute 'enabled'")
+
+def _get_filter_enabled(filter_item):
+    """ Internal Worker function to return the frame-filter's enabled
+    state for filter operations.
+
+    Arguments:
+        filter_item: A tuple, with the first element being the name,
+                     and the second being the frame-filter object.
+    Returns:
+        The enabled state of the frame filter from the "enabled"
+        attribute.
+
+    """
+    # If the filter class is badly implemented, do not cease filter
+    # operations, just set enabled to False.
+    try:
+        enabled = _get_enabled(filter_item[1])
+    except gdb.GdbError as e:
+        enabled = False
+
+    return enabled
+
+def _set_enabled(filter_item, state):
+    """ Internal Worker function to set the frame-filter's enabled
+    state.
+
+    Arguments:
+        filter_item: An object conforming to the frame filter
+                     interface.
+        state: True or False, depending on desired state.
+
+    Raises:
+        gdb.GdbError: When the enabled attribute has not been
+                      implemented.
+    """
+
+    if hasattr(filter_item, "enabled"):
+        filter_item.enabled = state
+    else:
+        raise gdb.GdbError("Cannot find class attribute 'enabled'")
+
+def _get_name(frame_filter):
+    """ Internal Worker function to return the name of the
+    frame-filter.
+
+    Arguments:
+        filter_item: An object conforming to the frame filter
+                     interface.
+
+    Returns:
+        The name of the frame filter from the "name" attribute.
+
+    Raises:
+        gdb.GdbError: When the name attribute has not been
+                      implemented.
+    """
+    if hasattr(frame_filter, "name"):
+        return frame_filter.name
+    raise gdb.GdbError("Cannot find class attribute 'name'")
+
+def _return_list(name):
+    """ Internal Worker function to return the frame filter
+    dictionary, depending on the name supplied as an argument.  If the
+    name is not "global" or "progspace", it is assumed to name an
+    object-file.
+
+    Arguments:
+        name: The name of the list, as specified by GDB user commands.
+
+    Returns:
+        A dictionary object.
+
+    Raises:
+        gdb.GdbError:  A dictionary of that name cannot be found.
+    """
+
+    if name  == "global":
+        return gdb.frame_filters
+    else:
+        if name == "progspace":
+            cp = gdb.current_progspace()
+            return cp.frame_filters
+        else:
+            for objfile in gdb.objfiles():
+                if name == objfile.filename:
+                    return objfile.frame_filters
+
+    msg = "Cannot find frame-filter dictionary for '" + name + "'"
+    raise gdb.GdbError(msg)
+
+def _sort_list():
+    """ Internal Worker function to merge all known frame-filter
+    lists, prune any filters with the state set to "disabled", and
+    sort the list on the frame-filter's "priority" attribute.
+
+    Returns:
+        sorted_list: A sorted, pruned list of frame filters to
+                     execute.
+    """
+
+    all_filters = []
+    for objfile in gdb.objfiles():
+        all_filters = all_filters + objfile.frame_filters.items()
+    cp = gdb.current_progspace()
+
+    all_filters = all_filters + cp.frame_filters.items()
+    all_filters = all_filters + gdb.frame_filters.items()
+
+    sorted_frame_filters = copy.copy(all_filters)
+    sorted_frame_filters.sort(key = _get_sort_priority,
+                                   reverse = True)
+    sorted_frame_filters = filter(_get_filter_enabled,
+                                  sorted_frame_filters)
+
+    return sorted_frame_filters
+
+def invoke(frame):
+    """ Public internal function that will execute the chain of frame
+    filters.  Each filter is executed in priority order.
+
+    Arguments:
+        frame: The initial frame.
+
+    Returns:
+        frame_iterator: The iterator after all frame filters have
+                        had a change to execute, or None if no frame
+                        filters are registered.
+    """
+
+    # Get a sorted list of frame filters.
+    sorted_list = _sort_list()
+
+    # Check to see if there are any frame-filters.  If not, just
+    # return None and let default backtrace printing occur.
+    if len(sorted_list) == 0:
+        return None
+
+    frame_iterator = FrameIterator(frame)
+
+    # Apply base filter to all gdb.Frames.  This unifies the
+    # interface.
+    frame_iterator = itertools.imap(BaseFrameWrapper, frame_iterator)
+
+    for ff in sorted_list:
+        frame_iterator = ff[1].filter(frame_iterator)
+
+    return frame_iterator
+
+# GDB Commands.
+class SetFilterPrefixCmd(gdb.Command):
+    def __init__(self):
+        super(SetFilterPrefixCmd, self).__init__("set python frame-filter",
+                                                 gdb.COMMAND_DATA,
+                                                 gdb.COMPLETE_COMMAND, True)
+class ShowFilterPrefixCmd(gdb.Command):
+    def __init__(self):
+        super(ShowFilterPrefixCmd, self).__init__("show python frame-filter",
+                                                  gdb.COMMAND_DATA,
+                                                  gdb.COMPLETE_COMMAND, True)
+class InfoFrameFilter(gdb.Command):
+    """GDB command to list all registered frame-filters.
+
+    Usage: info frame-filters
+    """
+    @staticmethod
+    def enabled_string(state):
+        """Return "Yes" if filter is enabled, otherwise "No"."""
+        if state:
+            return "Yes"
+        else:
+            return "No"
+
+    def __init__(self):
+        super(InfoFrameFilter, self).__init__("info frame-filter",
+                                              gdb.COMMAND_DATA)
+
+    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 = frame_filters.items()
+        sorted_frame_filters.sort(key = _get_sort_priority,
+                                  reverse = True)
+
+        print "  Priority  Enabled  Name"
+        print "  ========  =======  ===="
+        if len(sorted_frame_filters) == 0:
+            print "  No frame filters registered."
+        else:
+            for frame_filter in sorted_frame_filters:
+                name = frame_filter[0]
+                try:
+                    priority = '{:<8}'.format(
+                        str(_get_priority(frame_filter[1])))
+                    enabled = '{:<7}'.format(
+                        self.enabled_string(_get_enabled(frame_filter[1])))
+                except Exception as e:
+                    print "  Error printing filter '"+name+"': ",e
+                else:
+                    print "  %s  %s  %s" % (priority, enabled, name)
+
+    def print_list(self, title, filter_list):
+        """Print a list."""
+        if filter_list:
+            print title
+            self.list_frame_filters(filter_list)
+
+    def invoke(self, arg, from_tty):
+        """GDB calls this to perform the command."""
+        self.print_list("global frame-filters:", gdb.frame_filters)
+
+        cp = gdb.current_progspace()
+        self.print_list("progspace %s frame-filters:" % cp.filename,
+                        cp.frame_filters)
+
+        for objfile in gdb.objfiles():
+            self.print_list("objfile %s frame-filters:" % objfile.filename,
+                            objfile.frame_filters)
+
+# Internal enable/disable functions.
+
+def do_enable_frame_filter_1(frame_filters, name, flag):
+    """Internal worker for enabling/disabling frame_filters.
+
+    Arguments:
+        frame_filters: Dictionary that this frame filter is contained
+                       within.
+        name: Name of the frame filter.
+        flag: True for Enable, False for Disable.
+
+    Raises:
+        gdb.GdbError: A frame filter cannot be found.
+    """
+
+    try:
+        ff = frame_filters[name]
+    except KeyError:
+        msg = "frame-filter '" + str(name) + "' not found."
+        raise gdb.GdbError(msg)
+
+    _set_enabled(ff, flag)
+
+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]
+    frame_filter = command_tuple[1]
+
+    op_list = _return_list(list_op)
+    do_enable_frame_filter_1(op_list, frame_filter, flag)
+
+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.  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(EnableFrameFilter, self).__init__("enable frame-filter",
+                                                 gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        """GDB calls this to perform the command."""
+        command_tuple = _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.  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(DisableFrameFilter, self).__init__("disable frame-filter",
+                                                  gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        """GDB calls this to perform the command."""
+        command_tuple = _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 python 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 new priority to set the frame filter.
+    """
+
+    def __init__(self):
+        super(SetFrameFilterPriority, self).__init__("set python " \
+                                                     "frame-filter priority",
+                                                     gdb.COMMAND_DATA,
+                                                     gdb.COMPLETE_COMMAND)
+    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:
+            raise gdb.GdbError("set python frame-filter priority " \
+                              "takes exactly three arguments.")
+
+        object_list = argv[0]
+        name = argv[1]
+        priority = argv[2]
+        return(object_list, name, priority)
+
+    def _set_filter_priority_1(self, frame_filters, name, priority):
+        """Internal worker for setting priority of frame_filters.
+
+        Arguments:
+            frame_filters: The frame_filter dictionary.
+            name: The name of the filter.
+            priority: Priority of filter.
+
+        Raises:
+            gdb.GdbError: An error finding the frame filter.
+        """
+        try:
+            ff = frame_filters[name]
+        except KeyError:
+            msg = "frame-filter '" + str(name) + "' not found."
+            raise gdb.GdbError(msg)
+
+        _set_priority(ff, priority)
+
+    def _set_filter_priority(self,command_tuple):
+        """Internal worker for setting priority of frame-filters, by
+        parsing a tuple and calling _set_filter_priority_1 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]
+        priority = command_tuple [2]
+
+        op_list = _return_list(list_op)
+
+        self._set_filter_priority_1(op_list, frame_filter, priority)
+
+    def invoke(self, arg, from_tty):
+        """GDB calls this to perform the command."""
+
+        command_tuple = self._parse_pri_arg(arg)
+        try:
+            self._set_filter_priority(command_tuple)
+        except gdb.GdbError as e:
+            # Print the error, instead of raising it.
+            gdb.write(e.message+"\n")
+
+class ShowFrameFilterPriority(gdb.Command):
+    """GDB command to show the priority of the specified frame-filter.
+
+    Usage: show python frame-filter priority list name
+
+    LIST is the name of the frame-filter list to operate.  Named lists
+    are: "global" for the global frame-filter list, "progspace" for
+    the program space's file frame-filter list.  If either of these
+    two are not specified, the list 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 python " \
+                                                      "frame-filter priority",
+                                                      gdb.COMMAND_DATA,
+                                                      gdb.COMPLETE_COMMAND)
+    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:
+            raise gdb.GdbError("show python frame-filter priority " \
+                              "takes exactly two arguments.")
+
+        object_list = argv[0]
+        name = argv[1]
+        return (object_list, name)
+
+    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 = _return_list(frame_filters)
+
+        try:
+            ff = op_list[name]
+        except KeyError:
+            msg = "frame-filter '" + str(name) + "' not found."
+            raise gdb.GdbError(msg)
+
+        return _get_priority(ff)
+
+    def invoke(self, arg, from_tty):
+        """GDB calls this to perform the command."""
+        try:
+            command_tuple = self._parse_pri_arg(arg)
+        except gdb.GdbError as e:
+            # Print the error instead of raising it.
+            gdb.write(e.message+"\n")
+            return
+        filter_name = command_tuple[1]
+        list_name = command_tuple[0]
+        try:
+            priority = self.get_filter_priority(list_name, filter_name);
+        except Exception as e:
+            print "Error printing filter priority for '"+name+"':",e
+        else:
+            print "Priority of filter '" + filter_name + "' in list '" \
+                + list_name + "' is: " + str(priority)
+
+def register_frame_filter_commands():
+    """Call from a top level script to install the frame-filter commands."""
+    InfoFrameFilter()
+    SetFilterPrefixCmd()
+    ShowFilterPrefixCmd()
+    EnableFrameFilter()
+    DisableFrameFilter()
+    SetFrameFilterPriority()
+    ShowFrameFilterPriority()
+
+register_frame_filter_commands()
diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c
new file mode 100644
index 0000000..ad0c44a
--- /dev/null
+++ b/gdb/python/py-framefilter.c
@@ -0,0 +1,1324 @@
+/* Python frame filters
+
+   Copyright (C) 2012 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#include "defs.h"
+#include "objfiles.h"
+#include "symtab.h"
+#include "language.h"
+#include "exceptions.h"
+#include "arch-utils.h"
+#include "python.h"
+#include "ui-out.h"
+#include "valprint.h"
+#include "annotate.h"
+#include "hashtab.h"
+#include "mi/mi-cmds.h"
+#include "demangle.h"
+#include "mi/mi-cmds.h"
+#include "python-internal.h"
+
+
+/* Helper function to extract a symbol, name and language definition
+   from a Python object that conforms to the "Symbol Value" interface.
+   OBJ is the Python object to extract the values from.  **NAME is a
+   pass-through argument where the name of the symbol will be written.
+   **NAME is allocated in this function, but the caller is responsible
+   for clean up.  **SYM is a pass-through argument where the symbol
+   will be written.  In the case of the API returning a string, this
+   will be set to NULL.  **LANGUAGE is also a pass-through argument
+   denoting the language attributed to the Symbol.  In the case of
+   **SYM being NULL, this will be set to the current language.
+   Returns 0 on error with the appropriate Python exception set, and 1
+   on success.  */
+
+static int
+extract_sym (PyObject *obj, char **name, struct symbol **sym,
+	     const struct language_defn **language)
+{
+  if (PyObject_HasAttrString (obj, "symbol"))
+    {
+      PyObject *result = PyObject_CallMethod (obj, "symbol", NULL);
+
+      if (! result)
+	return 0;
+
+      /* For 'symbol' callback, the function can return a symbol or a
+	 string.  */
+      if (PyString_Check (result))
+	{
+	  *name = python_string_to_host_string (result);
+	  Py_DECREF (result);
+
+	  if (! *name)
+	    return 0;
+	  *language = current_language;
+	  *sym = NULL;
+	}
+      else
+	{
+	  /* This type checks 'result' during the conversion so we
+	     just call it unconditionally and check the return.  */
+	  *sym = symbol_object_to_symbol (result);
+
+	  Py_DECREF (result);
+
+	  if (! *sym)
+	    {
+	      PyErr_SetString (PyExc_RuntimeError,
+			       _("Unexpected value.  Expecting a " \
+				 "gdb.Symbol or a Python string."));
+	      return 0;
+	    }
+
+	  /* Duplicate the symbol name, so the caller has consistency
+	     in garbage collection.  */
+	  *name = xstrdup (SYMBOL_PRINT_NAME (*sym));
+
+	  if (language_mode == language_mode_auto)
+	    *language = language_def (SYMBOL_LANGUAGE (*sym));
+	  else
+	    *language = current_language;
+	}
+    }
+  else
+    {
+      PyErr_SetString (PyExc_RuntimeError,
+			 _("Mandatory function 'symbol' not " \
+			 "implemented."));
+      return 0;
+    }
+
+  return 1;
+}
+
+/* Helper function to extract a value from an object that conforms to
+   the "Symbol Value" interface.  OBJ is the Python object to extract
+   the value from.  **VALUE is a pass-through argument where the value
+   will be written.  If the object does not have the value attribute,
+   or provides the Python None for a value, **VALUE will be set to
+   NULL and this function will return as successful.  Returns 0 on
+   error with the appropriate Python exception set, and 1 on
+   success.  */
+
+static int
+extract_value (PyObject *obj, struct value **value)
+{
+  if (PyObject_HasAttrString (obj, "value"))
+    {
+      PyObject *vresult = PyObject_CallMethod (obj, "value", NULL);
+
+      if (! vresult)
+	return 0;
+
+      /* The Python code has returned 'None' for a value, so we set
+	 value to NULL.  This flags that GDB should read the
+	 value.  */
+      if (vresult == Py_None)
+	{
+	  Py_DECREF (vresult);
+	  *value = NULL;
+	  return 1;
+	}
+      else
+	{
+	  *value = convert_value_from_python (vresult);
+	  Py_DECREF (vresult);
+
+	  if (*value == NULL)
+	    return 0;
+
+	  return 1;
+	}
+    }
+  else
+    *value = NULL;
+
+  return 1;
+}
+
+static int
+mi_should_print (struct symbol *sym, const char *type)
+{
+  int print_me = 0;
+
+  switch (SYMBOL_CLASS (sym))
+    {
+    default:
+    case LOC_UNDEF:	/* catches errors        */
+    case LOC_CONST:	/* constant              */
+    case LOC_TYPEDEF:	/* local typedef         */
+    case LOC_LABEL:	/* local label           */
+    case LOC_BLOCK:	/* local function        */
+    case LOC_CONST_BYTES:	/* loc. byte seq.        */
+    case LOC_UNRESOLVED:	/* unresolved static     */
+    case LOC_OPTIMIZED_OUT:	/* optimized out         */
+      print_me = 0;
+      break;
+
+    case LOC_ARG:	/* argument              */
+    case LOC_REF_ARG:	/* reference arg         */
+    case LOC_REGPARM_ADDR:	/* indirect register arg */
+    case LOC_LOCAL:	/* stack local           */
+    case LOC_STATIC:	/* static                */
+    case LOC_REGISTER:	/* register              */
+    case LOC_COMPUTED:	/* computed location     */
+      if (strcmp (type, "all"))
+	print_me = 1;
+      else if (strcmp (type, "locals"))
+	print_me = !SYMBOL_IS_ARGUMENT (sym);
+      else
+	print_me = SYMBOL_IS_ARGUMENT (sym);
+    }
+  return print_me;
+}
+
+/* Helper function which outputs a type name to a "type" field in a
+   stream.  OUT is the ui-out structure the type name will be output
+   too, and VAL is the value that the type will be extracted from.
+   Returns 0 on error, with any GDB exceptions converted to a Python
+   exception.  */
+
+static int
+py_print_type (struct ui_out *out, struct value *val)
+{
+  volatile struct gdb_exception except;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      struct type *type;
+      struct ui_file *stb;
+      struct cleanup *cleanup;
+
+      stb = mem_fileopen ();
+      cleanup = make_cleanup_ui_file_delete (stb);
+      type = check_typedef (value_type (val));
+      type_print (value_type (val), "", stb, -1);
+      ui_out_field_stream (out, "type", stb);
+      do_cleanups (cleanup);
+    }
+  if (except.reason > 0)
+    {
+      PyErr_SetString (PyExc_RuntimeError,
+		       except.message);
+      return 0;
+    }
+  return 1;
+}
+
+/* Helper function which outputs a value name to value field in a
+   stream.  OUT is the ui-out structure the value will be output too,
+   VAL is the value that will be printed, OPTS contains the value
+   printing options, MI_PRINT_TYPE is the value delimiter for MI
+   output and LANGUAGE is the language_defn that the value will be
+   printed with.  If the output is detected to be non-MI,
+   MI_PRINT_TYPE is ignored.  Returns 0 on error, with any GDB
+   exceptions converted to a Python exception.  */
+
+static int
+py_print_value (struct ui_out *out, struct value *val,
+		struct value_print_options opts,
+		int mi_print_type,
+		const struct language_defn *language)
+{
+  int should_print = 0;
+
+  /* MI disallows different value types against different options the
+     client passes, so test type against option.  For CLI print all
+     values.  */
+  if (ui_out_is_mi_like_p (out))
+    {
+      struct type *type;
+
+      type = check_typedef (value_type (val));
+      if (mi_print_type == PRINT_ALL_VALUES)
+	should_print = 1;
+      else if (mi_print_type == PRINT_SIMPLE_VALUES
+	       && TYPE_CODE (type) != TYPE_CODE_ARRAY
+	       && TYPE_CODE (type) != TYPE_CODE_STRUCT
+	       && TYPE_CODE (type) != TYPE_CODE_UNION)
+	should_print = 1;
+    }
+  else
+    should_print = 1;
+
+  if (should_print)
+    {
+      volatile struct gdb_exception except;
+
+      TRY_CATCH (except, RETURN_MASK_ALL)
+	{
+	  struct ui_file *stb;
+	  struct cleanup *cleanup;
+
+	  stb = mem_fileopen ();
+	  cleanup = make_cleanup_ui_file_delete (stb);
+	  common_val_print (val, stb, 0, &opts, language);
+	  ui_out_field_stream (out, "value", stb);
+	  do_cleanups (cleanup);
+	}
+      if (except.reason > 0)
+	{
+	  PyErr_SetString (PyExc_RuntimeError,
+			   except.message);
+	  return 0;
+	}
+    }
+
+  return 1;
+}
+
+/* Helper function to call a Python method and extract an iterator
+   from the result, error checking for Python exception and returns
+   that are not iterators.  FILTER is the Python object to call, and
+   FUNC is the name of the method.  Returns a PyObject, or NULL on
+   error with the appropriate exception set.  This function can return
+   an iterator, or None.  */
+
+static PyObject *
+get_py_iter_from_func (PyObject *filter, char *func)
+{
+  if (PyObject_HasAttrString (filter, func))
+    {
+      PyObject *result = PyObject_CallMethod (filter, func, NULL);
+
+      if (result)
+	{
+	  if (result != Py_None)
+	    {
+	      if (! PyIter_Check (result))
+		{
+		  PyErr_Format (PyExc_RuntimeError,
+				_(" %s function must " \
+				  "return an iterator."), func);
+		  Py_DECREF (result);
+		  return NULL;
+		}
+	      else
+		{
+		  PyObject *iterator = PyObject_GetIter (result);
+
+		  Py_DECREF (result);
+
+		  if (! iterator)
+		    return NULL;
+		  else
+		    return iterator;
+		}
+	    }
+	}
+      else
+	return NULL;
+    }
+
+    Py_RETURN_NONE;
+}
+
+/*  Helper function to output a single frame argument and value to an
+    output stream.  This function will account for entry values if the
+    FV parameter is populated, the frame argument has entry values
+    associated with them, and the appropriate "set entry-value"
+    options are set.  Will output in CLI or MI like format depending
+    on the type of output stream detected.  OUT is the output stream,
+    SYM_NAME is the name of the symbol.  If SYM_NAME is populated then
+    it must have an accompanying value in the parameter FV.  FA is a
+    frame argument structure.  If FA is populated, both SYM_NAME and
+    FV are ignored.  OPTS contains the value printing options,
+    MI_PRINT_TYPE is an enumerator to the value types that will be
+    printed if the output is MI.  PRINT_MI_ARGS indicates whether to
+    output the ARGS="1" field in MI output.  */
+static int
+py_print_single_arg (struct ui_out *out,
+		     char *sym_name,
+		     struct frame_arg *fa,
+		     struct value *fv,
+		     struct value_print_options opts,
+		     int mi_print_type,
+		     int print_mi_args_flag,
+		     const char *cli_print_frame_args_type,
+		     const struct language_defn *language)
+{
+  struct value *val;
+  struct cleanup *inner_cleanup =
+    make_cleanup (null_cleanup, NULL);
+
+  if (fa)
+    {
+      language = language_def (SYMBOL_LANGUAGE (fa->sym));
+      val = fa->val;
+    }
+  else
+    val = fv;
+
+  /*  MI has varying rules for tuples, but generally if there is only
+      one element in each item in the list, do not start a tuple.  */
+  if (print_mi_args_flag || mi_print_type != PRINT_NO_VALUES)
+    {
+      inner_cleanup =
+	make_cleanup_ui_out_tuple_begin_end (out,
+					     NULL);
+    }
+
+  annotate_arg_begin ();
+
+  /* If frame argument is populated, check for entry-values and the
+     entry value options.  */
+  if (fa)
+    {
+      struct ui_file *stb;
+
+      stb = mem_fileopen ();
+
+      fprintf_symbol_filtered (stb, SYMBOL_PRINT_NAME (fa->sym),
+			       SYMBOL_LANGUAGE (fa->sym),
+			       DMGL_PARAMS | DMGL_ANSI);
+      if (fa->entry_kind == print_entry_values_compact)
+	{
+	  fputs_filtered ("=", stb);
+
+	  fprintf_symbol_filtered (stb, SYMBOL_PRINT_NAME (fa->sym),
+				   SYMBOL_LANGUAGE (fa->sym),
+				   DMGL_PARAMS | DMGL_ANSI);
+	}
+      if (fa->entry_kind == print_entry_values_only
+	  || fa->entry_kind == print_entry_values_compact)
+	{
+	  fputs_filtered ("@entry", stb);
+	}
+      ui_out_field_stream (out, "name", stb);
+      ui_file_delete (stb);
+    }
+  else
+    /* Otherwise, just output the name.  */
+    ui_out_field_string (out, "name", sym_name);
+
+  annotate_arg_name_end ();
+
+  if (! ui_out_is_mi_like_p (out))
+    ui_out_text (out, "=");
+
+  if (print_mi_args_flag)
+    ui_out_field_int (out, "arg", 1);
+
+  /* For MI print the type.  */
+  if (ui_out_is_mi_like_p (out)
+      && mi_print_type == PRINT_SIMPLE_VALUES)
+    {
+      if (! py_print_type (out, val))
+	goto error;
+    }
+
+  annotate_arg_value (value_type (val));
+
+    /* If the output is to the CLI, and the user option set print
+     frame-arguments is set to none, just output "...".  */
+  if (! ui_out_is_mi_like_p (out)
+      && ! strcmp (cli_print_frame_args_type, "none"))
+
+    {
+      ui_out_field_string (out, "value", "...");
+    }
+  else
+    {
+      /* If CLI, and the first if condition above not true always
+	 print values.  For MI do not print values if the enumerator
+	 is PRINT_NO_VALUES.  */
+      if (! ui_out_is_mi_like_p (out)
+	  || (ui_out_is_mi_like_p (out)
+	      && mi_print_type != PRINT_NO_VALUES))
+	{
+	  if (! py_print_value (out, val, opts, mi_print_type, language))
+	    goto error;
+	}
+    }
+
+  do_cleanups (inner_cleanup);
+
+  return 1;
+
+ error:
+  do_cleanups (inner_cleanup);
+  return 0;
+}
+
+/* Helper function to loop over frame arguments provided by the
+   "frame_arguments" Python API.  Elements in the iterator must
+   conform to the "Symbol Value" interface.  ITER is the Python
+   iterator object, OUT is the output stream, MI_PRINT_TYPE is an
+   enumerator to the value types that will be printed if the output is
+   MI, PRINT_MI_ARGS indicates whether to output the ARGS="1" field in
+   MI output, CLI_PRINT_FRAME_ARGS_TYPE is an enumerator of the user
+   set option for frame argument printing output, and FRAME is the
+   backing frame.  If (all) the frame argument values are provided via
+   the "value" API call, FRAME is not needed.  */
+
+static int
+enumerate_args (PyObject *iter,
+		struct ui_out *out,
+		int mi_print_type,
+		int print_mi_args_flag,
+		const char *cli_print_frame_args_type,
+		struct frame_info *frame)
+{
+  PyObject *item;
+  struct value_print_options opts;
+
+  get_user_print_options (&opts);
+
+  if (! ui_out_is_mi_like_p (out))
+    {
+      /* True in "summary" mode, false otherwise.  */
+      opts.summary = !strcmp (cli_print_frame_args_type, "scalars");
+    }
+
+  opts.deref_ref = 1;
+
+
+  annotate_frame_args ();
+
+  /*  Collect the first argument outside of the loop, so output of
+      commas in the argument output is correct.  At the end of the
+      loop block collect another item from the iterator, and, if it is
+      not null emit a comma.  */
+  item = PyIter_Next (iter);
+  if (! item && PyErr_Occurred ())
+    goto error;
+
+  while (item)
+    {
+      const struct language_defn *language;
+      char *sym_name;
+      struct symbol *sym;
+      struct value *val;
+      int success = 0;
+      volatile struct gdb_exception except;
+
+      success = extract_sym (item, &sym_name, &sym, &language);
+      if (! success)
+	{
+	  Py_DECREF (item);
+	  goto error;
+	}
+
+      success = extract_value (item, &val);
+      if (! success)
+	{
+	  xfree (sym_name);
+	  Py_DECREF (item);
+	  goto error;
+	}
+
+      Py_DECREF (item);
+      item = NULL;
+
+      if (sym && ui_out_is_mi_like_p (out) && ! mi_should_print (sym, "args"))
+	continue;
+
+      /* If the object did not provide a value, read it using
+	 read_frame_args and account for entry values, if any.  */
+      if (! val)
+	{
+	  struct frame_arg arg, entryarg;
+
+	  /* If there is no value, and also no symbol, set error and
+	     exit.  */
+	  if (! sym)
+	    {
+	      PyErr_SetString (PyExc_RuntimeError,
+			       _("No symbol or value provided."));
+	      xfree (sym_name);
+	      goto error;
+	    }
+
+	  TRY_CATCH (except, RETURN_MASK_ALL)
+	    {
+	      read_frame_arg (sym, frame, &arg, &entryarg);
+	    }
+	  if (except.reason > 0)
+	    {
+	      xfree (sym_name);
+	      PyErr_SetString (PyExc_RuntimeError,
+			       except.message);
+	      goto error;
+	    }
+
+	  /* The object has not provided a value, so this is a frame
+	     argument to be read by GDB.  In this case we have to
+	     account for entry-values.  */
+
+	  if (arg.entry_kind != print_entry_values_only)
+	    py_print_single_arg (out, NULL, &arg, NULL, opts,
+				 mi_print_type,
+				 print_mi_args_flag,
+				 cli_print_frame_args_type, NULL);
+
+	  if (entryarg.entry_kind != print_entry_values_no)
+	    {
+	      if (arg.entry_kind != print_entry_values_only)
+		{
+		  ui_out_text (out, ", ");
+		  ui_out_wrap_hint (out, "    ");
+		}
+
+	      py_print_single_arg (out, NULL, &entryarg, NULL, opts,
+				   mi_print_type,
+				   print_mi_args_flag,
+				   cli_print_frame_args_type, NULL);
+	    }
+
+	  xfree (arg.error);
+	  xfree (entryarg.error);
+	}
+      else
+	{
+	  /* If the object has provided a value, we just print that.  */
+	  if (val)
+	    py_print_single_arg (out, sym_name, NULL, val, opts,
+				 mi_print_type,
+				 print_mi_args_flag,
+				 cli_print_frame_args_type,
+				 language);
+	}
+
+      xfree (sym_name);
+
+      /* Collect the next item from the iterator.  If
+	 this is the last item, do not print the
+	 comma.  */
+      item = PyIter_Next (iter);
+      if (item)
+	ui_out_text (out, ", ");
+      else
+	if (PyErr_Occurred ())
+	  goto error;
+
+      annotate_arg_end ();
+    }
+
+  return 1;
+
+ error:
+  return 0;
+}
+
+
+/* Helper function to loop over variables provided by the
+   "frame_locals" Python API.  Elements in the iterator must conform
+   to the "Symbol Value" interface.  ITER is the Python iterator
+   object, OUT is the output stream, MI_PRINT_TYPE is an enumerator to
+   the value types that will be printed if the output is MI,
+   PRINT_MI_ARGS_FLAG indicates whether to output the ARGS field in MI
+   output, and FRAME is the backing frame.  If (all) of the variables
+   values are provided via the "value" API call, FRAME is not
+   needed.  */
+
+static int
+enumerate_locals (PyObject *iter,
+		  struct ui_out *out,
+		  int mi_print_type,
+		  int indent,
+		  int print_mi_args_flag,
+		  struct frame_info *frame)
+{
+  PyObject *item;
+  struct value_print_options opts;
+
+  get_user_print_options (&opts);
+  opts.deref_ref = 1;
+
+  while ((item = PyIter_Next (iter)))
+    {
+      const struct language_defn *language;
+      char *sym_name;
+      struct value *val;
+      int success = 0;
+      struct symbol *sym;
+      volatile struct gdb_exception except;
+      struct cleanup *inner_cleanup =
+	make_cleanup (null_cleanup, NULL);
+
+      success = extract_sym (item, &sym_name, &sym, &language);
+      if (! success)
+	{
+	  Py_DECREF (item);
+	  goto error;
+	}
+
+      success = extract_value (item, &val);
+      if (! success)
+	{
+	  xfree (sym_name);
+	  Py_DECREF (item);
+	  goto error;
+	}
+
+      Py_DECREF (item);
+
+      if (sym && ui_out_is_mi_like_p (out) && ! mi_should_print (sym, "locals"))
+	continue;
+
+      /* If the object did not provide a value, read it.  */
+      if (! val)
+	{
+	  TRY_CATCH (except, RETURN_MASK_ALL)
+	    {
+	      val = read_var_value (sym, frame);
+	    }
+	  if (except.reason > 0)
+	    {
+	      xfree (sym_name);
+	      PyErr_SetString (PyExc_RuntimeError,
+			       except.message);
+	      goto error;
+	    }
+	}
+
+      /* With PRINT_NO_VALUES, MI does not emit a tuple normally as
+	 each output contains only one field.  The exception is
+	 -stack-list-variables, which always provides a tuple.  */
+      if (ui_out_is_mi_like_p (out))
+	{
+	  if (print_mi_args_flag || mi_print_type != PRINT_NO_VALUES)
+	    {
+	      inner_cleanup =
+		make_cleanup_ui_out_tuple_begin_end (out,
+						     NULL);
+	    }
+	}
+      else
+	/* If the output is not MI we indent locals.  */
+	ui_out_spaces (out, (8 + (indent * 2)));
+
+      ui_out_field_string (out, "name", sym_name);
+      xfree (sym_name);
+
+      if (! ui_out_is_mi_like_p (out))
+	ui_out_text (out, " = ");
+
+      if (ui_out_is_mi_like_p (out)
+	  && mi_print_type == PRINT_SIMPLE_VALUES)
+	{
+	  if (! py_print_type (out, val))
+	    goto error;
+	}
+
+      if (! ui_out_is_mi_like_p (out)
+	  || (ui_out_is_mi_like_p (out)
+	      && mi_print_type != PRINT_NO_VALUES))
+	{
+	  py_print_value (out, val, opts, mi_print_type, language);
+	}
+
+      ui_out_text (out, "\n");
+      do_cleanups (inner_cleanup);
+    }
+
+  if (! item && PyErr_Occurred())
+    goto error;
+
+ done:
+  return 1;
+
+ error:
+  return 0;
+}
+
+/*  Helper function for -stack-list-variables.  */
+
+static int
+py_mi_print_variables (PyObject *filter, struct ui_out *out,
+		       int mi_print_type,
+		       const char *cli_print_frame_args_type,
+		       struct frame_info *frame)
+{
+  struct cleanup *old_chain;
+  PyObject *args_iter;
+  PyObject *locals_iter;
+
+  args_iter = get_py_iter_from_func (filter, "frame_args");
+  old_chain = make_cleanup_py_xdecref (args_iter);
+  if (! args_iter)
+    goto error;
+
+  locals_iter = get_py_iter_from_func (filter, "frame_locals");
+  if (! locals_iter)
+    goto error;
+
+  make_cleanup_py_decref (locals_iter);
+  make_cleanup_ui_out_list_begin_end (out, "variables");
+
+  if (args_iter != Py_None)
+      if (! enumerate_args (args_iter, out, mi_print_type,
+			    1, cli_print_frame_args_type, frame))
+	goto error;
+
+  if (locals_iter != Py_None)
+    if (! enumerate_locals (locals_iter, out, mi_print_type, 1, 1,
+			    frame))
+
+      goto error;
+
+  do_cleanups (old_chain);
+  return 1;
+
+ error:
+  do_cleanups (old_chain);
+  return 0;
+}
+
+/* Helper function for printing locals.  This function largely just
+   creates the wrapping tuple, and calls enumerate_locals.  */
+
+static int
+py_print_locals (PyObject *filter,
+		 struct ui_out *out,
+		 int mi_print_type,
+		 int indent,
+		 struct frame_info *frame)
+{
+  PyObject *locals_iter = get_py_iter_from_func (filter,
+						 "frame_locals");
+  struct cleanup *old_chain = make_cleanup_py_xdecref (locals_iter);
+
+  if (! locals_iter)
+    goto locals_error;
+
+  make_cleanup_ui_out_list_begin_end (out, "locals");
+  if (locals_iter != Py_None)
+    if (! enumerate_locals (locals_iter, out, mi_print_type,
+			    indent, 0, frame))
+      goto locals_error;
+
+  do_cleanups (old_chain);
+  return 1;
+
+ locals_error:
+  do_cleanups (old_chain);
+  return 0;
+}
+
+/* Helper function for printing frame arguments.  This function
+   largely just creates the wrapping tuple, and calls
+   enumerate_args.  */
+
+static int
+py_print_args (PyObject *filter,
+	       struct ui_out *out,
+	       int mi_print_type,
+	       const char *cli_print_frame_args_type,
+	       struct frame_info *frame)
+{
+  PyObject *args_iter  = get_py_iter_from_func (filter, "frame_args");
+  struct cleanup *old_chain = make_cleanup_py_xdecref (args_iter);
+
+  if (! args_iter)
+    goto args_error;
+
+  make_cleanup_ui_out_list_begin_end (out, "args");
+  annotate_frame_args ();
+
+  if (! ui_out_is_mi_like_p (out))
+    ui_out_text (out, " (");
+
+  if (args_iter != Py_None)
+    if (! enumerate_args (args_iter, out, mi_print_type,
+			  0, cli_print_frame_args_type,
+			  frame))
+      goto args_error;
+
+  if (! ui_out_is_mi_like_p (out))
+    ui_out_text (out, ")");
+
+  do_cleanups (old_chain);
+  return 1;
+
+ args_error:
+  do_cleanups (old_chain);
+  return 0;
+}
+
+/* Hash function for the printed frame hash.  */
+
+static hashval_t
+hash_printed_frame_entry (const void *data)
+{
+  const struct frame_info *frame = data;
+
+  return htab_hash_pointer (frame);
+}
+
+/* Equality function for the printed hash.  */
+
+static int
+eq_printed_frame_entry (const void *a, const void *b)
+{
+  const struct frame_info *ea = a;
+  const struct frame_info *eb = b;
+
+  return ea == eb;
+}
+
+
+/*  Print a single frame to the designated output stream, detecting
+    whether the output is MI or console, and formatting the output
+    according to the conventions of that protocol.  FILTER is the
+    frame-filter associated with this frame.  PRINT_LEVEL is a flag
+    and indicates whether to print the frame level.  PRINT_FRAME_INFO
+    is a flag that indicates to print the frame information
+    (everything other than arguments or locals).  PRINT_ARGS is a flag
+    that indicates whether to print frame arguments, and PRINT_LOCALS
+    is a flag that indicates whether to print frame local variables.
+    MI_PRINT_TYPE is an enumerator to the value types that will be
+    printed if the output is MI.  CLI_PRINT_FRAMES_ARGS_TYPE is an
+    enumerator indicating what type of frame arguments to print.  OUT
+    is the output stream to print too, INDENT is the level of
+    indention for this frame (in the case of elided frames), and
+    LEVELS_PRINTED is a hash-table containing all the frames level
+    that have already been printed.  If a frame level has been
+    printed, do not print it again (in the case of elided frames).  */
+
+static int
+py_print_frame (PyObject *filter, int print_level, int print_frame_info,
+		int print_args, int print_locals, int mi_print_type,
+		const char *cli_print_frame_args_type,
+		struct ui_out *out, int indent, htab_t levels_printed)
+{
+  int has_addr = 0;
+  CORE_ADDR address = 0;
+  struct gdbarch *gdbarch = NULL;
+  struct frame_info *frame = NULL;
+  struct cleanup *cleanup_stack = make_cleanup (null_cleanup, NULL);
+  struct value_print_options opts;
+  PyObject *elided;
+
+  get_user_print_options (&opts);
+
+  /* Get the underlying frame.  This is needed to determine GDB
+  architecture, and also, in the cases of frame variables/arguments to
+  read them if they returned filter object requires us to do so.  */
+  if (PyObject_HasAttrString (filter, "inferior_frame"))
+    {
+      PyObject *result = PyObject_CallMethod (filter, "inferior_frame", NULL);
+
+      if (! result)
+	goto error;
+      frame = frame_object_to_frame_info (result);
+      if (! frame)
+	{
+	  Py_DECREF (result);
+	  goto error;
+	}
+
+      gdbarch = get_frame_arch (frame);
+      Py_DECREF (result);
+    }
+  else
+    {
+      PyErr_SetString (PyExc_RuntimeError,
+		       _("'inferior_frame' API must be implemented."));
+      goto error;
+    }
+
+  /* stack-list-variables.  */
+  if (print_locals && print_args && ! print_frame_info)
+    {
+      if (! py_mi_print_variables (filter, out,
+				   mi_print_type,
+				   cli_print_frame_args_type,
+				   frame))
+	goto error;
+      else
+	return PY_BT_COMPLETED;
+    }
+
+  /* -stack-list-locals does not require a
+     wrapping frame attribute.  */
+  if (print_frame_info || (print_args && ! print_locals))
+    make_cleanup_ui_out_tuple_begin_end (out, "frame");
+
+  if (print_frame_info)
+    {
+      /* Elided frames are also printed with this function (recursively)
+	 and are printed with indention.  */
+      if (indent > 0)
+	ui_out_spaces (out, indent);
+
+      /* The address is required for frame annotations, and also for
+	 address printing.  */
+      if (PyObject_HasAttrString (filter, "address"))
+	{
+	  PyObject *paddr = PyObject_CallMethod (filter, "address", NULL);
+	  if (paddr)
+	    {
+	      if (paddr != Py_None)
+		{
+		  address = PyLong_AsLong (paddr);
+		  has_addr = 1;
+		}
+	      Py_DECREF (paddr);
+	    }
+	  else
+	    goto error;
+	}
+
+    }
+
+  /* Print frame level.  MI does not require the level if
+     locals/variables only are being printed.  */
+  if ((print_frame_info || print_args) && print_level)
+    {
+      struct frame_info **slot;
+      int level;
+
+      slot = (struct frame_info **) htab_find_slot (levels_printed,
+						    frame, INSERT);
+      level = frame_relative_level (frame);
+
+      /* Check if this frame has already been printed (there are cases
+	 where elided synthetic dummy-frames have to 'borrow' the frame
+	 architecture from the eliding frame.  If that is the case, do
+	 not print 'level', but print spaces.  */
+      if (*slot != NULL && (*slot) == frame)
+	{
+	  char buffer[10];
+	  sprintf (buffer, "%d", level);
+	  ui_out_spaces (out, strlen (buffer) + 2);
+	}
+      else
+	{
+	  *slot = frame;
+	  annotate_frame_begin (print_level ? level : 0,
+				gdbarch, address);
+	  ui_out_text (out, "#");
+	  ui_out_field_fmt_int (out, 2, ui_left, "level",
+				level);
+	}
+    }
+
+  if (print_frame_info)
+    {
+      /* Print address to the address field.  If an address is not provided,
+	 print nothing.  */
+      if (opts.addressprint && has_addr)
+	{
+	  annotate_frame_address ();
+	  ui_out_field_core_addr (out, "addr", gdbarch, address);
+	  annotate_frame_address_end ();
+	  ui_out_text (out, " in ");
+	}
+
+      /* Print frame function.  */
+      if (PyObject_HasAttrString (filter, "function"))
+	{
+	  PyObject *result = PyObject_CallMethod (filter, "function", NULL);
+
+	  if (result)
+	    {
+	      if (result != Py_None)
+		{
+		  char *func = NULL;
+		  char *dup = PyString_AsString (result);
+
+		  if (! dup)
+		    {
+		      Py_DECREF (result);
+		      goto error;
+		    }
+
+		  func = xstrdup (dup);
+		  annotate_frame_function_name ();
+		  ui_out_field_string (out, "func", func);
+		  xfree (func);
+
+		}
+	      Py_DECREF (result);
+	    }
+	  else
+	    goto error;
+	}
+    }
+
+
+  /* Frame arguments.  Check the result, and error if something went
+     wrong.  */
+  if (print_args)
+    {
+      if (! py_print_args (filter, out, mi_print_type,
+			   cli_print_frame_args_type, frame))
+	goto error;
+    }
+
+  /* File name/source/line number information.  */
+  if (print_frame_info)
+    {
+      annotate_frame_source_begin ();
+
+      if (PyObject_HasAttrString (filter, "filename"))
+	{
+	  PyObject *result = PyObject_CallMethod (filter, "filename",
+					      NULL);
+	  if (result)
+	    {
+	      if (result != Py_None)
+		{
+		  char *filename = NULL;
+		  char *dup = PyString_AsString (result);
+
+		  if (! dup)
+		    {
+		      Py_DECREF (result);
+		      goto error;
+		    }
+
+		  filename  = xstrdup (dup);
+		  ui_out_wrap_hint (out, "   ");
+		  ui_out_text (out, " at ");
+		  annotate_frame_source_file ();
+		  ui_out_field_string (out, "file", filename);
+		  annotate_frame_source_file_end ();
+		  xfree (filename);
+		}
+	      Py_DECREF (result);
+	    }
+	  else
+	goto error;
+	}
+
+      if (PyObject_HasAttrString (filter, "line"))
+	{
+	  PyObject *result = PyObject_CallMethod (filter, "line", NULL);
+	  int line;
+
+	  if (result)
+	    {
+	      if (result != Py_None)
+		{
+		  line  = PyLong_AsLong (result);
+		  ui_out_text (out, ":");
+		  annotate_frame_source_line ();
+		  ui_out_field_int (out, "line", line);
+		}
+	      Py_DECREF (result);
+	    }
+	  else
+	    goto error;
+	}
+    }
+
+  /* For MI we need to deal with the "children" list population of
+     elided frames, so if MI output detected do not send newline.  */
+  if (! ui_out_is_mi_like_p (out))
+    {
+      annotate_frame_end ();
+      ui_out_text (out, "\n");
+    }
+
+  if (print_locals)
+    {
+      if (! py_print_locals (filter, out, mi_print_type, indent,
+			     frame))
+	goto error;
+    }
+
+  /* Finally recursively print elided frames, if any.  */
+  elided  = get_py_iter_from_func (filter, "elided");
+  if (! elided)
+    goto error;
+
+  if (elided != Py_None)
+    {
+      PyObject *item;
+
+      make_cleanup_py_decref (elided);
+      make_cleanup_ui_out_list_begin_end (out, "children");
+
+      if (! ui_out_is_mi_like_p (out))
+	indent = indent + 4;
+
+      while ((item = PyIter_Next (elided)))
+	{
+	  int success =  py_print_frame (item, print_level,
+					 print_frame_info,
+					 print_args,
+					 print_locals,
+					 mi_print_type,
+					 cli_print_frame_args_type,
+					 out, indent,
+					 levels_printed);
+
+	  if (success == 0 && PyErr_Occurred ())
+	    {
+	      Py_DECREF (item);
+	      goto error;
+	    }
+
+	  Py_DECREF (item);
+	}
+    }
+
+  /* In MI now we can signal the end.  */
+  if (ui_out_is_mi_like_p (out))
+      ui_out_text (out, "\n");
+
+  do_cleanups (cleanup_stack);
+  return PY_BT_COMPLETED;
+
+ error:
+  do_cleanups (cleanup_stack);
+  return PY_BT_ERROR;
+}
+
+/* Helper function to initiate frame filter invocation at starting
+   frame FRAME.  */
+static PyObject *
+bootstrap_python_frame_filters (struct frame_info *frame)
+{
+
+  PyObject *module, *sort_func, *iterable, *frame_obj;
+
+  frame_obj = frame_info_to_frame_object (frame);
+  if (! frame_obj)
+    return NULL;
+
+  module = PyImport_ImportModule ("gdb.command.frame_filters");
+  if (! module)
+    {
+      Py_DECREF (frame_obj);
+      return NULL;
+    }
+
+  sort_func = PyObject_GetAttrString (module, "invoke");
+  if (! sort_func)
+    {
+      Py_DECREF (frame_obj);
+      Py_DECREF (module);
+      return NULL;
+    }
+
+  iterable = PyObject_CallFunctionObjArgs (sort_func, frame_obj, NULL);
+
+  Py_DECREF (module);
+  Py_DECREF (sort_func);
+  Py_DECREF (frame_obj);
+
+  if (! iterable)
+    return NULL;
+
+  return iterable;
+}
+
+/*  Public and dispatch function for frame filters.  This is the only
+    publicly exported function in this file.  FRAME is the source
+    frame to start frame-filter invocation.  FLAGS is an integer
+    holding the flags for printing.  The following elements of the
+    FRAME_FILTER_FLAGS enum denotes makeup of FLAGS: PRINT_LEVEL is a
+    flag indicating whether to print the frame's relative level in the
+    output.  PRINT_FRAME_INFO is a flag that indicates whether this
+    function should print the frame information, PRINT_ARGS is a flag
+    that indicates whether to print frame arguments, and PRINT_LOCALS,
+    likewise, with frame local variables.  MI_PRINT_ARGS_TYPE is an
+    enum from MI that indicates which values types to print.  This
+    parameter is ignored if the output is detected to be CLI.
+    CLI_PRINT_FRAME_ARGS_TYPE likewise is a an element of what value
+    types to print from CLI.  OUT is the output stream to print, and
+    COUNT is a delimiter (required for MI slices).  */
+
+int apply_frame_filter (struct frame_info *frame, int flags,
+			enum print_values mi_print_args_type,
+			const char *cli_print_frame_args_type,
+			struct ui_out *out, int count)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct cleanup *cleanups;
+  int result = 0;
+  int print_result = 0;
+  int success = 0;
+  PyObject *iterable;
+  int print_level, print_frame_info, print_args, print_locals;
+
+  /* Extract print settings from FLAGS.  */
+  print_level = (flags & PRINT_LEVEL) ? 1 : 0;
+  print_frame_info = (flags & PRINT_FRAME_INFO) ? 1 : 0;
+  print_args = (flags & PRINT_ARGS) ? 1 : 0;
+  print_locals = (flags & PRINT_LOCALS) ? 1 : 0;
+
+  cleanups = ensure_python_env (gdbarch, current_language);
+
+  iterable = bootstrap_python_frame_filters (frame);
+
+  if (!iterable)
+    goto done;
+
+  /*  If iterable is None, then there are not any frame filters
+      registered.  If this is the case, defer to default GDB printing
+      routines in MI and CLI.  */
+
+  make_cleanup_py_decref (iterable);
+  if (iterable == Py_None)
+    {
+      do_cleanups (cleanups);
+      return PY_BT_NO_FILTERS;
+    }
+
+  /* Is it an iterator */
+  if PyIter_Check (iterable)
+    {
+      PyObject *iterator = PyObject_GetIter (iterable);
+      PyObject *item;
+      htab_t levels_printed;
+
+      if (! iterator)
+	goto done;
+
+      make_cleanup_py_decref (iterator);
+      levels_printed = htab_create (20,
+				    hash_printed_frame_entry,
+				    eq_printed_frame_entry,
+				    NULL);
+
+      while ((item = PyIter_Next (iterator)) && count--)
+	{
+	  success =  py_print_frame (item, print_level,
+				     print_frame_info, print_args,
+				     print_locals,
+				     mi_print_args_type,
+				     cli_print_frame_args_type,
+				     out, 0, levels_printed);
+
+	  /* Do not exit on error printing the frame, continue with
+	     other frames.  */
+	  if (success == PY_BT_ERROR && PyErr_Occurred ())
+	    gdbpy_print_stack ();
+
+	  Py_DECREF (item);
+	}
+
+      htab_delete (levels_printed);
+    }
+  else
+    {
+      Py_DECREF (iterable);
+      error (_("Frame filter must support iteration protocol."));
+    }
+
+ done:
+  if (PyErr_Occurred ())
+    gdbpy_print_stack ();
+  do_cleanups (cleanups);
+  return success;
+}
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
index 5d2398f..228b71b 100644
--- a/gdb/python/py-objfile.c
+++ b/gdb/python/py-objfile.c
@@ -33,6 +33,8 @@ typedef struct
   /* The pretty-printer list of functions.  */
   PyObject *printers;
 
+  /* The frame filter list of functions.  */
+  PyObject *frame_filters;
   /* The type-printer list.  */
   PyObject *type_printers;
 } objfile_object;
@@ -61,6 +63,7 @@ objfpy_dealloc (PyObject *o)
   objfile_object *self = (objfile_object *) o;
 
   Py_XDECREF (self->printers);
+  Py_XDECREF (self->frame_filters);
   Py_XDECREF (self->type_printers);
   self->ob_type->tp_free ((PyObject *) self);
 }
@@ -81,9 +84,19 @@ objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
 	  return NULL;
 	}
 
+      self->frame_filters = PyDict_New ();
+      if (!self->frame_filters)
+	{
+	  Py_DECREF (self->printers);
+	  Py_DECREF (self);
+	  return NULL;
+	}
+
       self->type_printers = PyList_New (0);
       if (!self->type_printers)
 	{
+	  Py_DECREF (self->printers);
+	  Py_DECREF (self->frame_filters);
 	  Py_DECREF (self);
 	  return NULL;
 	}
@@ -129,6 +142,44 @@ objfpy_set_printers (PyObject *o, PyObject *value, void *ignore)
   return 0;
 }
 
+PyObject *
+objfpy_get_frame_filters (PyObject *o, void *ignore)
+{
+  objfile_object *self = (objfile_object *) o;
+
+  Py_INCREF (self->frame_filters);
+  return self->frame_filters;
+}
+
+static int
+objfpy_set_frame_filters (PyObject *o, PyObject *filters, void *ignore)
+{
+  PyObject *tmp;
+  objfile_object *self = (objfile_object *) o;
+
+  if (! filters)
+    {
+      PyErr_SetString (PyExc_TypeError,
+		       _("Cannot delete the frame filters attribute."));
+      return -1;
+    }
+
+  if (! PyDict_Check (filters))
+    {
+      PyErr_SetString (PyExc_TypeError,
+		       _("The frame_filters attribute must be a dictionary."));
+      return -1;
+    }
+
+  /* Take care in case the LHS and RHS are related somehow.  */
+  tmp = self->frame_filters;
+  Py_INCREF (filters);
+  self->frame_filters = filters;
+  Py_XDECREF (tmp);
+
+  return 0;
+}
+
 /* Get the 'type_printers' attribute.  */
 
 static PyObject *
@@ -225,9 +276,19 @@ objfile_to_objfile_object (struct objfile *objfile)
 	      return NULL;
 	    }
 
+	  object->frame_filters = PyDict_New ();
+	  if (!object->frame_filters)
+	    {
+	      Py_DECREF (object->printers);
+	      Py_DECREF (object);
+	      return NULL;
+	    }
+
 	  object->type_printers = PyList_New (0);
 	  if (!object->type_printers)
 	    {
+	      Py_DECREF (object->printers);
+	      Py_DECREF (object->frame_filters);
 	      Py_DECREF (object);
 	      return NULL;
 	    }
@@ -270,6 +331,8 @@ static PyGetSetDef objfile_getset[] =
     "The objfile's filename, or None.", NULL },
   { "pretty_printers", objfpy_get_printers, objfpy_set_printers,
     "Pretty printers.", NULL },
+  { "frame_filters", objfpy_get_frame_filters,
+    objfpy_set_frame_filters, "Frame Filters.", NULL },
   { "type_printers", objfpy_get_type_printers, objfpy_set_type_printers,
     "Type printers.", NULL },
   { NULL }
diff --git a/gdb/python/py-progspace.c b/gdb/python/py-progspace.c
index c1b1cac..9a26f39 100644
--- a/gdb/python/py-progspace.c
+++ b/gdb/python/py-progspace.c
@@ -35,6 +35,8 @@ typedef struct
   /* The pretty-printer list of functions.  */
   PyObject *printers;
 
+  /* The frame filter list of functions.  */
+  PyObject *frame_filters;
   /* The type-printer list.  */
   PyObject *type_printers;
 } pspace_object;
@@ -69,6 +71,7 @@ pspy_dealloc (PyObject *self)
   pspace_object *ps_self = (pspace_object *) self;
 
   Py_XDECREF (ps_self->printers);
+  Py_XDECREF (ps_self->frame_filters);
   Py_XDECREF (ps_self->type_printers);
   self->ob_type->tp_free (self);
 }
@@ -89,9 +92,19 @@ pspy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
 	  return NULL;
 	}
 
+      self->frame_filters = PyDict_New ();
+      if (!self->frame_filters)
+	{
+	  Py_DECREF (self->printers);
+	  Py_DECREF (self);
+	  return NULL;
+	}
+
       self->type_printers = PyList_New (0);
       if (!self->type_printers)
 	{
+	  Py_DECREF (self->printers);
+	  Py_DECREF (self->frame_filters);
 	  Py_DECREF (self);
 	  return NULL;
 	}
@@ -137,6 +150,44 @@ pspy_set_printers (PyObject *o, PyObject *value, void *ignore)
   return 0;
 }
 
+PyObject *
+pspy_get_frame_filters (PyObject *o, void *ignore)
+{
+  pspace_object *self = (pspace_object *) o;
+
+  Py_INCREF (self->frame_filters);
+  return self->frame_filters;
+}
+
+static int
+pspy_set_frame_filters (PyObject *o, PyObject *frame, void *ignore)
+{
+  PyObject *tmp;
+  pspace_object *self = (pspace_object *) o;
+
+  if (! frame)
+    {
+      PyErr_SetString (PyExc_TypeError,
+		       "cannot delete the frame filter attribute");
+      return -1;
+    }
+
+  if (! PyDict_Check (frame))
+    {
+      PyErr_SetString (PyExc_TypeError,
+		       "the frame filter attribute must be a dictionary");
+      return -1;
+    }
+
+  /* Take care in case the LHS and RHS are related somehow.  */
+  tmp = self->frame_filters;
+  Py_INCREF (frame);
+  self->frame_filters = frame;
+  Py_XDECREF (tmp);
+
+  return 0;
+}
+
 /* Get the 'type_printers' attribute.  */
 
 static PyObject *
@@ -221,13 +272,24 @@ pspace_to_pspace_object (struct program_space *pspace)
 	      return NULL;
 	    }
 
+	  object->frame_filters = PyDict_New ();
+	  if (!object->frame_filters)
+	    {
+	      Py_DECREF (object->printers);
+	      Py_DECREF (object);
+	      return NULL;
+	    }
+
 	  object->type_printers = PyList_New (0);
 	  if (!object->type_printers)
 	    {
+	      Py_DECREF (object->printers);
+	      Py_DECREF (object->frame_filters);
 	      Py_DECREF (object);
 	      return NULL;
 	    }
 
+
 	  set_program_space_data (pspace, pspy_pspace_data_key, object);
 	}
     }
@@ -257,6 +319,8 @@ static PyGetSetDef pspace_getset[] =
     "The progspace's main filename, or None.", NULL },
   { "pretty_printers", pspy_get_printers, pspy_set_printers,
     "Pretty printers.", NULL },
+  { "frame_filters", pspy_get_frame_filters, pspy_set_frame_filters,
+    "Frame filters.", NULL },
   { "type_printers", pspy_get_type_printers, pspy_set_type_printers,
     "Type printers.", NULL },
   { NULL }
diff --git a/gdb/python/py-utils.c b/gdb/python/py-utils.c
index d5d0e431..f8c2e26 100644
--- a/gdb/python/py-utils.c
+++ b/gdb/python/py-utils.c
@@ -48,6 +48,33 @@ make_cleanup_py_decref (PyObject *py)
   return make_cleanup (py_decref, (void *) py);
 }
 
+/* This is a cleanup function which decrements the refcount on a
+   Python object.  This function accounts appropriately for NULL
+   references.  */
+
+static void
+py_xdecref (void *p)
+{
+  PyObject *py = p;
+
+  /* Note that we need the extra braces in this 'if' to avoid a
+     warning from gcc.  */
+  if (py)
+    {
+      Py_XDECREF (py);
+    }
+}
+
+/* Return a new cleanup which will decrement the Python object's
+   refcount when run.  Account for and operate on NULL references
+   correctly.  */
+
+struct cleanup *
+make_cleanup_py_xdecref (PyObject *py)
+{
+  return make_cleanup (py_xdecref, (void *) py);
+}
+
 /* Converts a Python 8-bit string to a unicode string object.  Assumes the
    8-bit string is in the host charset.  If an error occurs during conversion,
    returns NULL with a python exception set.
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index ee04860..0ebb661 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -215,9 +215,11 @@ PyObject *frame_info_to_frame_object (struct frame_info *frame);
 
 PyObject *pspace_to_pspace_object (struct program_space *);
 PyObject *pspy_get_printers (PyObject *, void *);
+PyObject *pspy_get_frame_filters (PyObject *, void *);
 
 PyObject *objfile_to_objfile_object (struct objfile *);
 PyObject *objfpy_get_printers (PyObject *, void *);
+PyObject *objfpy_get_frame_filters (PyObject *, void *);
 
 thread_object *create_thread_object (struct thread_info *tp);
 thread_object *find_thread_object (ptid_t ptid);
@@ -264,6 +266,7 @@ void gdbpy_initialize_thread_event (void);
 void gdbpy_initialize_new_objfile_event (void);
 
 struct cleanup *make_cleanup_py_decref (PyObject *py);
+struct cleanup *make_cleanup_py_xdecref (PyObject *py);
 
 struct cleanup *ensure_python_env (struct gdbarch *gdbarch,
 				   const struct language_defn *language);
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 5f6df60..e7693bd 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1374,6 +1374,14 @@ free_type_printers (void *arg)
 {
 }
 
+int apply_frame_filter (struct frame_info *frame, int flags,
+			enum print_values mi_print_args_type,
+			const char *cli_print_frame_args_type,
+			struct ui_out *out, int count)
+{
+  return PY_BT_NO_FILTERS;
+}
+
 #endif /* HAVE_PYTHON */
 
 

diff --git a/gdb/python/python.h b/gdb/python/python.h
index 72872b0..e90f78c 100644
--- a/gdb/python/python.h
+++ b/gdb/python/python.h
@@ -21,6 +21,7 @@
 #define GDB_PYTHON_H
 
 #include "value.h"
+#include "mi/mi-cmds.h"
 
 struct breakpoint_object;
 
@@ -28,6 +29,28 @@ struct breakpoint_object;
    E.g. When the program loads libfoo.so, look for libfoo-gdb.py.  */
 #define GDBPY_AUTO_FILE_NAME "-gdb.py"
 
+/* Python frame-filter status returns constants.  */
+static const int PY_BT_ERROR = 0;
+static const int PY_BT_COMPLETED = 1;
+static const int PY_BT_NO_FILTERS = 2;
+
+/* Flags to pass to apply_frame_filter.  */
+
+enum frame_filter_flags
+  {
+    /* Set this flag if frame level is to be printed.  */
+    PRINT_LEVEL = 1,
+
+    /* Set this flag if frame information is to be printed.  */
+    PRINT_FRAME_INFO = 2,
+
+    /* Set this flag if frame arguments are to be printed.  */
+    PRINT_ARGS = 4,
+
+    /* Set this flag if frame locals are to be printed.  */
+    PRINT_LOCALS = 8,
+  };
+
 extern void finish_python_initialization (void);
 
 void eval_python_from_control_command (struct command_line *);
@@ -41,6 +64,11 @@ int apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
 			      const struct value_print_options *options,
 			      const struct language_defn *language);
 
+int apply_frame_filter (struct frame_info *frame, int flags,
+			enum print_values mi_print_args_type,
+			const char *cli_print_args_type,
+			struct ui_out *out, int count);
+
 void preserve_python_values (struct objfile *objfile, htab_t copied_types);
 
 void gdbpy_load_auto_scripts_for_objfile (struct objfile *objfile);



More information about the Gdb-patches mailing list