2013-05-10 Phil Muldoon <pmuldoon@redhat.com>

* stack.c (backtrace_command_1): Add "no-filters", and Python frame
	filter logic.
	(backtrace_command): Add "no-filters" option parsing.
	(_initialize_stack): Alter help to reflect "no-filters" option.
	* Makefile.in (SUBDIR_PYTHON_OBS): Add py-framefilter.o
	(SUBDIR_PYTHON_SRCS): Add py-framefilter.c
	(py-frame.o): Add target
	* data-directory/Makefile.in (PYTHON_DIR): Add Python frame
	filter files.
	* 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/frames.py: New file.
	* python/lib/gdb/__init__.py: Initialize global frame_filters
	dictionary
	* python/lib/gdb/FrameDecorator.py: New file.
	* python/lib/gdb/FrameIterator.py: New file.
	* mi/mi-cmds.c (mi_cmds): Add frame filters command.
	* mi/mi-cmds.h: Declare.
	* mi/mi-cmd-stack.c (mi_cmd_stack_list_frames): Add
	--no-frame-filter logic, and Python frame filter logic.
	(stack_enable_frame_filters): New function.
	(parse_no_frame_option): Ditto.
	(mi_cmd_stack_list_frames): Add --no-frame-filter and Python frame
	filter logic.
	(mi_cmd_stack_list_locals): Ditto.
	(mi_cmd_stack_list_args): Ditto.
	(mi_cmd_stack_list_variables): Ditto.
	* NEWS: Add frame filter note.

2013-05-10  Phil Muldoon  <pmuldoon@redhat.com>

	* gdb.python/py-framefilter.py: New File.
	* gdb.python/py-framefilter-mi.exp: Ditto.
	* gdb.python/py-framefilter.c: Ditto.
	* gdb.python/py-framefilter-mi.exp: Ditto.
	* gdb.python/py-framefilter-mi.c: Ditto,
	* gdb.python/py-framefilter-gdb.py.in: Ditto.

2013-05-10 Phil Muldoon  <pmuldoon@redhat.com>

	* gdb.texinfo (Backtrace): Add "no-filter" 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): 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.
This commit is contained in:
Phil Muldoon 2013-05-10 10:26:03 +00:00
parent 3ecb733811
commit 1e611234ee
29 changed files with 4846 additions and 88 deletions

View File

@ -1,3 +1,52 @@
2013-05-10 Phil Muldoon <pmuldoon@redhat.com>
* stack.c (backtrace_command_1): Add "no-filters", and Python frame
filter logic.
(backtrace_command): Add "no-filters" option parsing.
(_initialize_stack): Alter help to reflect "no-filters" option.
* Makefile.in (SUBDIR_PYTHON_OBS): Add py-framefilter.o
(SUBDIR_PYTHON_SRCS): Add py-framefilter.c
(py-frame.o): Add target
* data-directory/Makefile.in (PYTHON_DIR): Add Python frame
filter files.
* 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/frames.py: New file.
* python/lib/gdb/__init__.py: Initialize global frame_filters
dictionary
* python/lib/gdb/FrameDecorator.py: New file.
* python/lib/gdb/FrameIterator.py: New file.
* mi/mi-cmds.c (mi_cmds): Add frame filters command.
* mi/mi-cmds.h: Declare.
* mi/mi-cmd-stack.c (mi_cmd_stack_list_frames): Add
--no-frame-filter logic, and Python frame filter logic.
(stack_enable_frame_filters): New function.
(parse_no_frame_option): Ditto.
(mi_cmd_stack_list_frames): Add --no-frame-filter and Python frame
filter logic.
(mi_cmd_stack_list_locals): Ditto.
(mi_cmd_stack_list_args): Ditto.
(mi_cmd_stack_list_variables): Ditto.
* NEWS: Add frame filter note.
2013-05-09 Doug Evans <dje@google.com>
* symfile.c (syms_from_objfile_1): Delete args offsets, num_offsets.

View File

@ -288,6 +288,7 @@ SUBDIR_PYTHON_OBS = \
py-exitedevent.o \
py-finishbreakpoint.o \
py-frame.o \
py-framefilter.o \
py-function.o \
py-gdb-readline.o \
py-inferior.o \
@ -322,6 +323,7 @@ SUBDIR_PYTHON_SRCS = \
python/py-exitedevent.c \
python/py-finishbreakpoint.c \
python/py-frame.c \
python/py-framefilter.c \
python/py-function.c \
python/py-gdb-readline.c \
python/py-inferior.c \
@ -2144,6 +2146,10 @@ py-frame.o: $(srcdir)/python/py-frame.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-frame.c
$(POSTCOMPILE)
py-framefilter.o: $(srcdir)/python/py-framefilter.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-framefilter.c
$(POSTCOMPILE)
py-function.o: $(srcdir)/python/py-function.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-function.c
$(POSTCOMPILE)

View File

@ -3,6 +3,10 @@
*** Changes since GDB 7.6
* Python scripting
** Frame filters and frame decorators have been added.
* New targets
Nios II ELF nios2*-*-elf

View File

@ -53,10 +53,14 @@ PYTHON_DIR = python
PYTHON_INSTALL_DIR = $(DESTDIR)$(GDB_DATADIR)/$(PYTHON_DIR)
PYTHON_FILES = \
gdb/__init__.py \
gdb/frames.py \
gdb/FrameIterator.py \
gdb/FrameDecorator.py \
gdb/types.py \
gdb/printing.py \
gdb/prompt.py \
gdb/command/__init__.py \
gdb/command/frame_filters.py \
gdb/command/type_printers.py \
gdb/command/pretty_printers.py \
gdb/command/prompt.py \

View File

@ -1,3 +1,20 @@
2013-05-10 Phil Muldoon <pmuldoon@redhat.com>
* gdb.texinfo (Backtrace): Add "no-filter" 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): 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.
2013-05-08 Joel Brobecker <brobecker@adacore.com>
* gdbint.texinfo (Native Debugging): Add "AIX Shared Library

View File

