This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC] [PATCH] Provide the ability to write the frame unwinder in Python


Fixed documentation and added '_gdb.' prefix to 'objfiles()'.
PTAL.


On Mon, Mar 30, 2015 at 10:45 AM, Doug Evans <dje@google.com> wrote:
> Alexander Smundak writes:
>  > Addressed eliz@ and dje@ comments.
>  >
>  > gdb/ChangeLog
>  >
>  > 2015-03-28  Sasha Smundak  <asmundak@google.com>
>  >
>  >     * 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
>  >     * doc/python.texi (Writing a Frame Unwinder in Python): Add
>  >     section.
>  >     * 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/testsuite/ChangeLog
>  >
>  > 2015-03-28  Sasha Smundak  <asmundak@google.com>
>  >
>  >     * 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.
>
> Hi.  Just a few more nits.
>
>  > diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
>  > index d725eb0..6b1878e 100644
>  > --- a/gdb/doc/python.texi
>  > +++ b/gdb/doc/python.texi
>  > @@ -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
>  > +
>  > +A @code{gdb.UnwindInfo} object can be constructed by one of the
>  > +methods described above.  Use the following method to set the caller
>
> I'd replace "can be constructed by one of the methods describe above." with
> "is constructed with the @code{PendingFrame.create_unwind_info}
> method described above."
>
>  > +frame's registers:
>  > +
>  > +@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_instance
>
> s/unwind_instance/unwind_info/
>
>  > diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py
>  > index 92b06f2..0494959 100644
>  > --- a/gdb/python/lib/gdb/__init__.py
>  > +++ b/gdb/python/lib/gdb/__init__.py
>  > @@ -71,6 +71,42 @@ type_printers = []
>  >  xmethods = []
>  >  # Initial frame filters.
>  >  frame_filters = {}
>  > +# Initial frame unwinders.
>  > +frame_unwinders = []
>  > +
>  > +def execute_unwinders(pending_frame):
>  > +    """Internal function called from GDB to execute all unwinders.
>  > +
>  > +    Runs each currently enabled unwinder until it finds the one that
>  > +    can unwind given frame.
>  > +
>  > +    Arguments:
>  > +        pending_frame: gdb.PendingFrame instance.
>  > +    Returns:
>  > +        gdb.UnwindInfo instance or None.
>  > +    """
>  > +    for objfile in objfiles():
>
> It's odd to call objfiles() here and _gdb.current_progspace() below.
> Either the _gdb. prefix is necessary or it is not.
> At the least let's be consistent here.
> How about instead of adding _gdb. prefix here ...
>
>  > +        for unwinder in objfile.frame_unwinders:
>  > +            if unwinder.enabled:
>  > +                unwind_info = unwinder(pending_frame)
>  > +                if unwind_info is not None:
>  > +                    return unwind_info
>  > +
>  > +    current_progspace = _gdb.current_progspace()
>
> .... remove it here.
> [and rerun the testsuite to verify]
>
>  > +    for unwinder in current_progspace.frame_unwinders:
>  > +        if unwinder.enabled:
>  > +            unwind_info = unwinder(pending_frame)
>  > +            if unwind_info is not None:
>  > +                return unwind_info
>  > +
>  > +    for unwinder in frame_unwinders:
>  > +        if unwinder.enabled:
>  > +            unwind_info = unwinder(pending_frame)
>  > +            if unwind_info is not None:
>  > +                return unwind_info
>  > +
>  > +    return None
>  > +
>  >
>  >  # Convenience variable to GDB's python directory
>  >  PYTHONDIR = os.path.dirname(os.path.dirname(__file__))

Attachment: patch11.diff
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]