mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2025-01-02 01:38:26 +00:00
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:
parent
3ecb733811
commit
1e611234ee
@ -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.
|
||||
|
@ -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)
|
||||
|
4
gdb/NEWS
4
gdb/NEWS
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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. */
|
||||
|
285
gdb/python/lib/gdb/FrameDecorator.py
Normal file
285
gdb/python/lib/gdb/FrameDecorator.py
Normal 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
|
45
gdb/python/lib/gdb/FrameIterator.py
Normal file
45
gdb/python/lib/gdb/FrameIterator.py
Normal 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
|
@ -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__))
|
||||
|
461
gdb/python/lib/gdb/command/frame_filters.py
Normal file
461
gdb/python/lib/gdb/command/frame_filters.py
Normal 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()
|
229
gdb/python/lib/gdb/frames.py
Normal file
229
gdb/python/lib/gdb/frames.py
Normal 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
1528
gdb/python/py-framefilter.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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 }
|
||||
|
@ -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 }
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
121
gdb/stack.c
121
gdb/stack.c
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
48
gdb/testsuite/gdb.python/py-framefilter-gdb.py.in
Normal file
48
gdb/testsuite/gdb.python/py-framefilter-gdb.py.in
Normal 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()
|
138
gdb/testsuite/gdb.python/py-framefilter-mi.c
Normal file
138
gdb/testsuite/gdb.python/py-framefilter-mi.c
Normal 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);
|
||||
}
|
179
gdb/testsuite/gdb.python/py-framefilter-mi.exp
Normal file
179
gdb/testsuite/gdb.python/py-framefilter-mi.exp
Normal 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"
|
155
gdb/testsuite/gdb.python/py-framefilter.c
Normal file
155
gdb/testsuite/gdb.python/py-framefilter.c
Normal 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);
|
||||
}
|
239
gdb/testsuite/gdb.python/py-framefilter.exp
Normal file
239
gdb/testsuite/gdb.python/py-framefilter.exp
Normal 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"
|
117
gdb/testsuite/gdb.python/py-framefilter.py
Normal file
117
gdb/testsuite/gdb.python/py-framefilter.py
Normal 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()
|
Loading…
Reference in New Issue
Block a user