@ -6465,6 +6465,7 @@ currently executing frame and describes it briefly, similar to the
@menu
* Frames:: Stack frames
* Backtrace:: Backtraces
* Frame Filter Management:: Managing frame filters
* Selection:: Selecting a frame
* Frame Info:: Information on a frame
@ -6552,6 +6553,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})}
@ -6577,6 +6579,19 @@ 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 no-filters
@itemx bt no-filters
@itemx bt no-filters @var{n}
@itemx bt no-filters -@var{n}
@itemx bt no-filters full
@itemx bt no-filters full @var{n}
@itemx bt no-filters full -@var{n}
Do not run Python frame filters on this backtrace. @xref{Frame
Filter API}, for more information. Additionally use @ref{disable
frame-filter all} to turn off all frame filters. This is only
relevant when @value{GDBN} has been configured with @code{Python}
support.
@end table
@kindex where
@ -6727,6 +6742,149 @@ Display an absolute filename.
Show the current way to display filenames.
@end table
@node Frame Filter Management
@section Management of Frame Filters.
@cindex managing frame filters
Frame filters are Python based utilities to manage and decorate the
output of frames. @xref{Frame Filter API}, for further information.
Managing frame filters is performed by several commands available
within @value{GDBN}, 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
@anchor{disable frame-filter all}
@item disable frame-filter @var{filter-dictionary} @var{filter-name}
Disable a frame filter in the dictionary matching
@var{filter-dictionary}, or @code{all}, and @var{filter-name}.
@var{filter-dictionary} may be @code{all}, @code{global},
@code{progspace} or the name of the object file where the frame filter
dictionary resides. When @code{all} is specified, all frame filters
across all dictionaries are disabled. @var{filter-name} is the name
of the frame filter and is used when @code{all} is not the option for
@var{filter-dictionary}. 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}, or @code{all}, and @var{filter-name}.
@var{filter-dictionary} may be @code{all}, @code{global},
@code{progspace} or the name of the object file where the frame filter
dictionary resides. When @code{all} is specified, all frame filters across
all dictionaries are enabled. @var{filter-name} is the name of the frame
filter and is used when @code{all} is not the option for
@var{filter-dictionary}.
Example:
@smallexample
(gdb) info frame-filter
global frame-filters:
Priority Enabled Name
1000 No PrimaryFunctionFilter
100 Yes Reverse
progspace /build/test frame-filters:
Priority Enabled Name
100 Yes ProgspaceFilter
objfile /build/test frame-filters:
Priority Enabled Name
999 Yes BuildProgra Filter
(gdb) disable frame-filter /build/test BuildProgramFilter
(gdb) info frame-filter
global frame-filters:
Priority Enabled Name
1000 No PrimaryFunctionFilter
100 Yes Reverse
progspace /build/test frame-filters:
Priority Enabled Name
100 Yes ProgspaceFilter
objfile /build/test frame-filters:
Priority Enabled Name
999 No BuildProgramFilter
(gdb) enable frame-filter global PrimaryFunctionFilter
(gdb) info frame-filter
global frame-filters:
Priority Enabled Name
1000 Yes PrimaryFunctionFilter
100 Yes Reverse
progspace /build/test frame-filters:
Priority Enabled Name
100 Yes ProgspaceFilter
objfile /build/test frame-filters:
Priority Enabled Name
999 No BuildProgramFilter
@end smallexample
@kindex set frame-filter priority
@item set 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 frame-filter priority
@item show 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 Yes PrimaryFunctionFilter
100 Yes Reverse
progspace /build/test frame-filters:
Priority Enabled Name
100 Yes ProgspaceFilter
objfile /build/test frame-filters:
Priority Enabled Name
999 No BuildProgramFilter
(gdb) set frame-filter priority global Reverse 50
(gdb) info frame-filter
global frame-filters:
Priority Enabled Name
1000 Yes PrimaryFunctionFilter
50 Yes Reverse
progspace /build/test frame-filters:
Priority Enabled Name
100 Yes ProgspaceFilter
objfile /build/test frame-filters:
Priority Enabled Name
999 No BuildProgramFilter
@end smallexample
@end table
@node Selection
@section Selecting a Frame
@ -23026,6 +23184,9 @@ optional arguments while skipping others. Example:
* Selecting Pretty-Printers:: How GDB chooses a pretty-printer.
* Writing a Pretty-Printer:: Writing a Pretty-Printer.
* Type Printing API:: Pretty-printing types.
* Frame Filter API:: Filtering Frames.
* Frame Decorator API:: Decorating Frames.
* Writing a Frame Filter:: Writing a Frame Filter.
* 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.
@ -24405,6 +24566,636 @@ 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 Filter API
@subsubsection Filtering Frames.
@cindex frame filters 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 taking an iterator as an argument, applying
actions to the contents of that iterator, and returning another
iterator (or, possibly, the same iterator it was provided in the case
where the filter does not perform any operations). Typically, frame
filters utilize tools such as the Python's @code{itertools} module to
work with and create new iterators from the source iterator.
Regardless of how a filter chooses to apply actions, it must not alter
the underlying @value{GDBN} frame or frames, or attempt to alter the
call-stack within @value{GDBN}. 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.
An important consideration when designing frame filters, and well
worth reflecting upon, is that frame filters should avoid unwinding
the call stack if possible. Some stacks can run very deep, into the
tens of thousands in some cases. To search every frame when a frame
filter executes may be too expensive at that step. The frame filter
cannot know how many frames it has to iterate over, and it may have to
iterate through them all. This ends up duplicating effort as
@value{GDBN} performs this iteration when it prints the frames. If
the filter can defer unwinding frames until frame decorators are
executed, after the last filter has executed, it should. @xref{Frame
Decorator API}, for more information on decorators. Also, there are
examples for both frame decorators and filters in later chapters.
@xref{Writing a Frame Filter}, for more information.
The Python dictionary @code{gdb.frame_filters} contains key/object
pairings that comprise a frame filter. Frame filters in this
dictionary are called @code{global} frame filters, and they are
available when debugging all inferiors. These frame filters must
register with the dictionary directly. 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 contains a @code{frame_filters} dictionary
attribute.
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 several object files, might be in use.
@value{GDBN} then prunes any frame filter whose @code{enabled}
attribute is @code{False}. This pruned list is then sorted according
to the @code{priority} attribute in each filter.
Once the dictionaries are combined, pruned and sorted, @value{GDBN}
creates an iterator which wraps each frame in the call stack in a
@code{FrameDecorator} object, and calls each filter in order. The
output from the previous filter will always be the input to the next
filter, and so on.
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 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 decorators that wrap each
@code{gdb.Frame}, or a frame decorator that wraps another frame
decorator. The first filter that is executed in the sequence of frame
filters will receive an iterator entirely comprised of default
@code{FrameDecorator} objects. However, after each frame filter is
executed, the previous frame filter may have wrapped some or all of
the frame decorators with their own frame decorator. As frame
decorators must also conform to a mandatory interface, these
decorators can be assumed to act in a uniform manner (@pxref{Frame
Decorator 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 decorator 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{Frame Filter
Management}). This attribute may contain any combination of letters
or numbers. 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 are 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 Decorator API
@subsubsection Decorating Frames.
@cindex frame decorator api
Frame decorators are sister objects to frame filters (@pxref{Frame
Filter API}). Frame decorators are applied by a frame filter and can
only be used in conjunction with frame filters.
The purpose of a frame decorator is to customize the printed content
of each @code{gdb.Frame} in commands where frame filters are executed.
This concept is called decorating a frame. Frame decorators decorate
a @code{gdb.Frame} with Python code contained within each API call.
This separates the actual data contained in a @code{gdb.Frame} from
the decorated data produced by a frame decorator. This abstraction is
necessary to maintain integrity of the data contained in each
@code{gdb.Frame}.
Frame decorators have a mandatory interface, defined below.
@value{GDBN} already contains a frame decorator called
@code{FrameDecorator}. This contains substantial amounts of
boilerplate code to decorate the content of a @code{gdb.Frame}. It is
recommended that other frame decorators inherit and extend this
object, and only to override the methods needed.
@defun FrameDecorator.elided (self)
The @code{elided} method groups frames together in a hierarchical
system. An example would be an interpreter, where multiple low-level
frames make up a single call in the interpreted language. In this
example, the frame filter would elide the low-level frames and present
a single high-level frame, representing the call in the interpreted
language, to the user.
The @code{elided} function must return an iterable and this iterable
must contain the frames that are being elided wrapped in a suitable
frame decorator. If no frames are being elided this function may
return an empty iterable, or @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's task to also filter out the elided frames from
the source iterator. This will avoid printing the frame twice.
@end defun
@defun FrameDecorator.function (self)
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
@code{None}.
If this function returns @code{None}, @value{GDBN} will not print any
data for this field.
@end defun
@defun FrameDecorator.address (self)
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 @code{None}.
If this function returns a @code{None}, @value{GDBN} will not print
any data for this field.
@end defun
@defun FrameDecorator.filename (self)
This method returns the filename and path associated with this frame.
This method must return a Python string containing the filename and
the path to the object file backing the frame, or @code{None}.
If this function returns a @code{None}, @value{GDBN} will not print
any data for this field.
@end defun
@defun FrameDecorator.line (self):
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 @code{None}.
If this function returns a @code{None}, @value{GDBN} will not print
any data for this field.
@end defun
@defun FrameDecorator.frame_args (self)
@anchor{frame_args}
This method must return an iterable, or @code{None}. Returning an
empty iterable, or @code{None} means frame arguments will not be
printed for this frame. This iterable must contain objects that
implement two methods, described here.
This object must implement a @code{argument} method which takes a
single @code{self} parameter and must return a @code{gdb.Symbol}
(@pxref{Symbols In Python}), or a Python string. The object must also
implement a @code{value} method which takes a single @code{self}
parameter and must return a @code{gdb.Value} (@pxref{Values From
Inferior}), a Python value, or @code{None}. If the @code{value}
method returns @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 SomeFrameDecorator()
...
...
def frame_args(self):
args = []
try:
block = self.inferior_frame.block()
except:
return None
# Iterate over all symbols in a block. Only add
# symbols that are arguments.
for sym in block:
if not sym.is_argument:
continue
args.append(SymValueWrapper(sym,None))
# Add example synthetic argument.
args.append(SymValueWrapper(``foo'', 42))
return args
@end smallexample
@end defun
@defun FrameDecorator.frame_locals (self)
This method must return an iterable or @code{None}. Returning an
empty iterable, or @code{None} means frame local arguments will not be
printed for this frame.
The object interface, the description of the various strategies for
reading frame locals, and the example are largely similar to those
described in the @code{frame_args} function, (@pxref{frame_args,,The
frame filter frame_args function}). Below is a modified example:
@smallexample
class SomeFrameDecorator()
...
...
def frame_locals(self):
vars = []
try:
block = self.inferior_frame.block()
except:
return None
# Iterate over all symbols in a block. Add all
# symbols, except arguments.
for sym in block:
if sym.is_argument:
continue
vars.append(SymValueWrapper(sym,None))
# Add an example of a synthetic local variable.
vars.append(SymValueWrapper(``bar'', 99))
return vars
@end smallexample
@end defun
@defun FrameDecorator.inferior_frame (self):
This method must return the underlying @code{gdb.Frame} that this
frame decorator is decorating. @value{GDBN} requires the underlying
frame for internal frame information to determine how to print certain
values when printing a frame.
@end defun
@node Writing a Frame Filter
@subsubsection Writing a Frame Filter
@cindex writing a frame filter
There are three basic elements that a frame filter must implement: it
must correctly implement the documented interface (@pxref{Frame Filter
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):
# Frame filter attribute creation.
#
# 'name' is the name of the filter that GDB will display.
#
# 'priority' is the priority of the filter relative to other
# filters.
#
# 'enabled' is a boolean that indicates whether this filter is
# enabled and should be executed.
self.name = "Foo"
self.priority = 100
self.enabled = True
# Register this frame filter with the global frame_filters
# dictionary.
gdb.frame_filters[self.name] = self
def filter(self, frame_iter):
# Just return the iterator.
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, and as shown in
the comments the filter assigns the following attributes: @code{name},
@code{priority} and whether the filter should be enabled with the
@code{enabled} attribute.
The second step is registering the frame filter with the dictionary or
dictionaries that the frame filter has interest in. As shown in the
comments, this filter just registers itself with the global dictionary
@code{gdb.frame_filters}. As noted earlier, @code{gdb.frame_filters}
is a dictionary that is initialized in the @code{gdb} module when
@value{GDBN} starts. What dictionary a filter registers with is an
important consideration. Generally, if a filter is specific to a set
of code, it should be registered either in the @code{objfile} or
@code{progspace} dictionaries as they are specific to the program
currently loaded in @value{GDBN}. The global dictionary is always
present in @value{GDBN} and is never unloaded. Any filters registered
with the global dictionary will exist until @value{GDBN} exits. To
avoid filters that may conflict, it is generally better to register
frame filters against the dictionaries that more closely align with
the usage of the filter currently in question. @xref{Python
Auto-loading}, for further information on auto-loading Python scripts.
@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{Frame Filter
Management}), 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. As shown in the example comments, we define the
@code{filter} method and note that the 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 decorator to perform some work on the frames.
@xref{Frame Decorator API}, for further information on the frame
decorator interface.
This example works on inlined frames. It highlights frames which are
inlined by tagging them with an ``[inlined]'' tag. By applying a
frame decorator to all frames with the Python @code{itertools imap}
method, the example defers actions to the frame decorator. Frame
decorators 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 decorator 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.
Some stacks can run very deep, into the tens of thousands in some
cases. 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 decorator can examine each frame
in turn when @value{GDBN} iterates. From a performance viewpoint,
this is the most appropriate decision to make as it avoids duplicating
the effort that the printing step would undertake anyway. 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 = "InlinedFrameFilter"
self.priority = 100
self.enabled = True
gdb.frame_filters[self.name] = self
def filter(self, frame_iter):
frame_iter = itertools.imap(InlinedFrameDecorator,
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 decorator object called
@code{InlinedFrameDecorator} 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 decorator for this example.
@smallexample
class InlinedFrameDecorator(FrameDecorator):
def __init__(self, fobj):
super(InlinedFrameDecorator, self).__init__(fobj)
def function(self):
frame = fobj.inferior_frame()
name = str(frame.name())
if frame.type() == gdb.INLINE_FRAME:
name = name + " [inlined]"
return name
@end smallexample
This frame decorator only defines and overrides the @code{function}
method. It lets the supplied @code{FrameDecorator}, 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] (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 decorator 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 decorator 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
decorator 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 = "InlinedFrameFilter"
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
try:
eliding_frame = next(self.input_iterator)
except StopIteration:
return frame
return ElidingFrameDecorator(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 decorator, @code{frame}, is wrapping
an inlined frame. If it is not, it returns the existing frame decorator
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 decorator, @code{ElidingFrameDecorator}, which contains both the
elided frame, and the eliding frame.
@smallexample
class ElidingInlineDecorator(FrameDecorator):
def __init__(self, frame, elided_frames):
super(ElidingInlineDecorator, self).__init__(frame)
self.frame = frame
self.elided_frames = elided_frames
def elided(self):
return iter(self.elided_frames)
@end smallexample
This frame decorator overrides one function and returns the inlined
frame in the @code{elided} method. As before it lets
@code{FrameDecorator} 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 Inferiors In Python
@subsubsection Inferiors In Python
@cindex inferiors in Python
@ -25235,6 +26026,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 Filter API}, for more information.
@end defvar
@node Objfiles In Python
@subsubsection Objfiles In Python
@ -25285,6 +26081,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 Filter API}, for more information.
@end defvar
A @code{gdb.Objfile} object has the following methods:
@defun Objfile.is_valid ()
@ -26351,7 +27152,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
@ -30222,6 +31023,22 @@ 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).
@subheading The @code{-stack-info-frame} Command
@findex -stack-info-frame
@ -30289,13 +31106,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
@ -30312,7 +31130,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.
@ -30383,13 +31203,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
@ -30419,7 +31240,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
@ -30489,11 +31312,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
@ -30504,7 +31328,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.
@ -30529,13 +31354,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
@ -30543,7 +31369,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

