This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[patch][python] 5 of 5 - Frame filter documentation changes
- From: Phil Muldoon <pmuldoon at redhat dot com>
- To: "gdb-patches at sourceware dot org" <gdb-patches at sourceware dot org>
- Date: Fri, 30 Nov 2012 14:31:59 +0000
- Subject: [patch][python] 5 of 5 - Frame filter documentation changes
This patch/email address documentation changes for Python Frame
Filters.
2012-11-30 Phil Muldoon <pmuldoon@redhat.com>
* gdb.texinfo (Backtrace): Add "raw" argument.
(Python API): Add Frame Filters API, Frame Wrapper API,
Writing a Frame Filter/Wrapper, Managing Management of Frame
Filters chapter entries.
(Frame Filters API): New Node.
(Frame Wrapper API): New Node.
(Writing a Frame Filter/Wrapper): New Node.
(Managing Frame Filters): New Node.
(Progspaces In Python): Add note about frame_filters attribute.
(Objfiles in Python): Ditto.
(GDB/MI Stack Manipulation): Add -enable-frame-filters command,
@anchors and --no-frame-filters option to -stack-list-variables,
-stack-list-frames, -stack-list-locals and -stack-list-arguments
commands.
--
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index afe3845..5a0215d 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6360,6 +6360,7 @@ line per frame, for many frames, starting with the currently executing
frame (frame zero), followed by its caller (frame one), and on up the
stack.
+@anchor{backtrace-command}
@table @code
@kindex backtrace
@kindex bt @r{(@code{backtrace})}
@@ -6385,6 +6386,17 @@ Similar, but print only the outermost @var{n} frames.
@itemx bt full -@var{n}
Print the values of the local variables also. @var{n} specifies the
number of frames to print, as described above.
+
+@item backtrace raw
+@itemx bt raw
+@itemx bt raw @var{n}
+@itemx bt raw -@var{n}
+@itemx bt raw full
+@itemx bt raw full @var{n}
+@itemx bt raw full -@var{n}
+Do not run Python frame filters on this backtrace. @xref{Frame
+Filters API}, for more information. This is only relevant when
+@value{GDBN} has been configured with @code{Python} support.
@end table
@kindex where
@@ -22738,6 +22750,10 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
* Selecting Pretty-Printers:: How GDB chooses a pretty-printer.
* Writing a Pretty-Printer:: Writing a Pretty-Printer.
* Type Printing API:: Pretty-printing types.
+* Frame Filters API:: Filtering and Wrapping Frames.
+* Frame Wrapper API:: Wrapping and Decorating Frames.
+* Writing a Frame Filter/Wrapper:: Writing a Frame Filter and Wrapper.
+* Managing Frame Filters:: Management of Frame Filters.
* Inferiors In Python:: Python representation of inferiors (processes)
* Events In Python:: Listening for events from @value{GDBN}.
* Threads In Python:: Accessing inferior threads from Python.
@@ -24095,6 +24111,759 @@ done then type printers would have to make use of the event system in
order to avoid holding information that could become stale as the
inferior changed.
+@node Frame Filters API
+@subsubsection Filtering and Wrapping Frames.
+@cindex Frame Filter/Wrappers API
+
+Frame filters are Python objects that manipulate the visibility of a
+frame or frames when a backtrace (@pxref{Backtrace}) is printed by
+@value{GDBN}.
+
+Only commands that print a backtrace, or, in the case of @sc{gdb/mi}
+commands (@pxref{GDB/MI}), those that return a collection of frames
+are affected. The commands that work with frame filters are:
+
+@code{backtrace} (@pxref{backtrace-command,, The backtrace command}),
+@code{-stack-list-frames}
+(@pxref{-stack-list-frames,, The -stack-list-frames command}),
+@code{-stack-list-variables} (@pxref{-stack-list-variables,, The
+-stack-list-variables command}), @code{-stack-list-arguments}
+@pxref{-stack-list-arguments,, The -stack-list-arguments command}) and
+@code{-stack-list-locals} (@pxref{-stack-list-locals,, The
+-stack-list-locals command}).
+
+A frame filter works by applying actions to an iterator that is passed
+to that frame filter as a parameter. Typically, frame filters utilize
+tools such as the Python's @code{itertools} module to modify the
+iterator. If the frame filter modifies the iterator, it returns that
+modified iterator, otherwise it returns the original iterator
+unmodified. A frame filter must not alter the underlying @value{GDBN}
+frame or frames, or attempt to alter the call-stack within
+@value{GDBN}. Frame filters may only work on the wrapping iterator.
+This preserves data integrity within @value{GDBN}.
+
+Frame filters are executed on a priority basis and care should be
+taken that some frame filters may have been executed before, and that
+some frame filters will be executed after. Each frame filter object
+takes a Python iterator, and returns a Python iterator. For further
+information on frame filters see, @ref{Writing a Frame
+Filter/Wrapper}.
+
+Frame filters have a mandatory interface which each frame filter must
+implement, defined here:
+
+@defun FrameFilter.filter (iterator)
+@value{GDBN} will call this method on a frame filter when it has
+reached the order in the priority list for that filter.
+
+For example, if there are four frame filters:
+
+@smallexample
+Name Priority
+
+Filter1 5
+Filter2 10
+Filter3 100
+Filter4 1
+@end smallexample
+
+The order that the frame filters will be called is:
+
+@smallexample
+Filter3 -> Filter2 -> Filter1 -> Filter4
+@end smallexample
+
+Note that the output (a Python iterator) from @code{Filter3} is passed
+to the input of @code{Filter2}, and so on.
+
+This @code{filter} method is passed a Python iterator. This iterator
+contains a sequence of frame wrappers that wrap each @code{gdb.Frame},
+or another frame wrapper that wraps a frame wrapper. The first filter
+that is executed in the sequence of frame filters will receive an
+iterator entirely comprised of @code{BaseFrameWrapper} objects.
+However, after each frame filter is executed, the previous frame
+filter may have wrapped some or all of the frame wrappers with their
+own frame wrapper. As Frame Wrappers must also conform to a mandatory
+interface, these wrappers can be assumed to act in a uniform manner
+(@pxref{Frame Wrapper API}).
+
+This method must return an object conforming to the Python iterator
+protocol. Each item in the iterator must be an object conforming to
+the frame wrapper interface. If a frame filter does not wish to
+perform any operations on this iterator, it should return that
+iterator untouched.
+
+This method is not optional. If it does not exist, @value{GDBN} will
+raise and print an error.
+@end defun
+
+@defvar FrameFilter.name
+The @code{name} attribute must be Python string which contains the
+name of the filter displayed by @value{GDBN} (@pxref{Managing Frame
+Filters}). This attribute may contain any combination of letters,
+numbers and spaces. Care should be taken to ensure that it is unique.
+This attribute is mandatory.
+@end defvar
+
+@defvar FrameFilter.enabled
+The @code{enabled} attribute must be Python boolean. This attribute
+indicates to @value{GDBN} whether the frame filter is enabled, and
+should be considered when frame filters are executed. If
+@code{enabled} is @code{True}, then the frame filter will be executed
+when any of the backtrace commands detailed earlier in this chapter
+are executed. If @code{enabled} is @code{False}, then the frame
+filter will not be executed. This attribute is mandatory.
+@end defvar
+
+@defvar FrameFilter.priority
+The @code{priority} attribute must be Python integer. This attribute
+controls the order of execution in relation to other frame filters.
+There is no imposed limits on the range of @code{priority} other than
+it must be a valid integer. The higher the @code{priority} attribute,
+the sooner the frame filter will be executed in relation to other
+frame filters. Although @code{priority} can be negative, it is
+recommended practice to assume zero is the lowest priority that a
+frame filter can be assigned. Frame filters that have the same
+priority are executed in unsorted order in that priority slot. This
+attribute is mandatory.
+@end defvar
+
+@node Frame Wrapper API
+@subsubsection Wrapping and Decorating Frames.
+@cindex Frame Wrapper API
+
+Frame wrappers are sister objects to frame filters (@pxref{Frame
+Filters API}). Frame wrappers are applied by a frame filter and can
+only be used in conjunction with frame filters.
+
+The purpose of a frame wrapper is to customize the printed content of
+each frame. Frame wrappers have a mandatory interface, defined below.
+A frame wrapper object works on a single frame, but a frame wrapper
+object can be applied to multiple frames.
+
+@value{GDBN} already contains a frame wrapper called
+@code{BaseFrameWrapper}. This contains substantial amounts of
+boilerplate code to print the content of frames. It is recommended
+that other frame wrappers inherit and extend this object, and only to
+override the methods needed. The Python code for
+@code{BaseFrameWrapper} can be found in
+@file{@var{data-directory}/python/gdb}
+
+@defun FrameWrapper.elided ()
+
+The @code{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.
+
+The @code{elide} function must return an iterator that conforms to the
+Python iterator protocol. This iterator must contains the frames that
+are being elided wrapped in a suitable frame wrapper. If there are no
+frames being elided in this frame wrapper, this method must return a
+Python @code{None}. Elided frames are indented from normal frames in
+a @code{CLI} backtrace, or in the case of @code{GDB/MI}, are placed in
+the @code{children} field of the eliding frame.
+
+It is the frame filter task to also filter out the elided frames from
+the source iterator. This will avoid the frame being printed twice.
+@end defun
+
+@defun FrameWrapper.function ()
+
+This method returns the name of the function in the frame that is to
+be printed.
+
+This method must return a Python string describing the function, or a
+Python @code{None}.
+
+If this function returns a Python @code{None}, @value{GDBN} will not
+print any data for this field.
+@end defun
+
+@defun FrameWrapper.address ()
+
+This method returns the address of the frame that is to be printed.
+
+This method must return a Python numeric integer type of sufficient
+size to describe the address of the frame, or a Python @code{None}.
+
+If this function returns a Python @code{None}, @value{GDBN} will not
+print any data for this field.
+@end defun
+
+@defun FrameWrapper.filename ()
+
+This method returns the filename associated with this frame.
+
+This method must return a Python string containing the filename, and
+optionally, the path to the filename of the frame, or a Python
+@code{None}.
+
+If this function returns a Python @code{None}, @value{GDBN} will not
+print any data for this field.
+@end defun
+
+
+@defun FrameWrapper.line ():
+
+This method returns the line number associated with the current
+position within the function addressed by this frame.
+
+This method must return a Python integer type, or a Python
+@code{None}.
+
+If this function returns a Python @code{None}, @value{GDBN} will not
+print any data for this field.
+@end defun
+
+@defun FrameWrapper.frame_args ()
+
+This method must return an iterator that conforms to the Python
+iterator protocol, or a Python @code{None}. This iterator must
+contain objects that implement two methods, described here.
+
+The object must implement an @code{argument} method which takes no
+parameters and must return a @code{gdb.Symbol} or a Python string. It
+must also implement a @code{value} method which takes no parameters
+and which must return a @code{gdb.Value}, a Python value, or
+@code{None}. If the @code{value} method returns a Python @code{None},
+and the @code{argument} method returns a @code{gdb.Symbol},
+@value{GDBN} will look-up and print the value of the @code{gdb.Symbol}
+automatically.
+
+A brief example:
+
+@smallexample
+class SymValueWrapper ():
+
+ def __init__(self, symbol, value):
+ self.sym = symbol
+ self.val = value
+
+ def value (self):
+ return self.val
+
+ def symbol (self):
+
+ return self.sym
+
+class SomeFrameWrapper ()
+...
+...
+ def frame_args (self):
+ fvars = []
+ fvars.append (SymValueWrapper (``foo'', 42))
+
+ return iter (fvars)
+@end smallexample
+
+Even if the @code{frame_args} method returns only a single object, it
+must be wrapped in an iterator.
+
+If this function returns a Python @code{None}, @value{GDBN} will not
+print arguments for this frame.
+@end defun
+
+@defun FrameWrapper.frame_locals ()
+
+This method must return an iterator that conforms to the Python
+iterator protocol, or a Python @code{None}. This iterator must
+contain objects that implement two methods, described here.
+
+The object must implement an @code{argument} method which takes no
+parameters and must return a @code{gdb.Symbol} or a Python string. It
+must also implement a @code{value} method which takes no parameters
+and which must return a @code{gdb.Value}, a Python value, or
+@code{None}. If the @code{value} method returns a Python @code{None},
+and the @code{argument} method returns a @code{gdb.Symbol},
+@value{GDBN} will look-up and print the value of the @code{gdb.Symbol}
+automatically.
+
+A brief example:
+
+@smallexample
+class SymValueWrapper ():
+
+ def __init__(self, symbol, value):
+ self.sym = symbol
+ self.val = value
+
+ def value (self):
+ return self.val
+
+ def symbol (self):
+
+ return self.sym
+
+class SomeFrameWrapper ()
+...
+...
+ def frame_locals (self):
+ fvars = []
+ fvars.append (SymValueWrapper (``foo'', 42))
+
+ return iter (fvars)
+@end smallexample
+
+Even if the @code{frame_locals} method returns only a single object, it
+must be wrapped in an iterator.
+
+If this function returns a Python @code{None}, @value{GDBN} will not
+print locals for this frame.
+@end defun
+
+@defun FrameWrapper.frame ():
+
+This method must return the underlying @code{gdb.Frame} that this
+frame wrapper is wrapping. @value{GDBN} requires the underlying frame
+for internal frame information to determine how to print certain
+values in frame printing
+@end defun
+
+@node Writing a Frame Filter/Wrapper
+@subsubsection Writing a Frame Filter and Wrapper
+@cindex Writing a Frame Filter/Wrapper
+
+The Python dictionary @code{gdb.frame_filters} contains key/object
+pairings that compromise a frame filter. These frame filters must
+register with the dictionary directly. Frame filters in this
+dictionary are called @code{global} frame filters, and they are
+available when debugging all inferiors. In addition to the
+@code{global} dictionary, there are other dictionaries that are loaded
+with different inferiors via auto-loading (@pxref{Python
+Auto-loading}). The two other areas where frame filter dictionaries
+can be found are: @code{gdb.Progspace} which contains a
+@code{frame_filters} dictionary attribute, and each @code{gdb.Objfile}
+object which also contain a @code{frame_filters} dictionary attribute.
+
+Each frame filter object in these dictionaries is passed a single
+Python iterator argument and should return a Python iterator. Each
+frame filter object must conform to the frame filter interface
+definition (@pxref{Frame Filters API}). The iterator returned by the
+frame filter must contain only a collection of frame wrappers
+(@pxref{Frame Wrapper API}), conforming to the frame wrapper interface
+definition.
+
+When a command is executed from @value{GDBN} that is compatible with
+frame filters, @value{GDBN} combines the @code{global},
+@code{gdb.Progspace} and all @code{gdb.ObjFile} dictionaries
+currently loaded. All of the @code{gdb.Objfile} dictionaries are
+combined as several frames and thus object files might be in use.
+@value{GDBN} then prunes any frame filter where the @code{enabled}
+attribute is set to @code{False}. This pruned list is then sorted
+according to the @code{priority} attribute in each filter. Once the
+dictionaries are combined, sorted and pruned, @value{GDBN} then wraps
+all frames in the call-stack with a @code{BaseFrameWrapper} object,
+and calls each filter in priority order. The input to the first frame
+filter will be an initial iterator wrapping a collection of
+@code{BaseFrameWrapper} objects. The output from the previous filter
+will always be the input to the next filter, and so on.
+
+@subsubheading Implementing a frame filter
+
+There are three basic elements that a frame filter must implement: it
+must correctly implement the documented interface (@pxref{Frame
+Filters API}), it must register itself with @value{GDBN}, and finally,
+it must decide if it is to work on the data provided by
+@value{GDBN}. In all cases, whether it works on the iterator or not,
+each frame filter must return an iterator. A bare-bones frame filter
+follows the pattern in the following example.
+
+@smallexample
+import gdb
+
+class FrameFilter ():
+
+ def __init__ (self):
+ self.name = "Foo"
+ self.priority = 100
+ self.enabled = True
+ gdb.frame_filters [self.name] = self
+
+ def filter (self, frame_iter):
+ return frame_iter
+@end smallexample
+
+The frame filter in the example above implements the three
+requirements for all frame filters. It implements the API, self
+registers, and makes a decision on the iterator (in this case, it just
+returns the iterator untouched).
+
+The first step is attribute creation and assignment:
+
+@smallexample
+ self.name = "Foo"
+ self.priority = 100
+ self.enabled = True
+@end smallexample
+
+The second step is registering the frame filter with the dictionary or
+dictionaries that the frame filter has interest in:
+
+@smallexample
+ gdb.frame_filters [self.name] = self
+@end smallexample
+
+As noted earlier, @code{gdb.frame_filters} is a dictionary that is
+initialized in the @code{gdb} module when @value{GDBN} starts. In
+this example, the frame filter only wishes to register with the
+@code{global} dictionary.
+
+@value{GDBN} takes a hands-off approach to frame filter registration,
+therefore it is the frame filter's responsibility to ensure
+registration has occurred, and that any exceptions are handled
+appropriately. In particular, you may wish to handle exceptions
+relating to Python dictionary key uniqueness. It is mandatory that
+the dictionary key is the same as frame filter's @code{name}
+attribute. When a user manages frame filters (@pxref{Managing Frame
+Filters}), the names @value{GDBN} will display are those contained in
+the @code{name} attribute.
+
+The final step of this example is the implementation of the
+@code{filter} method:
+
+@smallexample
+ def filter (self, frame_iter):
+ return frame_iter
+@end smallexample
+
+Note that the @code{filter} method must take an iterator, and also
+must return an iterator. In this bare-bones example, the frame filter
+is not very useful as it just returns the iterator untouched. However
+this is a valid operation for frame filters that have the
+@code{enabled} attribute set, but decide not to operate on any frames.
+
+In the next example, the frame filter operates on all frames and
+utilizes a frame wrapper to perform some work on the frames.
+@xref{Frame Wrapper API}, for further information on the frame wrapper
+interface.
+
+This example works on inlined frames. It highlights frames which are
+inlined by adding the function in which they are inlined into. By
+applying a frame wrapper to all frames with the Python @code{itertools
+imap} method, the example defers actions to the frame wrapper. Frame
+wrappers are only processed when @value{GDBN} prints the backtrace.
+
+This introduces a new decision making topic: whether to perform
+decision making operations at the filtering step, or at the printing
+step. In this example's approach, it does not perform any filtering
+decisions at the filtering step beyond mapping a frame wrapper to each
+frame. This allows the actual decision making to be performed when
+each frame is printed. This is an important consideration, and well
+worth reflecting upon when designing a frame filter. An issue that
+frame filters should avoid is unwinding the stack if possible. To
+search every frame to determine if it is inlined ahead of time may be
+too expensive at the filtering step. The frame filter cannot know how
+many frames it has to iterate over, and it would have to iterate
+through them all. This ends up duplicating effort as @value{GDBN}
+performs this iteration when it prints the frames.
+
+In this example decision making can be deferred to the printing step.
+As each frame is printed, the frame wrapper can examine each frame in
+turn when @value{GDBN} iterates. From a performance viewpoint, this
+is the most appropriate decision to make. A backtrace from large or
+complex programs can constitute many thousands of frames. Also, if
+there are many frame filters unwinding the stack during filtering, it
+can substantially delay the printing of the backtrace which will
+result in large memory usage, and a poor user experience.
+
+@smallexample
+class InlineFilter ():
+
+ def __init__ (self):
+ self.name = "Inlined Frame Class"
+ self.priority = 100
+ self.enabled = True
+ gdb.frame_filters [self.name] = self
+
+ def filter (self, frame_iter):
+ frame_iter = itertools.imap (InlinedFrameWrapper,
+ frame_iter)
+ return frame_iter
+@end smallexample
+
+This frame filter is somewhat similar to the earlier example, except
+that the @code{filter} method applies a frame wrapper object called
+@code{InlinedFrameWrapper} to each element in the iterator. The
+@code{imap} Python method is light-weight. It does not proactively
+iterate over the iterator, but rather creates a new iterator which
+wraps the existing one.
+
+Below is the frame wrapper for this example.
+
+@smallexample
+class InlinedFrameWrapper (BaseFrameWrapper):
+
+ def __init__(self, fobj):
+ super(InlinedFrameWrapper, self).__init__(fobj)
+ self.fobj = fobj
+
+ def function (self):
+ frame = self.inferior_frame()
+ name = str(frame.name())
+ function = str(frame.function())
+
+ if frame.type() == gdb.INLINE_FRAME:
+ name = name + " [inlined from "+ function +"]"
+
+ return name
+@end smallexample
+
+This frame wrapper only defines and overrides the @code{function}
+method. It lets the supplied @code{BaseFrameWrapper}, which is
+shipped with @value{GDBN}, perform the other work associated with
+printing this frame.
+
+The combination of these two objects create this output from a
+backtrace:
+
+@smallexample
+#0 0x004004e0 in bar () at inline.c:11
+#1 0x00400566 in max [inlined from main] (b=6, a=12) at inline.c:21
+#2 0x00400566 in main () at inline.c:31
+@end smallexample
+
+So in the case of this example, a frame wrapper is applied to all
+frames, regardless of whether they may be inlined or not. As
+@value{GDBN} iterates over the iterator produced by the frame filters,
+@value{GDBN} executes each frame wrapper which then makes a decision
+on what to print in the @code{function} callback. Using a strategy
+like this is a way to defer decisions on the frame content to printing
+time.
+
+@subheading Eliding Frames
+
+It might be that the above example is not desirable for representing
+inlined frames, and a hierarchical approach may be preferred. If we
+want to hierarchically represent frames, the @code{elided} frame
+wrapper interface might be preferable.
+
+This example approaches the issue with the @code{elided} method. This
+example is quite long, but very simplistic. It is out-of-scope for
+this section to write a complete example that comprehensively covers
+all approaches of finding and printing inlined frames. However, this
+example illustrates the approach an author might use.
+
+This example comprises of three sections.
+
+@smallexample
+class InlineFrameFilter ():
+
+ def __init__ (self):
+ self.name = "Inlined Frame Class"
+ self.priority = 100
+ self.enabled = True
+ gdb.frame_filters [self.name] = self
+
+ def filter (self, frame_iter):
+ return ElidingInlineIterator (frame_iter)
+@end smallexample
+
+This frame filter is very similar to the other examples. The only
+difference is this frame filter is wrapping the iterator provided to
+it (@code{frame_iter}) with a custom iterator called
+@code{ElidingInlineIterator}. This again defers actions to when
+@value{GDBN} prints the backtrace, as the iterator is not traversed
+until printing.
+
+The iterator for this example is as follows. It is in this section of
+the example where decisions are made on the content of the backtrace.
+
+@smallexample
+class ElidingInlineIterator:
+ def __init__(self, ii):
+ self.input_iterator = ii
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ frame = next(self.input_iterator)
+ if frame.inferior_frame().type() != gdb.INLINE_FRAME:
+ return frame
+
+ eliding_frame = next(self.input_iterator)
+ return ElidingFrameWrapper(eliding_frame, [frame])
+@end smallexample
+
+This iterator implements the Python iterator protocol. When the
+@code{next} function is called (when @value{GDBN} prints each frame),
+the iterator checks if this frame wrapper, @code{frame}, is wrapping
+an inlined frame. If it is not, it returns the existing frame wrapper
+untouched. If it is wrapping an inlined frame, it assumes that the
+inlined frame was contained within the next oldest frame,
+@code{eliding_frame}, which it fetches. It then creates and returns a
+frame wrapper, @code{ElidingFrameWrapper}, which contains both the
+elided frame, and the eliding frame.
+
+@smallexample
+class ElidingInlineWrapper(BaseFrameWrapper):
+
+ def __init__(self, frame, elided_frames):
+ super(ElidingInlineWrapper, self).__init__(frame)
+ self.frame = frame
+ self.elided_frames = elided_frames
+
+ def elided(self):
+ return iter(self.elided_frames)
+@end smallexample
+
+This frame wrapper overrides one function and returns the inlined
+frame in the @code{elided} method. As before it lets
+@code{BaseFrameWrapper} do the rest of the work involved in printing
+this frame. This produces the following output.
+
+@smallexample
+#0 0x004004e0 in bar () at inline.c:11
+#2 0x00400529 in main () at inline.c:25
+ #1 0x00400529 in max (b=6, a=12) at inline.c:15
+@end smallexample
+
+In that output, @code{max} which has been inlined into @code{main} is
+printed hierarchically. Another approach would be to combine the
+@code{function} method, and the @code{elided} method to both print a
+marker in the inlined frame, and also show the hierarchical
+relationship.
+
+@node Managing Frame Filters
+@subsubsection Management of Frame Filters.
+@cindex Managing Frame Filters
+
+There are several commands available within @value{GDBN} to manage
+frame filters, detailed here.
+
+@table @code
+@kindex info frame-filter
+@item info frame-filter
+Print a list of installed frame filters from all dictionaries, showing
+their name, priority and enabled status.
+
+@kindex disable frame-filter
+@item disable frame-filter @var{filter-dictionary} @var{filter-name}
+Disable a frame filter in the dictionary matching
+@var{filter-dictionary} and @var{filter-name}.
+@var{filter-dictionary} may be @code{global}, @code{progspace} or the
+name of the object file where the frame filter dictionary resides.
+@var{filter-name} is the name of the frame filter. A disabled
+frame-filter is not deleted, it may be enabled again later.
+
+@kindex enable frame-filter
+@item enable frame-filter @var{filter-dictionary} @var{filter-name}
+Enable a frame filter in the dictionary matching
+@var{filter-dictionary} and @var{filter-name}.
+@var{filter-dictionary} may be @code{global}, @code{progspace} or the
+name of the object file where the frame filter dictionary resides.
+@var{filter-name} is the name of the frame filter.
+
+Example:
+
+@smallexample
+(gdb) info frame-filter
+
+global frame-filters:
+ Priority Enabled Name
+ ======== ======= ====
+ 1000 No Capital Primary Function Filter
+ 100 Yes Reverse
+progspace /build/test frame-filters:
+ Priority Enabled Name
+ ======== ======= ====
+ 100 Yes Progspace Filter 1
+objfile /build/test frame-filters:
+ Priority Enabled Name
+ ======== ======= ====
+ 999 Yes Build Test Program Filter
+
+(gdb) disable frame-filter ``/build/test'' ``Build Test Program Filter''
+(gdb) info frame-filter
+
+global frame-filters:
+ Priority Enabled Name
+ ======== ======= ====
+ 1000 No Capital Primary Function Filter
+ 100 Yes Reverse
+progspace /build/test frame-filters:
+ Priority Enabled Name
+ ======== ======= ====
+ 100 Yes Progspace Filter 1
+objfile /build/test frame-filters:
+ Priority Enabled Name
+ ======== ======= ====
+ 999 No Build Test Program Filter
+
+(gdb) enable frame-filter global ``Capital Primary Function Filter''
+(gdb) info frame-filter
+
+global frame-filters:
+ Priority Enabled Name
+ ======== ======= ====
+ 1000 Yes Capital Primary Function Filter
+ 100 Yes Reverse
+progspace /build/test frame-filters:
+ Priority Enabled Name
+ ======== ======= ====
+ 100 Yes Progspace Filter 1
+objfile /build/test frame-filters:
+ Priority Enabled Name
+ ======== ======= ====
+ 999 No Build Test Program Filter
+
+@end smallexample
+
+@kindex set python frame-filter priority
+@item set python frame-filter priority @var{filter-dictionary} @var{filter-name} @var{priority}
+Set the @var{priority} of a frame filter in the dictionary matching
+@var{filter-dictionary}, and the frame filter name matching
+@var{filter-name}. @var{filter-dictionary} may be @code{global},
+@code{progspace} or the name of the object file where the frame filter
+dictionary resides. @var{priority} is an integer.
+
+@kindex show python frame-filter priority
+@item show python frame-filter priority @var{filter-dictionary} @var{filter-name}
+Show the @var{priority} of a frame filter in the dictionary matching
+@var{filter-dictionary}, and the frame filter name matching
+@var{filter-name}. @var{filter-dictionary} may be @code{global},
+@code{progspace} or the name of the object file where the frame filter
+dictionary resides.
+
+Example:
+
+@smallexample
+(gdb) info frame-filter
+
+global frame-filters:
+ Priority Enabled Name
+ ======== ======= ====
+ 1000 No Capital Primary Function Filter
+ 100 Yes Reverse
+progspace /build/test frame-filters:
+ Priority Enabled Name
+ ======== ======= ====
+ 100 Yes Progspace Filter 1
+objfile /build/test frame-filters:
+ Priority Enabled Name
+ ======== ======= ====
+ 999 Yes Build Test Program Filter
+
+(gdb) set python frame-filter priority global ``Reverse'' 50
+(gdb) info frame-filter
+
+global frame-filters:
+ Priority Enabled Name
+ ======== ======= ====
+ 1000 No Capital Primary Function Filter
+ 50 Yes Reverse
+progspace /build/test frame-filters:
+ Priority Enabled Name
+ ======== ======= ====
+ 100 Yes Progspace Filter 1
+objfile /build/test frame-filters:
+ Priority Enabled Name
+ ======== ======= ====
+ 999 No Build Test Program Filter
+@end smallexample
+@end table
+
@node Inferiors In Python
@subsubsection Inferiors In Python
@cindex inferiors in Python
@@ -24944,6 +25713,11 @@ The @code{type_printers} attribute is a list of type printer objects.
@xref{Type Printing API}, for more information.
@end defvar
+@defvar Progspace.frame_filters
+The @code{frame_filters} attribute is a dictionary of frame filter
+objects. @xref{Frame Filters API}, for more information.
+@end defvar
+
@node Objfiles In Python
@subsubsection Objfiles In Python
@@ -24994,6 +25768,11 @@ The @code{type_printers} attribute is a list of type printer objects.
@xref{Type Printing API}, for more information.
@end defvar
+@defvar Objfile.frame_filters
+The @code{frame_filters} attribute is a dictionary of frame filter
+objects. @xref{Frame Filters API}, for more information.
+@end defvar
+
A @code{gdb.Objfile} object has the following methods:
@defun Objfile.is_valid ()
@@ -25975,7 +26754,7 @@ No my-foo-pretty-printers.py
When reading an auto-loaded file, @value{GDBN} sets the
@dfn{current objfile}. This is available via the @code{gdb.current_objfile}
function (@pxref{Objfiles In Python}). This can be useful for
-registering objfile-specific pretty-printers.
+registering objfile-specific pretty-printers and frame-filters.
@menu
* objfile-gdb.py file:: The @file{@var{objfile}-gdb.py} file
@@ -29659,6 +30438,25 @@ Is this going away????
@node GDB/MI Stack Manipulation
@section @sc{gdb/mi} Stack Manipulation Commands
+@subheading The @code{-enable-frame-filters} Command
+@findex -enable-frame-filters
+
+@smallexample
+-enable-frame-filters
+@end smallexample
+
+@value{GDBN} allows Python-based frame filters to affect the output of
+the MI commands relating to stack traces. As there is no way to
+implement this in a fully backward-compatible way, a front end must
+request that this functionality be enabled.
+
+Once enabled, this feature cannot be disabled.
+
+Note that if Python support has not been compiled into @value{GDBN},
+this command will still succeed (and do nothing).
+
+This feature is currently (as of @value{GDBN} 7.6) experimental, and
+may work differently in future versions of @value{GDBN}.
@subheading The @code{-stack-info-frame} Command
@findex -stack-info-frame
@@ -29726,13 +30524,14 @@ For a stack with frame levels 0 through 11:
(gdb)
@end smallexample
+@anchor{-stack-list-arguments}
@subheading The @code{-stack-list-arguments} Command
@findex -stack-list-arguments
@subsubheading Synopsis
@smallexample
- -stack-list-arguments @var{print-values}
+ -stack-list-arguments [ --no-frame-filters ] @var{print-values}
[ @var{low-frame} @var{high-frame} ]
@end smallexample
@@ -29749,7 +30548,9 @@ If @var{print-values} is 0 or @code{--no-values}, print only the names of
the variables; if it is 1 or @code{--all-values}, print also their
values; and if it is 2 or @code{--simple-values}, print the name,
type and value for simple data types, and the name and type for arrays,
-structures and unions.
+structures and unions. If the option @code{--no-frame-filters} is
+supplied, then Python frame filters will not be executed.
+
Use of this command to obtain arguments in a single frame is
deprecated in favor of the @samp{-stack-list-variables} command.
@@ -29820,13 +30621,14 @@ args=[@{name="intarg",value="2"@},
@c @subheading -stack-list-exception-handlers
+@anchor{-stack-list-frames}
@subheading The @code{-stack-list-frames} Command
@findex -stack-list-frames
@subsubheading Synopsis
@smallexample
- -stack-list-frames [ @var{low-frame} @var{high-frame} ]
+ -stack-list-frames [ --no-frame-filters @var{low-frame} @var{high-frame} ]
@end smallexample
List the frames currently on the stack. For each frame it displays the
@@ -29856,7 +30658,9 @@ levels are between the two arguments (inclusive). If the two arguments
are equal, it shows the single frame at the corresponding level. It is
an error if @var{low-frame} is larger than the actual number of
frames. On the other hand, @var{high-frame} may be larger than the
-actual number of frames, in which case only existing frames will be returned.
+actual number of frames, in which case only existing frames will be
+returned. If the option @code{--no-frame-filters} is supplied, then
+Python frame filters will not be executed.
@subsubheading @value{GDBN} Command
@@ -29926,11 +30730,12 @@ Show a single frame:
@subheading The @code{-stack-list-locals} Command
@findex -stack-list-locals
+@anchor{-stack-list-locals}
@subsubheading Synopsis
@smallexample
- -stack-list-locals @var{print-values}
+ -stack-list-locals [ --no-frame-filters ] @var{print-values}
@end smallexample
Display the local variable names for the selected frame. If
@@ -29941,7 +30746,8 @@ type and value for simple data types, and the name and type for arrays,
structures and unions. In this last case, a frontend can immediately
display the value of simple data types and create variable objects for
other data types when the user wishes to explore their values in
-more detail.
+more detail. If the option @code{--no-frame-filters} is supplied, then
+Python frame filters will not be executed.
This command is deprecated in favor of the
@samp{-stack-list-variables} command.
@@ -29966,13 +30772,14 @@ This command is deprecated in favor of the
(gdb)
@end smallexample
+@anchor{-stack-list-variables}
@subheading The @code{-stack-list-variables} Command
@findex -stack-list-variables
@subsubheading Synopsis
@smallexample
- -stack-list-variables @var{print-values}
+ -stack-list-variables [ --no-frame-filters ] @var{print-values}
@end smallexample
Display the names of local variables and function arguments for the selected frame. If
@@ -29980,7 +30787,8 @@ Display the names of local variables and function arguments for the selected fra
the variables; if it is 1 or @code{--all-values}, print also their
values; and if it is 2 or @code{--simple-values}, print the name,
type and value for simple data types, and the name and type for arrays,
-structures and unions.
+structures and unions. If the option @code{--no-frame-filters} is
+supplied, then Python frame filters will not be executed.
@subsubheading Example