mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-03 21:34:46 +08:00
Add support for writing unwinders in Python.
gdb/ChangeLog: * Makefile.in (SUBDIR_PYTHON_OBJS): Add py-unwind.o. (SUBDIR_PYTHON_SRCS): Add py-unwind.c. (py-unwind.o): New recipe. * NEWS: mention Python frame unwinding. * data-directory/Makefile.in (PYTHON_FILE_LIST): Add gdb/unwinder.py and gdb/command/unwinder.py * python/lib/gdb/__init__.py (packages): Add frame_unwinders list. (execute_unwinders): New function. * python/lib/gdb/command/unwinders.py: New file. * python/lib/gdb/unwinder.py: New file. * python/py-objfile.c (objfile_object): Add frame_unwinders field. (objfpy_dealloc): Decrement frame_unwinders reference count. (objfpy_initialize): Create frame_unwinders list. (objfpy_get_frame_unwinders): New function. (objfpy_set_frame_unwinders): Ditto. (objfile_getset): Add frame_unwinders attribute to Objfile. * python/py-progspace.c (pspace_object): Add frame_unwinders field. (pspy_dealloc): Decrement frame_unwinders reference count. (pspy_initialize): Create frame_unwinders list. (pspy_get_frame_unwinders): New function. (pspy_set_frame_unwinders): Ditto. (pspy_getset): Add frame_unwinders attribute to gdb.Progspace. * python/py-unwind.c: New file. * python/python-internal.h (pspy_get_name_unwinders): New prototype. (objpy_get_frame_unwinders): New prototype. (gdbpy_initialize_unwind): New prototype. * python/python.c (gdbpy_apply_type_printers): Call gdbpy_initialize_unwind. gdb/doc/ChangeLog: * doc/python.texi (Writing a Frame Unwinder in Python): Add section. gdb/testsuite/ChangeLog: * gdb.python/py-unwind-maint.c: New file. * gdb.python/py-unwind-maint.exp: New test. * gdb.python/py-unwind-maint.py: New file. * gdb.python/py-unwind.c: New file. * gdb.python/py-unwind.exp: New test. * gdb.python/py-unwind.py: New test.
This commit is contained in:

committed by
Doug Evans