View File

@ -31,6 +31,10 @@
#include "language.h"
#include "valprint.h"
#include "exceptions.h"
#include "utils.h"
#include "mi-getopt.h"
#include "python/python.h"
#include <ctype.h>
enum what_to_list { locals, arguments, all };
@ -38,6 +42,28 @@ static void list_args_or_locals (enum what_to_list what,
enum print_values values,
struct frame_info *fi);
/* True if we want to allow Python-based frame filters. */
static int frame_filters = 0;
void
mi_cmd_enable_frame_filters (char *command, char **argv, int argc)
{
if (argc != 0)
error (_("-enable-frame-filters: no arguments allowed"));
frame_filters = 1;
}
/* Parse the --no-frame-filters option in commands where we cannot use
mi_getopt. */
static int
parse_no_frames_option (const char *arg)
{
if (arg && (strcmp (arg, "--no-frame-filters") == 0))
return 1;
return 0;
}
/* Print a list of the stack frames. Args can be none, in which case
we want to print the whole backtrace, or a pair of numbers
specifying the frame numbers at which to start and stop the
@ -52,14 +78,46 @@ mi_cmd_stack_list_frames (char *command, char **argv, int argc)
int i;
struct cleanup *cleanup_stack;
struct frame_info *fi;
if (argc > 2 || argc == 1)
error (_("-stack-list-frames: Usage: [FRAME_LOW FRAME_HIGH]"));
if (argc == 2)
enum py_bt_status result = PY_BT_ERROR;
int raw_arg = 0;
int oind = 0;
enum opt
{
frame_low = atoi (argv[0]);
frame_high = atoi (argv[1]);
NO_FRAME_FILTERS
};
static const struct mi_opt opts[] =
{
{"-no-frame-filters", NO_FRAME_FILTERS, 0},
{ 0, 0, 0 }
};
/* Parse arguments. In this instance we are just looking for
--no-frame-filters. */
while (1)
{
char *oarg;
int opt = mi_getopt ("-stack-list-frames", argc, argv,
opts, &oind, &oarg);
if (opt < 0)
break;
switch ((enum opt) opt)
{
case NO_FRAME_FILTERS:
raw_arg = oind;
break;
}
}
/* After the last option is parsed, there should either be low -
high range, or no further arguments. */
if ((argc - oind != 0) && (argc - oind != 2))
error (_("-stack-list-frames: Usage: [--no-frame-filters] [FRAME_LOW FRAME_HIGH]"));
/* If there is a range, set it. */
if (argc - oind == 2)
{
frame_low = atoi (argv[0 + oind]);
frame_high = atoi (argv[1 + oind]);
}
else
{
@ -81,16 +139,37 @@ mi_cmd_stack_list_frames (char *command, char **argv, int argc)
cleanup_stack = make_cleanup_ui_out_list_begin_end (current_uiout, "stack");
/* Now let's print the frames up to frame_high, or until there are
frames in the stack. */
for (;
fi && (i <= frame_high || frame_high == -1);
i++, fi = get_prev_frame (fi))
if (! raw_arg && frame_filters)
{
QUIT;
/* Print the location and the address always, even for level 0.
If args is 0, don't print the arguments. */
print_frame_info (fi, 1, LOC_AND_ADDRESS, 0 /* args */ );
int flags = PRINT_LEVEL | PRINT_FRAME_INFO;
int py_frame_low = frame_low;
/* We cannot pass -1 to frame_low, as that would signify a
relative backtrace from the tail of the stack. So, in the case
of frame_low == -1, assign and increment it. */
if (py_frame_low == -1)
py_frame_low++;
result = apply_frame_filter (get_current_frame (), flags,
NO_VALUES, current_uiout,
py_frame_low, frame_high);
}
/* Run the inbuilt backtrace if there are no filters registered, or
if "--no-frame-filters" has been specified from the command. */
if (! frame_filters || raw_arg || result == PY_BT_NO_FILTERS)
{
/* Now let's print the frames up to frame_high, or until there are
frames in the stack. */
for (;
fi && (i <= frame_high || frame_high == -1);
i++, fi = get_prev_frame (fi))
{
QUIT;
/* Print the location and the address always, even for level 0.
If args is 0, don't print the arguments. */
print_frame_info (fi, 1, LOC_AND_ADDRESS, 0 /* args */ );
}
}
do_cleanups (cleanup_stack);
@ -147,13 +226,34 @@ void
mi_cmd_stack_list_locals (char *command, char **argv, int argc)
{
struct frame_info *frame;
int raw_arg = 0;
enum py_bt_status result = PY_BT_ERROR;
int print_value;
if (argc != 1)
error (_("-stack-list-locals: Usage: PRINT_VALUES"));
if (argc > 0)
raw_arg = parse_no_frames_option (argv[0]);
frame = get_selected_frame (NULL);
if (argc < 1 || argc > 2 || (argc == 2 && ! raw_arg)
|| (argc == 1 && raw_arg))
error (_("-stack-list-locals: Usage: [--no-frame-filters] PRINT_VALUES"));
list_args_or_locals (locals, parse_print_values (argv[0]), frame);
frame = get_selected_frame (NULL);
print_value = parse_print_values (argv[raw_arg]);
if (! raw_arg && frame_filters)
{
int flags = PRINT_LEVEL | PRINT_LOCALS;
result = apply_frame_filter (frame, flags, print_value,
current_uiout, 0, 0);
}
/* Run the inbuilt backtrace if there are no filters registered, or
if "--no-frame-filters" has been specified from the command. */
if (! frame_filters || raw_arg || result == PY_BT_NO_FILTERS)
{
list_args_or_locals (locals, print_value, frame);
}
}
/* Print a list of the arguments for the current frame. With argument
@ -170,15 +270,20 @@ mi_cmd_stack_list_args (char *command, char **argv, int argc)
struct cleanup *cleanup_stack_args;
enum print_values print_values;
struct ui_out *uiout = current_uiout;
int raw_arg = 0;
enum py_bt_status result = PY_BT_ERROR;
if (argc < 1 || argc > 3 || argc == 2)
error (_("-stack-list-arguments: Usage: "
"PRINT_VALUES [FRAME_LOW FRAME_HIGH]"));
if (argc > 0)
raw_arg = parse_no_frames_option (argv[0]);
if (argc == 3)
if (argc < 1 || (argc > 3 && ! raw_arg) || (argc == 2 && ! raw_arg))
error (_("-stack-list-arguments: Usage: " \
"[--no-frame-filters] PRINT_VALUES [FRAME_LOW FRAME_HIGH]"));
if (argc >= 3)
{
frame_low = atoi (argv[1]);
frame_high = atoi (argv[2]);
frame_low = atoi (argv[1 + raw_arg]);
frame_high = atoi (argv[2 + raw_arg]);
}
else
{
@ -188,7 +293,7 @@ mi_cmd_stack_list_args (char *command, char **argv, int argc)
frame_high = -1;
}
print_values = parse_print_values (argv[0]);
print_values = parse_print_values (argv[raw_arg]);
/* Let's position fi on the frame at which to start the
display. Could be the innermost frame if the whole stack needs
@ -203,21 +308,41 @@ mi_cmd_stack_list_args (char *command, char **argv, int argc)
cleanup_stack_args
= make_cleanup_ui_out_list_begin_end (uiout, "stack-args");
/* Now let's print the frames up to frame_high, or until there are
frames in the stack. */
for (;
fi && (i <= frame_high || frame_high == -1);
i++, fi = get_prev_frame (fi))
if (! raw_arg && frame_filters)
{
struct cleanup *cleanup_frame;
int flags = PRINT_LEVEL | PRINT_ARGS;
int py_frame_low = frame_low;
QUIT;
cleanup_frame = make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
ui_out_field_int (uiout, "level", i);
list_args_or_locals (arguments, print_values, fi);
do_cleanups (cleanup_frame);
/* We cannot pass -1 to frame_low, as that would signify a
relative backtrace from the tail of the stack. So, in the case
of frame_low == -1, assign and increment it. */
if (py_frame_low == -1)
py_frame_low++;
result = apply_frame_filter (get_current_frame (), flags,
print_values, current_uiout,
py_frame_low, frame_high);
}
/* Run the inbuilt backtrace if there are no filters registered, or
if "--no-frame-filters" has been specified from the command. */
if (! frame_filters || raw_arg || result == PY_BT_NO_FILTERS)
{
/* Now let's print the frames up to frame_high, or until there are
frames in the stack. */
for (;
fi && (i <= frame_high || frame_high == -1);
i++, fi = get_prev_frame (fi))
{
struct cleanup *cleanup_frame;
QUIT;
cleanup_frame = make_cleanup_ui_out_tuple_begin_end (uiout, "frame");
ui_out_field_int (uiout, "level", i);
list_args_or_locals (arguments, print_values, fi);
do_cleanups (cleanup_frame);
}
}
do_cleanups (cleanup_stack_args);
}
@ -230,13 +355,35 @@ void
mi_cmd_stack_list_variables (char *command, char **argv, int argc)
{
struct frame_info *frame;
int raw_arg = 0;
enum py_bt_status result = PY_BT_ERROR;
int print_value;
if (argc != 1)
error (_("Usage: PRINT_VALUES"));
if (argc > 0)
raw_arg = parse_no_frames_option (argv[0]);
frame = get_selected_frame (NULL);
if (argc < 1 || argc > 2 || (argc == 2 && ! raw_arg)
|| (argc == 1 && raw_arg))
error (_("-stack-list-variables: Usage: " \
"[--no-frame-filters] PRINT_VALUES"));
list_args_or_locals (all, parse_print_values (argv[0]), frame);
frame = get_selected_frame (NULL);
print_value = parse_print_values (argv[raw_arg]);
if (! raw_arg && frame_filters)
{
int flags = PRINT_LEVEL | PRINT_ARGS | PRINT_LOCALS;
result = apply_frame_filter (frame, flags, print_value,
current_uiout, 0, 0);
}
/* Run the inbuilt backtrace if there are no filters registered, or
if "--no-frame-filters" has been specified from the command. */
if (! frame_filters || raw_arg || result == PY_BT_NO_FILTERS)
{
list_args_or_locals (all, print_value, frame);
}
}
/* Print single local or argument. ARG must be already read in. For

View File

@ -86,6 +86,7 @@ static struct mi_cmd mi_cmds[] =
mi_cmd_data_write_register_values),
DEF_MI_CMD_MI ("enable-timings", mi_cmd_enable_timings),
DEF_MI_CMD_MI ("enable-pretty-printing", mi_cmd_enable_pretty_printing),
DEF_MI_CMD_MI ("enable-frame-filters", mi_cmd_enable_frame_filters),
DEF_MI_CMD_MI ("environment-cd", mi_cmd_env_cd),
DEF_MI_CMD_MI ("environment-directory", mi_cmd_env_dir),
DEF_MI_CMD_MI ("environment-path", mi_cmd_env_path),

View File

@ -118,6 +118,7 @@ extern mi_cmd_argv_ftype mi_cmd_var_show_attributes;
extern mi_cmd_argv_ftype mi_cmd_var_show_format;
extern mi_cmd_argv_ftype mi_cmd_var_update;
extern mi_cmd_argv_ftype mi_cmd_enable_pretty_printing;
extern mi_cmd_argv_ftype mi_cmd_enable_frame_filters;
extern mi_cmd_argv_ftype mi_cmd_var_set_update_range;
/* Description of a single command. */