parent
79730a3b26
commit
d11916aa89
@ -144,6 +144,7 @@ optional arguments while skipping others. Example:
|
||||
* Frame Filter API:: Filtering Frames.
|
||||
* Frame Decorator API:: Decorating Frames.
|
||||
* Writing a Frame Filter:: Writing a Frame Filter.
|
||||
* Unwinding Frames in Python:: Writing frame unwinder.
|
||||
* Xmethods In Python:: Adding and replacing methods of C++ classes.
|
||||
* Xmethod API:: Xmethod types.
|
||||
* Writing an Xmethod:: Writing an xmethod.
|
||||
@ -2178,6 +2179,148 @@ printed hierarchically. Another approach would be to combine the
|
||||
marker in the inlined frame, and also show the hierarchical
|
||||
relationship.
|
||||
|
||||
@node Unwinding Frames in Python
|
||||
@subsubsection Unwinding Frames in Python
|
||||
@cindex unwinding frames in Python
|
||||
|
||||
In @value{GDBN} terminology ``unwinding'' is the process of finding
|
||||
the previous frame (that is, caller's) from the current one. An
|
||||
unwinder has three methods. The first one checks if it can handle
|
||||
given frame (``sniff'' it). For the frames it can sniff an unwinder
|
||||
provides two additional methods: it can return frame's ID, and it can
|
||||
fetch registers from the previous frame. A running @value{GDBN}
|
||||
mantains a list of the unwinders and calls each unwinder's sniffer in
|
||||
turn until it finds the one that recognizes the current frame. There
|
||||
is an API to register an unwinder.
|
||||
|
||||
The unwinders that come with @value{GDBN} handle standard frames.
|
||||
However, mixed language applications (for example, an application
|
||||
running Java Virtual Machine) sometimes use frame layouts that cannot
|
||||
be handled by the @value{GDBN} unwinders. You can write Python code
|
||||
that can handle such custom frames.
|
||||
|
||||
You implement a frame unwinder in Python as a class with which has two
|
||||
attributes, @code{name} and @code{enabled}, with obvious meanings, and
|
||||
a single method @code{__call__}, which examines a given frame and
|
||||
returns an object (an instance of @code{gdb.UnwindInfo class)}
|
||||
describing it. If an unwinder does not recognize a frame, it should
|
||||
return @code{None}. The code in @value{GDBN} that enables writing
|
||||
unwinders in Python uses this object to return frame's ID and previous
|
||||
frame registers when @value{GDBN} core asks for them.
|
||||
|
||||
@subheading Unwinder Input
|
||||
|
||||
An object passed to an unwinder (a @code{gdb.PendingFrame} instance)
|
||||
provides a method to read frame's registers:
|
||||
|
||||
@defun PendingFrame.read_register (reg)
|
||||
This method returns the contents of the register @var{regn} in the
|
||||
frame as a @code{gdb.Value} object. @var{reg} can be either a
|
||||
register number or a register name; the values are platform-specific.
|
||||
They are usually found in the corresponding
|
||||
@file{@var{platform}-tdep.h} file in the @value{GDBN} source tree.
|
||||
@end defun
|
||||
|
||||
It also provides a factory method to create a @code{gdb.UnwindInfo}
|
||||
instance to be returned to @value{GDBN}:
|
||||
|
||||
@defun PendingFrame.create_unwind_info (frame_id)
|
||||
Returns a new @code{gdb.UnwindInfo} instance identified by given
|
||||
@var{frame_id}. The argument is used to build @value{GDBN}'s frame ID
|
||||
using one of functions provided by @value{GDBN}. @var{frame_id}'s attributes
|
||||
determine which function will be used, as follows:
|
||||
|
||||
@table @code
|
||||
@item sp, pc, special
|
||||
@code{frame_id_build_special (@var{frame_id}.sp, @var{frame_id}.pc, @var{frame_id}.special)}
|
||||
|
||||
@item sp, pc
|
||||
@code{frame_id_build (@var{frame_id}.sp, @var{frame_id}.pc)}
|
||||
|
||||
This is the most common case.
|
||||
|
||||
@item sp
|
||||
@code{frame_id_build_wild (@var{frame_id}.sp)}
|
||||
@end table
|
||||
The attribute values should be @code{gdb.Value}
|
||||
|
||||
@end defun
|
||||
|
||||
@subheading Unwinder Output: UnwindInfo
|
||||
|
||||
Use @code{PendingFrame.create_unwind_info} method described above to
|
||||
create a @code{gdb.UnwindInfo} instance. Use the following method to
|
||||
specify caller registers that have been saved in this frame:
|
||||
|
||||
@defun gdb.UnwindInfo.add_saved_register (reg, value)
|
||||
@var{reg} identifies the register. It can be a number or a name, just
|
||||
as for the @code{PendingFrame.read_register} method above.
|
||||
@var{value} is a register value (a @code{gdb.Value} object).
|
||||
@end defun
|
||||
|
||||
@subheading Unwinder Skeleton Code
|
||||
|
||||
@value{GDBN} comes with the module containing the base @code{Unwinder}
|
||||
class. Derive your unwinder class from it and structure the code as
|
||||
follows:
|
||||
|
||||
@smallexample
|
||||
from gdb.unwinders import Unwinder
|
||||
|
||||
class FrameId(object):
|
||||
def __init__(self, sp, pc):
|
||||
self.sp = sp
|
||||
self.pc = pc
|
||||
|
||||
|
||||
class MyUnwinder(Unwinder):
|
||||
def __init__(....):
|
||||
supe(MyUnwinder, self).__init___(<expects unwinder name argument>)
|
||||
|
||||
def __call__(pending_frame):
|
||||
if not <we recognize frame>:
|
||||
return None
|
||||
# Create UnwindInfo. Usually the frame is identified by the stack
|
||||
# pointer and the program counter.
|
||||
sp = pending_frame.read_register(<SP number>)
|
||||
pc = pending_frame.read_register(<PC number>)
|
||||
unwind_info = pending_frame.create_unwind_info(FrameId(sp, pc))
|
||||
|
||||
# Find the values of the registers in the caller's frame and
|
||||
# save them in the result:
|
||||
unwind_info.add_saved_register(<register>, <value>)
|
||||
....
|
||||
|
||||
# Return the result:
|
||||
return unwind_info
|
||||
|
||||
@end smallexample
|
||||
|
||||
@subheading Registering a Unwinder
|
||||
|
||||
An object file, a program space, and the @value{GDBN} proper can have
|
||||
unwinders registered with it.
|
||||
|
||||
The @code{gdb.unwinders} module provides the function to register a
|
||||
unwinder:
|
||||
|
||||
@defun gdb.unwinder.register_unwinder (locus, unwinder, replace=False)
|
||||
@var{locus} is specifies an object file or a program space to which
|
||||
@var{unwinder} is added. Passing @code{None} or @code{gdb} adds
|
||||
@var{unwinder} to the @value{GDBN}'s global unwinder list. The newly
|
||||
added @var{unwinder} will be called before any other unwinder from the
|
||||
same locus. Two unwinders in the same locus cannot have the same
|
||||
name. An attempt to add a unwinder with already existing name raises
|
||||
an exception unless @var{replace} is @code{True}, in which case the
|
||||
old unwinder is deleted.
|
||||
@end defun
|
||||
|
||||
@subheading Unwinder Precedence
|
||||
|
||||
@value{GDBN} first calls the unwinders from all the object files in no
|
||||
particular order, then the unwinders from the current program space,
|
||||
and finally the unwinders from @value{GDBN}.
|
||||
|
||||
@node Xmethods In Python
|
||||
@subsubsection Xmethods In Python
|
||||
@cindex xmethods in Python
|
||||
|
Reference in New Issue
Block a user