View File

@ -0,0 +1,285 @@
# Copyright (C) 2013 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 FrameDecorator(object):
"""Basic implementation of a Frame Decorator"""
""" This base frame decorator decorates a frame or another frame
decorator, and provides convenience methods. If this object is
wrapping a frame decorator, defer to that wrapped object's method
if it has one. This allows for frame decorators that have
sub-classed FrameDecorator object, but also wrap other frame
decorators 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 decorators, all sub-classed from
FrameDecorator, the resulting hierarchy will be:
Decorator1
-- (wraps) Decorator2
-- (wraps) FrameDecorator
-- (wraps) gdb.Frame
In this case we have two frame decorators, both of which are
sub-classed from FrameDecorator. If Decorator1 just overrides the
'function' method, then all of the other methods are carried out
by the super-class FrameDecorator. But Decorator2 may have
overriden other methods, so FrameDecorator 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 decorator. 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):
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.type() == gdb.DUMMY_FRAME
or frame.type() == 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 or an address of
the function of the frame. First determine if this 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 this function returns an
address, GDB will attempt to determine the function name from
its internal minimal symbols store (for example, for inferiors
without debug-info)."""
# Both gdb.Frame, and FrameDecorator have a method called
# "function", so determine which object this is.
if not isinstance(self._base, gdb.Frame):
if hasattr(self._base, "function"):
# If it is not a gdb.Frame, and there is already a
# "function" method, use that.
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()
# If we cannot determine the function name, return the
# address. If GDB detects an integer value from this function
# it will attempt to find the function name from minimal
# symbols via its own internal functions.
if func == None:
pc = frame.pc()
return pc
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 iterable of frame arguments for this frame, if
any. The iterable object 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 iterable of local variables for this frame, if
any. The iterable object 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 decorator."""
# If 'base' is a frame decorator, 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 SymValueWrapper(object):
"""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(object):
"""Utility class to fetch and store frame local variables, or
frame arguments."""
def __init__(self, frame):
self.frame = frame
self.symbol_class = {
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
}
def fetch_b(self, 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 self.symbol_class.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 no frame local variables, return an empty list."""
lvars = []
block = self.frame.block()
while block != None:
if block.is_global or block.is_static:
break
for sym in block:
if sym.is_argument:
continue;
if self.fetch_b(sym):
lvars.append(SymValueWrapper(sym, None))
block = block.superblock
return lvars
def fetch_frame_args(self):
"""Public utility method to fetch frame arguments for the
stored frame. Frame arguments are the only type fetched. If
there are no frame argument variables, return an empty list."""
args = []
block = self.frame.block()
while block != None:
if block.function != None:
break
block = block.superblock
if block != None:
for sym in block:
if not sym.is_argument:
continue;
args.append(SymValueWrapper(sym, None))
return args

View File

@ -0,0 +1,45 @@
# Copyright (C) 2013 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 next(self):
"""next implementation.
Returns:
The next oldest frame."""
result = self.frame
if result is None:
raise StopIteration
self.frame = result.older()
return result

View File

@ -67,6 +67,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__))

View File

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

View File

@ -0,0 +1,229 @@
# Frame-filter commands.
# Copyright (C) 2013 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/>.
"""Internal functions for working with frame-filters."""
import gdb
from gdb.FrameIterator import FrameIterator
from gdb.FrameDecorator import FrameDecorator
import itertools
import collections
def get_priority(filter_item):
""" Internal worker function to return the frame-filter's priority
from a frame filter object. This is a fail free function as it is
used in sorting and filtering. If a badly implemented frame
filter does not implement the priority attribute, return zero
(otherwise sorting/filtering will fail and prevent other frame
filters from executing).
Arguments:
filter_item: An object conforming to the frame filter
interface.
Returns:
The priority of the frame filter from the "priority"
attribute, or zero.
"""
# Do not fail here, as the sort will fail. If a filter has not
# (incorrectly) set a priority, set it to zero.
return getattr(filter_item, "priority", 0)
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.
"""
filter_item.priority = priority
def get_enabled(filter_item):
""" Internal worker function to return a filter's enabled state
from a frame filter object. This is a fail free function as it is
used in sorting and filtering. If a badly implemented frame
filter does not implement the enabled attribute, return False
(otherwise sorting/filtering will fail and prevent other frame
filters from executing).
Arguments:
filter_item: An object conforming to the frame filter
interface.
Returns:
The enabled state of the frame filter from the "enabled"
attribute, or False.
"""
# If the filter class is badly implemented when called from the
# Python filter command, do not cease filter operations, just set
# enabled to False.
return getattr(filter_item, "enabled", False)
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.
"""
filter_item.enabled = state
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 "all", "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 for a single specified dictionary, or a
list containing all the items for "all"
Raises:
gdb.GdbError: A dictionary of that name cannot be found.
"""
# If all dictionaries are wanted in the case of "all" we
# cannot return a combined dictionary as keys() may clash in
# between different dictionaries. As we just want all the frame
# filters to enable/disable them all, just return the combined
# items() as a list.
if name == "all":
all_dicts = gdb.frame_filters.values()
all_dicts = all_dicts + gdb.current_progspace().frame_filters.values()
for objfile in gdb.objfiles():
all_dicts = all_dicts + objfile.frame_filters.values()
return all_dicts
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.values()
cp = gdb.current_progspace()
all_filters = all_filters + cp.frame_filters.values()
all_filters = all_filters + gdb.frame_filters.values()
sorted_frame_filters = sorted(all_filters, key = get_priority,
reverse = True)
sorted_frame_filters = filter(get_enabled,
sorted_frame_filters)
return sorted_frame_filters
def execute_frame_filters(frame, frame_low, frame_high):
""" Internal function called from GDB that will execute the chain
of frame filters. Each filter is executed in priority order.
After the execution completes, slice the iterator to frame_low -
frame_high range.
Arguments:
frame: The initial frame.
frame_low: The low range of the slice. If this is a negative
integer then it indicates a backward slice (ie bt -4) which
counts backward from the last frame in the backtrace.
frame_high: The high range of the slice. If this is -1 then
it indicates all frames until the end of the stack from
frame_low.
Returns:
frame_iterator: The sliced 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 a basic frame decorator to all gdb.Frames. This unifies the
# interface.
frame_iterator = itertools.imap(FrameDecorator, frame_iterator)
for ff in sorted_list:
frame_iterator = ff.filter(frame_iterator)
# Slicing
# Is this a slice from the end of the backtrace, ie bt -2?
if frame_low < 0:
count = 0
slice_length = abs(frame_low)
# We cannot use MAXLEN argument for deque as it is 2.6 onwards
# and some GDB versions might be < 2.6.
sliced = collections.deque()
for frame_item in frame_iterator:
if count >= slice_length:
sliced.popleft();
count = count + 1
sliced.append(frame_item)
return iter(sliced)
# -1 for frame_high means until the end of the backtrace. Set to
# None if that is the case, to indicate to itertools.islice to
# slice to the end of the iterator.
if frame_high == -1:
frame_high = None
else:
# As frames start from 0, add one to frame_high so islice
# correctly finds the end
frame_high = frame_high + 1;
sliced = itertools.islice(frame_iterator, frame_low, frame_high)
return sliced

1528
gdb/python/py-framefilter.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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);
Py_TYPE (self)->tp_free (self);
}
@ -81,6 +84,13 @@ objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
return NULL;
}
self->frame_filters = PyDict_New ();
if (!self->frame_filters)
{
Py_DECREF (self);
return NULL;
}
self->type_printers = PyList_New (0);
if (!self->type_printers)
{
@ -129,6 +139,47 @@ objfpy_set_printers (PyObject *o, PyObject *value, void *ignore)
return 0;
}
/* Return the Python dictionary attribute containing frame filters for
this object file. */
PyObject *
objfpy_get_frame_filters (PyObject *o, void *ignore)
{
objfile_object *self = (objfile_object *) o;
Py_INCREF (self->frame_filters);
return self->frame_filters;
}
/* Set this object file's frame filters dictionary to 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,6 +276,13 @@ objfile_to_objfile_object (struct objfile *objfile)
return NULL;
}
object->frame_filters = PyDict_New ();
if (!object->frame_filters)
{
Py_DECREF (object);
return NULL;
}
object->type_printers = PyList_New (0);
if (!object->type_printers)
{
@ -270,6 +328,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 }

View File

@ -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);
Py_TYPE (self)->tp_free (self);
}
@ -89,6 +92,13 @@ pspy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
return NULL;
}
self->frame_filters = PyDict_New ();
if (!self->frame_filters)
{
Py_DECREF (self);
return NULL;
}
self->type_printers = PyList_New (0);
if (!self->type_printers)
{
@ -137,6 +147,47 @@ pspy_set_printers (PyObject *o, PyObject *value, void *ignore)
return 0;
}
/* Return the Python dictionary attribute containing frame filters for
this program space. */
PyObject *
pspy_get_frame_filters (PyObject *o, void *ignore)
{
pspace_object *self = (pspace_object *) o;
Py_INCREF (self->frame_filters);
return self->frame_filters;
}
/* Set this object file's frame filters dictionary to 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,6 +272,13 @@ pspace_to_pspace_object (struct program_space *pspace)
return NULL;
}
object->frame_filters = PyDict_New ();
if (!object->frame_filters)
{
Py_DECREF (object);
return NULL;
}
object->type_printers = PyList_New (0);
if (!object->type_printers)
{
@ -257,6 +315,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 }

View File

@ -48,6 +48,28 @@ 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;
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, 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.

View File

@ -251,9 +251,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 *);
PyObject *gdbarch_to_arch_object (struct gdbarch *gdbarch);
@ -304,6 +306,7 @@ void gdbpy_initialize_new_objfile_event (void);
void gdbpy_initialize_arch (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);

View File

@ -1393,6 +1393,15 @@ free_type_printers (void *arg)
{
}
enum py_bt_status
apply_frame_filter (struct frame_info *frame, int flags,
enum py_frame_args args_type,
struct ui_out *out, int frame_low,
int frame_high)
{
return PY_BT_NO_FILTERS;
}
#endif /* HAVE_PYTHON */

View File

@ -21,6 +21,7 @@
#define GDB_PYTHON_H
#include "value.h"
#include "mi/mi-cmds.h"
struct breakpoint_object;
@ -28,6 +29,66 @@ 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 return values. */
enum py_bt_status
{
/* Return when an error has occurred in processing frame filters,
or when printing the stack. */
PY_BT_ERROR = -1,
/* Return from internal routines to indicate that the function
succeeded. */
PY_BT_OK = 1,
/* Return when the frame filter process is complete, and all
operations have succeeded. */
PY_BT_COMPLETED = 2,
/* Return when the frame filter process is complete, but there
were no filter registered and enabled to process. */
PY_BT_NO_FILTERS = 3
};
/* 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,
};
/* A choice of the different frame argument printing strategies that
can occur in different cases of frame filter instantiation. */
typedef enum py_frame_args
{
/* Print no values for arguments when invoked from the MI. */
NO_VALUES = PRINT_NO_VALUES,
MI_PRINT_ALL_VALUES = PRINT_ALL_VALUES,
/* Print only simple values (what MI defines as "simple") for
arguments when invoked from the MI. */
MI_PRINT_SIMPLE_VALUES = PRINT_SIMPLE_VALUES,
/* Print only scalar values for arguments when invoked from the
CLI. */
CLI_SCALAR_VALUES,
/* Print all values for arguments when invoked from the
CLI. */
CLI_ALL_VALUES
} py_frame_args;
extern void finish_python_initialization (void);
void eval_python_from_control_command (struct command_line *);
@ -41,6 +102,11 @@ int apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
const struct value_print_options *options,
const struct language_defn *language);
enum py_bt_status apply_frame_filter (struct frame_info *frame, int flags,
enum py_frame_args args_type,
struct ui_out *out, int frame_low,
int frame_high);
void preserve_python_values (struct objfile *objfile, htab_t copied_types);
void gdbpy_load_auto_scripts_for_objfile (struct objfile *objfile);

View File

@ -54,6 +54,7 @@
#include "psymtab.h"
#include "symfile.h"
#include "python/python.h"
void (*deprecated_selected_frame_level_changed_hook) (int);
@ -1651,13 +1652,15 @@ frame_info (char *addr_exp, int from_tty)
frames. */
static void
backtrace_command_1 (char *count_exp, int show_locals, int from_tty)
backtrace_command_1 (char *count_exp, int show_locals, int no_filters,
int from_tty)
{
struct frame_info *fi;
int count;
int i;
struct frame_info *trailing;
int trailing_level;
int trailing_level, py_start = 0, py_end = 0;
enum py_bt_status result = PY_BT_ERROR;
if (!target_has_stack)
error (_("No stack."));
@ -1676,6 +1679,7 @@ backtrace_command_1 (char *count_exp, int show_locals, int from_tty)
{
struct frame_info *current;
py_start = count;
count = -count;
current = trailing;
@ -1697,9 +1701,17 @@ backtrace_command_1 (char *count_exp, int show_locals, int from_tty)
count = -1;
}
else
{
py_start = 0;
py_end = count;
}
}
else
count = -1;
{
py_end = -1;
count = -1;
}
if (info_verbose)
{
@ -1719,16 +1731,40 @@ backtrace_command_1 (char *count_exp, int show_locals, int from_tty)
}
}
for (i = 0, fi = trailing; fi && count--; i++, fi = get_prev_frame (fi))
if (! no_filters)
{
QUIT;
int flags = PRINT_LEVEL | PRINT_FRAME_INFO | PRINT_ARGS;
enum py_frame_args arg_type;
/* Don't use print_stack_frame; if an error() occurs it probably
means further attempts to backtrace would fail (on the other
hand, perhaps the code does or could be fixed to make sure
the frame->prev field gets set to NULL in that case). */
print_frame_info (fi, 1, LOCATION, 1);
if (show_locals)
flags |= PRINT_LOCALS;
if (!strcmp (print_frame_arguments, "scalars"))
arg_type = CLI_SCALAR_VALUES;
else if (!strcmp (print_frame_arguments, "all"))
arg_type = CLI_ALL_VALUES;
else
arg_type = NO_VALUES;
result = apply_frame_filter (get_current_frame (), flags, arg_type,
current_uiout, py_start, py_end);
}
/* Run the inbuilt backtrace if there are no filters registered, or
"no-filters" has been specified from the command. */
if (no_filters || result == PY_BT_NO_FILTERS)
{
for (i = 0, fi = trailing; fi && count--; i++, fi = get_prev_frame (fi))
{
QUIT;
/* Don't use print_stack_frame; if an error() occurs it probably
means further attempts to backtrace would fail (on the other
hand, perhaps the code does or could be fixed to make sure
the frame->prev field gets set to NULL in that case). */
print_frame_info (fi, 1, LOCATION, 1);
if (show_locals)
{
struct frame_id frame_id = get_frame_id (fi);
@ -1744,24 +1780,25 @@ backtrace_command_1 (char *count_exp, int show_locals, int from_tty)
}
}
/* Save the last frame to check for error conditions. */
trailing = fi;
}
/* Save the last frame to check for error conditions. */
trailing = fi;
}
/* If we've stopped before the end, mention that. */
if (fi && from_tty)
printf_filtered (_("(More stack frames follow...)\n"));
/* If we've stopped before the end, mention that. */
if (fi && from_tty)
printf_filtered (_("(More stack frames follow...)\n"));
/* If we've run out of frames, and the reason appears to be an error
condition, print it. */
if (fi == NULL && trailing != NULL)
{
enum unwind_stop_reason reason;
/* If we've run out of frames, and the reason appears to be an error
condition, print it. */
if (fi == NULL && trailing != NULL)
{
enum unwind_stop_reason reason;
reason = get_frame_unwind_stop_reason (trailing);
if (reason >= UNWIND_FIRST_ERROR)
printf_filtered (_("Backtrace stopped: %s\n"),
frame_stop_reason_string (reason));
reason = get_frame_unwind_stop_reason (trailing);
if (reason >= UNWIND_FIRST_ERROR)
printf_filtered (_("Backtrace stopped: %s\n"),
frame_stop_reason_string (reason));
}
}
}
@ -1769,7 +1806,8 @@ static void
backtrace_command (char *arg, int from_tty)
{
struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
int fulltrace_arg = -1, arglen = 0, argc = 0;
int fulltrace_arg = -1, arglen = 0, argc = 0, no_filters = -1;
int user_arg = 0;
if (arg)
{
@ -1786,25 +1824,31 @@ backtrace_command (char *arg, int from_tty)
for (j = 0; j < strlen (argv[i]); j++)
argv[i][j] = tolower (argv[i][j]);
if (fulltrace_arg < 0 && subset_compare (argv[i], "full"))
fulltrace_arg = argc;
if (no_filters < 0 && subset_compare (argv[i], "no-filters"))
no_filters = argc;
else
{
arglen += strlen (argv[i]);
argc++;
if (fulltrace_arg < 0 && subset_compare (argv[i], "full"))
fulltrace_arg = argc;
else
{
user_arg++;
arglen += strlen (argv[i]);
}
}
argc++;
}
arglen += argc;
if (fulltrace_arg >= 0)
arglen += user_arg;
if (fulltrace_arg >= 0 || no_filters >= 0)
{
if (arglen > 0)
{
arg = xmalloc (arglen + 1);
make_cleanup (xfree, arg);
arg[0] = 0;
for (i = 0; i < (argc + 1); i++)
for (i = 0; i < argc; i++)
{
if (i != fulltrace_arg)
if (i != fulltrace_arg && i != no_filters)
{
strcat (arg, argv[i]);
strcat (arg, " ");
@ -1816,7 +1860,8 @@ backtrace_command (char *arg, int from_tty)
}
}
backtrace_command_1 (arg, fulltrace_arg >= 0 /* show_locals */, from_tty);
backtrace_command_1 (arg, fulltrace_arg >= 0 /* show_locals */,
no_filters >= 0 /* no frame-filters */, from_tty);
do_cleanups (old_chain);
}
@ -1824,7 +1869,7 @@ backtrace_command (char *arg, int from_tty)
static void
backtrace_full_command (char *arg, int from_tty)
{
backtrace_command_1 (arg, 1 /* show_locals */, from_tty);
backtrace_command_1 (arg, 1 /* show_locals */, 0, from_tty);
}
@ -2558,7 +2603,9 @@ It can be a stack frame number or the address of the frame.\n"));
add_com ("backtrace", class_stack, backtrace_command, _("\
Print backtrace of all stack frames, or innermost COUNT frames.\n\
With a negative argument, print outermost -COUNT frames.\nUse of the \
'full' qualifier also prints the values of the local variables.\n"));
'full' qualifier also prints the values of the local variables.\n\
Use of the 'no-filters' qualifier prohibits frame filters from executing\n\
on this backtrace.\n"));
add_com_alias ("bt", "backtrace", class_stack, 0);
if (xdb_commands)
{

View File

@ -1,3 +1,12 @@
2013-05-10 Phil Muldoon <pmuldoon@redhat.com>
* gdb.python/py-framefilter.py: New File.
* gdb.python/py-framefilter-mi.exp: Ditto.
* gdb.python/py-framefilter.c: Ditto.
* gdb.python/py-framefilter-mi.exp: Ditto.
* gdb.python/py-framefilter-mi.c: Ditto,
* gdb.python/py-framefilter-gdb.py.in: Ditto.
2013-05-08 Tom Tromey <tromey@redhat.com>
* gdb.base/solib-search.exp: Set test name for "set

View File

@ -0,0 +1,48 @@
# Copyright (C) 2013 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/>.
# This file is part of the GDB testsuite. It tests Python-based
# frame-filters.
import gdb
import itertools
from gdb.FrameDecorator import FrameDecorator
class FrameObjFile ():
def __init__ (self):
self.name = "Filter1"
self.priority = 1
self.enabled = False
gdb.current_progspace().frame_filters ["Progspace" + self.name] = self
gdb.current_objfile().frame_filters ["ObjectFile" + self.name] = self
def filter (self, frame_iter):
return frame_iter
class FrameObjFile2 ():
def __init__ (self):
self.name = "Filter2"
self.priority = 100
self.enabled = True
gdb.current_progspace().frame_filters ["Progspace" + self.name] = self
gdb.current_objfile().frame_filters ["ObjectFile" + self.name] = self
def filter (self, frame_iter):
return frame_iter
FrameObjFile()
FrameObjFile2()

View File

@ -0,0 +1,138 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2013 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/>. */
#include <stdlib.h>
void funca(void);
int count = 0;
typedef struct
{
char *nothing;
int f;
short s;
} foobar;
void end_func (int foo, char *bar, foobar *fb, foobar bf)
{
const char *str = "The End";
const char *st2 = "Is Near";
int b = 12;
short c = 5;
{
int d = 15;
int e = 14;
const char *foo = "Inside block";
{
int f = 42;
int g = 19;
const char *bar = "Inside block x2";
{
short h = 9;
h = h +1; /* Inner test breakpoint */
}
}
}
return; /* Backtrace end breakpoint */
}
void funcb(int j)
{
struct foo
{
int a;
int b;
};
struct foo bar;
bar.a = 42;
bar.b = 84;
funca();
return;
}
void funca(void)
{
foobar fb;
foobar *bf;
if (count < 10)
{
count++;
funcb(count);
}
fb.nothing = "Foo Bar";
fb.f = 42;
fb.s = 19;
bf = malloc (sizeof (foobar));
bf->nothing = malloc (128);
bf->nothing = "Bar Foo";
bf->f = 24;
bf->s = 91;
end_func(21, "Param", bf, fb);
free (bf->nothing);
free (bf);
return;
}
void func1(void)
{
funca();
return;
}
int func2(void)
{
func1();
return 1;
}
void func3(int i)
{
func2();
return;
}
int func4(int j)
{
func3(j);
return 2;
}
int func5(int f, int d)
{
int i = 0;
char *random = "random";
i=i+f;
func4(i);
return i;
}
main()
{
func5(3,5);
}

View File

@ -0,0 +1,179 @@
# Copyright (C) 2013 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/>.
# This file is part of the GDB testsuite. It tests Python-based
# frame-filters.
load_lib mi-support.exp
load_lib gdb-python.exp
set MIFLAGS "-i=mi2"
gdb_exit
if [mi_gdb_start] {
continue
}
standard_testfile py-framefilter-mi.c
set pyfile py-framefilter.py
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-DMI}] != "" } {
untested ${testfile}.exp
return -1
}
mi_delete_breakpoints
mi_gdb_reinitialize_dir $srcdir/$subdir
mi_gdb_load ${binfile}
if {[lsearch -exact [mi_get_features] python] < 0} {
unsupported "python support is disabled"
return -1
}
mi_runto main
set remote_python_file [remote_download host ${srcdir}/${subdir}/${pyfile}]
mi_gdb_test "python execfile ('${remote_python_file}')" ".*\\^done." \
"Load python file"
# Multiple blocks test
mi_continue_to_line [gdb_get_line_number {Inner test breakpoint} ${srcfile}] \
"step to breakpoint"
mi_gdb_test "-stack-list-locals --all-values" \
"\\^done,locals=\\\[{name=\"h\",value=\"9\"},{name=\"f\",value=\"42\"},{name=\"g\",value=\"19\"},{name=\"bar\",value=\"$hex \\\\\"Inside block x2\\\\\"\"},{name=\"d\",value=\"15\"},{name=\"e\",value=\"14\"},{name=\"foo\",value=\"$hex \\\\\"Inside block\\\\\"\"},{name=\"str\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",value=\"12\"},{name=\"c\",value=\"5\"}\\\]" \
"stack-list-locals --all-values"
mi_gdb_test "-enable-frame-filters" ".*\\^done." "enable frame filters"
mi_gdb_test "-stack-list-locals --all-values" \
"\\^done,locals=\\\[{name=\"h\",value=\"9\"},{name=\"f\",value=\"42\"},{name=\"g\",value=\"19\"},{name=\"bar\",value=\"$hex \\\\\"Inside block x2\\\\\"\"},{name=\"d\",value=\"15\"},{name=\"e\",value=\"14\"},{name=\"foo\",value=\"$hex \\\\\"Inside block\\\\\"\"},{name=\"str\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",value=\"12\"},{name=\"c\",value=\"5\"}\\\]" \
"stack-list-locals --all-values frame filters enabled"
mi_continue_to_line [gdb_get_line_number {Backtrace end breakpoint} ${srcfile}] \
"step to breakpoint"
mi_gdb_test "-stack-list-frames" \
"\\^done,stack=\\\[frame={level=\"0\",addr=\"$hex\",func=\"cnuf_dne\".*},frame={level=\"1\",addr=\"$hex\",func=\"acnuf\".*},frame={level=\"2\",addr=\"$hex\",func=\"bcnuf\".*},frame={level=\"3\",addr=\"$hex\",func=\"acnuf\".*},frame={level=\"22\",addr=\"$hex\",func=\"1cnuf\".*,children=\\\[frame={level=\"23\",addr=\"$hex\",func=\"func2\".*}\\\]},frame={level=\"24\",addr=\"$hex\",func=\"3cnuf\".*},frame={level=\"27\",addr=\"$hex\",func=\"niam\".*}\\\].*" \
"filtered stack listing"
mi_gdb_test "-stack-list-frames 0 3" \
"\\^done,stack=\\\[frame={level=\"0\",addr=\"$hex\",func=\"cnuf_dne\".*},frame={level=\"1\",addr=\"$hex\",func=\"acnuf\".*},frame={level=\"2\",addr=\"$hex\",func=\"bcnuf\".*},frame={level=\"3\",addr=\"$hex\",func=\"acnuf\".*}\\\]" \
"filtered stack list 0 3"
mi_gdb_test "-stack-list-frames 22 24" \
"\\^done,stack=\\\[frame={level=\"22\",addr=\"$hex\",func=\"1cnuf\".*,children=\\\[frame={level=\"23\",addr=\"$hex\",func=\"func2\".*}\\\]},frame={level=\"24\",addr=\"$hex\",func=\"3cnuf\".*}\\\]" \
"filtered stack list 22 24"
#stack list arguments
mi_gdb_test "-stack-list-arguments 0" \
"\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[name=\"foo\",name=\"bar\",name=\"fb\",name=\"bf\"\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[name=\"j\"\\\]},.*frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[name=\"f\",name=\"d\"\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \
"stack-list-arguments 0"
mi_gdb_test "-stack-list-arguments --no-frame-filters 0" \
"\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[name=\"foo\",name=\"bar\",name=\"fb\",name=\"bf\"\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[name=\"j\"\\\]},.*frame={level=\"22\",args=\\\[\\\]},frame={level=\"23\",args=\\\[\\\]},.*frame={level=\"26\",args=\\\[name=\"f\",name=\"d\"\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \
"stack-list-arguments --no-frame-filters 0"
mi_gdb_test "-stack-list-arguments 0 0 3" \
"\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[name=\"foo\",name=\"bar\",name=\"fb\",name=\"bf\"\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[name=\"j\"\\\]},frame={level=\"3\",args=\\\[\\\]}\\\]" \
"stack-list-arguments 0 0 3"
mi_gdb_test "-stack-list-arguments 0 22 27" \
"\\^done,stack-args=\\\[frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[name=\"f\",name=\"d\"\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \
"stack-list-arguments 0 22 27"
mi_gdb_test "-stack-list-arguments 1" \
"\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",value=\"21\"},{name=\"bar\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",value=\"$hex\"},{name=\"bf\",value=\"{nothing = $hex \\\\\"Foo Bar\\\\\", f = 42, s = 19}\"}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",value=\"10\"}\\\]},.*frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",value=\"3\"},{name=\"d\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \
"stack-list-arguments 1"
mi_gdb_test "-stack-list-arguments --no-frame-filters 1" \
"\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",value=\"21\"},{name=\"bar\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",value=\"$hex\"},{name=\"bf\",value=\"{nothing = $hex \\\\\"Foo Bar\\\\\", f = 42, s = 19}\"}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",value=\"10\"}\\\]},.*frame={level=\"22\",args=\\\[\\\]},frame={level=\"23\",args=\\\[\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",value=\"3\"},{name=\"d\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \
"stack-list-arguments --no-frame-filters 1"
mi_gdb_test "-stack-list-arguments 1 0 3" \
"\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",value=\"21\"},{name=\"bar\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",value=\"$hex\"},{name=\"bf\",value=\"{nothing = $hex \\\\\"Foo Bar\\\\\", f = 42, s = 19}\"}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",value=\"10\"}\\\]},frame={level=\"3\",args=\\\[\\\]}\\\]" \
"stack-list-arguments 1 0 3"
mi_gdb_test "-stack-list-arguments 1 22 27" \
"\\^done,stack-args=\\\[frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",value=\"3\"},{name=\"d\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \
"stack-list-arguments 1 22 27"
mi_gdb_test "-stack-list-arguments 2" \
"\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",type=\"int\",value=\"21\"},{name=\"bar\",type=\"char \\\*\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",type=\"foobar \\\*\",value=\"$hex\"},{name=\"bf\",type=\"foobar\"\}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",type=\"int\",value=\"10\"}\\\]},.*frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",type=\"int\",value=\"3\"},{name=\"d\",type=\"int\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \
"stack-list-arguments 2"
mi_gdb_test "-stack-list-arguments --no-frame-filters 2" \
"\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",type=\"int\",value=\"21\"},{name=\"bar\",type=\"char \\\*\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",type=\"foobar \\\*\",value=\"$hex\"},{name=\"bf\",type=\"foobar\"}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",type=\"int\",value=\"10\"}\\\]},.*frame={level=\"22\",args=\\\[\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",type=\"int\",value=\"3\"},{name=\"d\",type=\"int\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \
"stack-list-arguments --no-frame-filters 2"
mi_gdb_test "-stack-list-arguments 2 0 3" \
"\\^done,stack-args=\\\[frame={level=\"0\",args=\\\[{name=\"foo\",type=\"int\",value=\"21\"},{name=\"bar\",type=\"char \\\*\",value=\"$hex \\\\\"Param\\\\\"\"},{name=\"fb\",type=\"foobar \\\*\",value=\"$hex\"},{name=\"bf\",type=\"foobar\"}\\\]},frame={level=\"1\",args=\\\[\\\]},frame={level=\"2\",args=\\\[{name=\"j\",type=\"int\",value=\"10\"}\\\]},frame={level=\"3\",args=\\\[\\\]}\\\]" \
"stack-list-arguments 2 0 3"
mi_gdb_test "-stack-list-arguments 2 22 27" \
"\\^done,stack-args=\\\[frame={level=\"22\",args=\\\[\\\],children=\\\[frame={level=\"23\",args=\\\[\\\]}\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",type=\"int\",value=\"3\"},{name=\"d\",type=\"int\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \
"stack-list-arguments 2 22 27"
mi_gdb_test "-stack-list-arguments --no-frame-filters 2 22 27" \
"\\^done,stack-args=\\\[frame={level=\"22\",args=\\\[\\\]},frame={level=\"23\",args=\\\[\\\]},.*frame={level=\"26\",args=\\\[{name=\"f\",type=\"int\",value=\"3\"},{name=\"d\",type=\"int\",value=\"5\"}\\\]},frame={level=\"27\",args=\\\[\\\]}\\\]" \
"stack-list-arguments --no-frame-filters 2 22 27"
#stack-list-locals
mi_gdb_test "-stack-list-locals --no-frame-filters 0" \
"\\^done,locals=\\\[name=\"str\",name=\"st2\",name=\"b\",name=\"c\"\\\]" \
"stack-list-locals --no-frame-filters 0"
mi_gdb_test "-stack-list-locals --no-frame-filters 1" \
"\\^done,locals=\\\[{name=\"str\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",value=\"12\"},{name=\"c\",value=\"5\"}\\\]" \
"stack-list-locals --no-frame-filters 1"
mi_gdb_test "-stack-list-locals --no-frame-filters 2" \
"\\^done,locals=\\\[{name=\"str\",type=\"const char \\\*\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",type=\"const char \\\*\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",type=\"int\",value=\"12\"},{name=\"c\",type=\"short\",value=\"5\"}\\\]" \
"stack-list-locals --no-frame-filters 2"
mi_gdb_test "-stack-list-locals --no-frame-filters --no-values" \
"\\^done,locals=\\\[name=\"str\",name=\"st2\",name=\"b\",name=\"c\"\\\]" \
"stack-list-locals --no-frame-filters --no-values"
mi_gdb_test "-stack-list-locals --no-frame-filters --all-values" \
"\\^done,locals=\\\[{name=\"str\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",value=\"12\"},{name=\"c\",value=\"5\"}\\\]" \
"stack-list-locals --no-frame-filters --all-values"
mi_gdb_test "-stack-list-locals --no-frame-filters --simple-values" \
"\\^done,locals=\\\[{name=\"str\",type=\"const char \\\*\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",type=\"const char \\\*\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",type=\"int\",value=\"12\"},{name=\"c\",type=\"short\",value=\"5\"}\\\]" \
"stack-list-locals --no-frame-filters --simple-values"
mi_gdb_test "-stack-list-locals 0" \
"\\^done,locals=\\\[name=\"str\",name=\"st2\",name=\"b\",name=\"c\"\\\]" \
"stack-list-locals 0"
mi_gdb_test "-stack-list-locals 1" \
"\\^done,locals=\\\[{name=\"str\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",value=\"12\"},{name=\"c\",value=\"5\"}\\\]" \
"stack-list-locals 1"
mi_gdb_test "-stack-list-locals 2" \
"\\^done,locals=\\\[{name=\"str\",type=\"const char \\\*\",value=\"$hex \\\\\"The End\\\\\"\"},{name=\"st2\",type=\"const char \\\*\",value=\"$hex \\\\\"Is Near\\\\\"\"},{name=\"b\",type=\"int\",value=\"12\"},{name=\"c\",type=\"short\",value=\"5\"}\\\]" \
"stack-list-locals 2"
# stack-list-variables
mi_gdb_test "-stack-list-variables --no-frame-filters 0" \
"\\^done,variables=\\\[{name=\"foo\",arg=\"1\"},{name=\"bar\",arg=\"1\"},{name=\"fb\",arg=\"1\"},{name=\"bf\",arg=\"1\"},{name=\"str\"},{name=\"st2\"},{name=\"b\"},{name=\"c\"}\\\]" \
"stack-list-variables --no-frame-filters 0"
mi_gdb_test "-stack-list-variables 0" \
"\\^done,variables=\\\[{name=\"foo\",arg=\"1\"},{name=\"bar\",arg=\"1\"},{name=\"fb\",arg=\"1\"},{name=\"bf\",arg=\"1\"},{name=\"str\"},{name=\"st2\"},{name=\"b\"},{name=\"c\"}\\\]" \
"stack-list-variables 0"

View File

@ -0,0 +1,155 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2013 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/>. */
#include <stdlib.h>
void funca(void);
int count = 0;
typedef struct
{
char *nothing;
int f;
short s;
} foobar;
void end_func (int foo, char *bar, foobar *fb, foobar bf)
{
const char *str = "The End";
const char *st2 = "Is Near";
int b = 12;
short c = 5;
{
int d = 15;
int e = 14;
const char *foo = "Inside block";
{
int f = 42;
int g = 19;
const char *bar = "Inside block x2";
{
short h = 9;
h = h +1; /* Inner test breakpoint */
}
}
}
return; /* Backtrace end breakpoint */
}
void funcb(int j)
{
struct foo
{
int a;
int b;
};
struct foo bar;
bar.a = 42;
bar.b = 84;
funca();
return;
}
void funca(void)
{
foobar fb;
foobar *bf = NULL;
if (count < 10)
{
count++;
funcb(count);
}
fb.nothing = "Foo Bar";
fb.f = 42;
fb.s = 19;
bf = alloca (sizeof (foobar));
bf->nothing = alloca (128);
bf->nothing = "Bar Foo";
bf->f = 24;
bf->s = 91;
end_func(21, "Param", bf, fb);
return;
}
void func1(void)
{
funca();
return;
}
int func2(int f)
{
int c;
const char *elided = "Elided frame";
foobar fb;
foobar *bf = NULL;
fb.nothing = "Elided Foo Bar";
fb.f = 84;
fb.s = 38;
bf = alloca (sizeof (foobar));
bf->nothing = alloca (128);
bf->nothing = "Elided Bar Foo";
bf->f = 48;
bf->s = 182;
func1();
return 1;
}
void func3(int i)
{
func2(i);
return;
}
int func4(int j)
{
func3(j);
return 2;
}
int func5(int f, int d)
{
int i = 0;
char *random = "random";
i=i+f;
func4(i);
return i;
}
main()
{
int z = 32;
int y = 44;
const char *foo1 = "Test";
func5(3,5);
}

View File

@ -0,0 +1,239 @@
# Copyright (C) 2013 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/>.
# This file is part of the GDB testsuite. It tests Python-based
# frame-filters.
load_lib gdb-python.exp
standard_testfile
# We cannot use prepare_for_testing as we have to set the safe-patch
# to check objfile and progspace printers.
if {[build_executable $testfile.exp $testfile $srcfile debug] == -1} {
return -1
}
# Start with a fresh gdb.
gdb_exit
gdb_start
# Skip all tests if Python scripting is not enabled.
if { [skip_python_tests] } { continue }
# Make the -gdb.py script available to gdb, it is automagically loaded by gdb.
# Care is taken to put it in the same directory as the binary so that
# gdb will find it.
set remote_obj_python_file \
[remote_download \
host ${srcdir}/${subdir}/${testfile}-gdb.py.in \
${subdir}/${testfile}-gdb.py]
gdb_reinitialize_dir $srcdir/$subdir
gdb_test_no_output "set auto-load safe-path ${remote_obj_python_file}" \
"set auto-load safe-path"
gdb_load ${binfile}
# Verify gdb loaded the script.
gdb_test "info auto-load python-scripts" "Yes.*/${testfile}-gdb.py.*" \
"Test auto-load had loaded python scripts"
if ![runto_main] then {
perror "couldn't run to breakpoint"
return
}
gdb_test_no_output "set python print-stack full" \
"Set python print-stack to full"
# Load global frame-filters
set remote_python_file [remote_download host ${srcdir}/${subdir}/${testfile}.py]
gdb_test_no_output "python execfile ('${remote_python_file}')" \
"Load python file"
gdb_breakpoint [gdb_get_line_number "Backtrace end breakpoint"]
gdb_breakpoint [gdb_get_line_number "Inner test breakpoint"]
gdb_continue_to_breakpoint "Inner test breakpoint"
# Test multiple local blocks.
gdb_test "bt full no-filters" \
".*#0.*end_func.*h = 9.*f = 42.*g = 19.*bar = $hex \"Inside block x2\".*d = 15.*e = 14.*foo = $hex \"Inside block\".*str = $hex \"The End\".*st2 = $hex \"Is Near\".*b = 12.*c = 5.*" \
"bt full no-filters"
gdb_test "bt full" \
".*#0.*cnuf_dne.*h = 9.*f = 42.*g = 19.*bar = $hex \"Inside block x2\".*d = 15.*e = 14.*foo = $hex \"Inside block\".*str = $hex \"The End\".*st2 = $hex \"Is Near\".*b = 12.*c = 5.*" \
"bt full with filters"
gdb_continue_to_breakpoint "Backtrace end breakpoint"
# Test set/show
gdb_test "info frame-filter" \
".*900.*Yes.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \
"info frame filter before setting priority"
gdb_test "show frame-filter priority global Elider" \
"Priority of filter 'Elider' in list 'global' is: 900" \
"show frame-filter priority global Elider before setting"
gdb_test_no_output "set frame-filter priority global Elider 1000" \
"set frame-filter priotiy global Elider 1000"
gdb_test "show frame-filter priority global Elider" \
"Priority of filter 'Elider' in list 'global' is: 1000" \
"show frame-filter priority global Elider after setting"
gdb_test "info frame-filter" \
".*1000.*Yes.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \
"info frame filter after setting priority"
# Test enable/disable
gdb_test "info frame-filter" \
".*1000.*Yes.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \
"info frame filter before disable frame filter"
gdb_test_no_output "disable frame-filter global Elider" \
"disable frame-filter global Elider"
gdb_test "info frame-filter" \
".*1000.*No.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \
"info frame filter after disable frame filter"
gdb_test_no_output "enable frame-filter global Elider" \
"enable frame-filter global Elider"
gdb_test "info frame-filter" \
".*1000.*Yes.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \
"info frame filter after reenabling frame filter"
# Test no-filters
gdb_test "bt no-filters" \
".*#0.*end_func.*#22.*in func1.*#27.*in main \\(\\).*" \
"bt no-filters"
# Test reverse
gdb_test "bt" \
".*#0.*cnuf_dne.*#22.*in 1cnuf.*#27.*in niam \\(\\).*" \
"bt with frame filters"
# Disable Reverse
gdb_test_no_output "disable frame-filter global Reverse" \
"disable frame-filter global Reverse"
gdb_test "bt" \
".*#0.*end_func.*#22.*in func1.*#27.*in main \\(\\).*" \
"bt with frame-filter Reverse disabled"
gdb_test "bt -2" \
".*#26.*func5.*#27.*in main \\(\\).*" \
"bt -2 with frame-filter Reverse disabled"
gdb_test "bt 3" \
".*#0.*end_func.*#1.*in funca \\(\\).*#2.*in funcb \\(j=10\\).*" \
"bt 3 with frame-filter Reverse disabled"
gdb_test "bt no-filter full" \
".*#0.*end_func.*str = $hex \"The End\".*st2 = $hex \"Is Near\".*b = 12.*c = 5.*#1.*in funca \\(\\).*#2.*in funcb \\(j=10\\).*bar = \{a = 42, b = 84\}.*" \
"bt no-filters full with Reverse disabled"
gdb_test "bt full" \
".*#0.*end_func.*str = $hex \"The End\".*st2 = $hex \"Is Near\".*b = 12.*c = 5.*#1.*in funca \\(\\).*#2.*in funcb \\(j=10\\).*bar = \{a = 42, b = 84\}.*#22.*in func1 \\(\\).*#23.*in func2 \\(f=3\\).*elided = $hex \"Elided frame\".*fb = \{nothing = $hex \"Elided Foo Bar\", f = 84, s = 38\}.*bf = $hex.*" \
"bt full with Reverse disabled"
# Test set print frame-arguments
# none
gdb_test_no_output "set print frame-arguments none" \
"turn off frame arguments"
gdb_test "bt no-filter 1" \
"#0.*end_func \\(foo=\.\.\., bar=\.\.\., fb=\.\.\., bf=\.\.\.\\) at .*py-framefilter.c.*" \
"bt no-filter 1 no args"
gdb_test "bt 1" \
"#0.*end_func \\(foo=\.\.\., bar=\.\.\., fb=\.\.\., bf=\.\.\.\\) at .*py-framefilter.c.*" \
"bt 1 no args"
# scalars
gdb_test_no_output "set print frame-arguments scalars" \
"turn frame arguments to scalars only"
gdb_test "bt no-filter 1" \
"#0.*end_func \\(foo=21, bar=$hex \"Param\", fb=$hex, bf=\.\.\.\\) at .*py-framefilter.c.*" \
"bt no-filter 1 scalars"
gdb_test "bt 1" \
"#0.*end_func \\(foo=21, bar=$hex \"Param\", fb=$hex, bf=\.\.\.\\) at .*py-framefilter.c.*" \
"bt 1 scalars"
# all
gdb_test_no_output "set print frame-arguments all" \
"turn on frame arguments"
gdb_test "bt no-filter 1" \
"#0.*end_func \\(foo=21, bar=$hex \"Param\", fb=$hex, bf=\{nothing = $hex \"Foo Bar\", f = 42, s = 19\}\\) at .*py-framefilter.c.*" \
"bt no-filter 1 all args"
gdb_test "bt 1" \
"#0.*end_func \\(foo=21, bar=$hex \"Param\", fb=$hex, bf=\{nothing = $hex \"Foo Bar\", f = 42, s = 19\}\\) at .*py-framefilter.c.*" \
"bt 1 all args"
# set print address off
gdb_test_no_output "set print address off" \
"Turn off address printing"
gdb_test "bt no-filter 1" \
"#0 end_func \\(foo=21, bar=\"Param\", fb=, bf=\{nothing = \"Foo Bar\", f = 42, s = 19\}\\) at .*py-framefilter.c.*" \
"bt no-filter 1 no address"
gdb_test "bt 1" \
"#0 end_func \\(foo=21, bar=\"Param\", fb=, bf=\{nothing = \"Foo Bar\", f = 42, s = 19\}\\) at .*py-framefilter.c.*" \
"bt 1 no addresss"
remote_file host delete ${remote_python_file}
# Test with no debuginfo
# We cannot use prepare_for_testing as we have to set the safe-patch
# to check objfile and progspace printers.
if {[build_executable $testfile.exp $testfile $srcfile {nodebug}] == -1} {
return -1
}
# Start with a fresh gdb.
gdb_exit
gdb_start
# Skip all tests if Python scripting is not enabled.
if { [skip_python_tests] } { continue }
# Make the -gdb.py script available to gdb, it is automagically loaded by gdb.
# Care is taken to put it in the same directory as the binary so that
# gdb will find it.
set remote_obj_python_file \
[remote_download \
host ${srcdir}/${subdir}/${testfile}-gdb.py.in \
${subdir}/${testfile}-gdb.py]
gdb_reinitialize_dir $srcdir/$subdir
gdb_test_no_output "set auto-load safe-path ${remote_obj_python_file}" \
"set auto-load safe-path for no debug info"
gdb_load ${binfile}
# Verify gdb loaded the script.
gdb_test "info auto-load python-scripts" "Yes.*/${testfile}-gdb.py.*" \
"Set autoload path for no debug info tests"
if ![runto_main] then {
perror "couldn't run to breakpoint"
return
}
gdb_test_no_output "set python print-stack full" \
"set python print-stack full for no debuginfo tests"
# Load global frame-filters
set remote_python_file [remote_download host ${srcdir}/${subdir}/${testfile}.py]
gdb_test_no_output "python execfile ('${remote_python_file}')" \
"Load python file for no debuginfo tests"
# Disable Reverse
gdb_test_no_output "disable frame-filter global Reverse" \
"disable frame-filter gloval Reverse for no debuginfo"
gdb_test "bt" \
".*#0..*in main \\(\\).*" \
"bt for no debuginfo"
gdb_test "bt full" \
".*#0..*in main \\(\\).*" \
"bt full for no debuginfo"
gdb_test "bt no-filters" \
".*#0..*in main \\(\\).*" \
"bt no filters for no debuginfo"
gdb_test "bt no-filters full" \
".*#0..*in main \\(\\).*" \
"bt no-filters full no debuginfo"

View File

@ -0,0 +1,117 @@
# Copyright (C) 2013 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/>.
# This file is part of the GDB testsuite. It tests Python-based
# frame-filters.
import gdb
import itertools
from gdb.FrameDecorator import FrameDecorator
import copy
class Reverse_Function (FrameDecorator):
def __init__(self, fobj):
super(Reverse_Function, self).__init__(fobj)
self.fobj = fobj
def function (self):
fname = str (self.fobj.function())
if (fname == None or fname == ""):
return None
else:
fname = fname[::-1]
return fname
class Dummy (FrameDecorator):
def __init__(self, fobj):
super(Dummy, self).__init__(fobj)
self.fobj = fobj
def function (self):
return "Dummy function"
def address (self):
return 0x123
def filename (self):
return "Dummy filename"
def frame_args (self):
return [("Foo",gdb.Value(12)),("Bar","Stuff"), ("FooBar",42)]
def frame_locals (self):
return []
def line (self):
return 0
def elided (self):
return None
class FrameFilter ():
def __init__ (self):
self.name = "Reverse"
self.priority = 100
self.enabled = True
gdb.frame_filters [self.name] = self
def filter (self, frame_iter):
frame_iter = itertools.imap (Reverse_Function,
frame_iter)
return frame_iter
class ElidingFrameDecorator(FrameDecorator):
def __init__(self, frame, elided_frames):
super(ElidingFrameDecorator, self).__init__(frame)
self.elided_frames = elided_frames
def elided(self):
return iter(self.elided_frames)
class ElidingIterator:
def __init__(self, ii):
self.input_iterator = ii
def __iter__(self):
return self
def next(self):
frame = next(self.input_iterator)
if str(frame.function()) != 'func1':
return frame
# Suppose we want to return the 'func1' frame but elide the
# next frame. E.g., if call in our interpreter language takes
# two C frames to implement, and the first one we see is the
# "sentinel".
elided = next(self.input_iterator)
return ElidingFrameDecorator(frame, [elided])
class FrameElider ():
def __init__ (self):
self.name = "Elider"
self.priority = 900
self.enabled = True
gdb.frame_filters [self.name] = self
def filter (self, frame_iter):
return ElidingIterator (frame_iter)
FrameFilter()
FrameElider()