From: Doug Evans <dje@google.com>
To: Alexander Smundak <asmundak@google.com>
Cc: Andy Wingo <wingo@igalia.com>,
gdb-patches <gdb-patches@sourceware.org>
Subject: Re: [RFC] [PATCH] Provide the ability to write the frame unwinder in Python
Date: Mon, 30 Mar 2015 17:45:00 -0000 [thread overview]
Message-ID: <21785.35758.416843.730797@ruffy2.mtv.corp.google.com> (raw)
In-Reply-To: <CAHQ51u5=mNXcA_CY4hQuvVHSKuMbaVUYyHvhrgZEUJZdX2iL8Q@mail.gmail.com>
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__))
next prev parent reply other threads:[~2015-03-30 17:45 UTC|newest]
Thread overview: 60+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-12-15 18:14 Alexander Smundak
2014-12-22 19:24 ` Alexander Smundak
2014-12-29 18:02 ` Alexander Smundak
2015-01-05 17:53 ` Alexander Smundak
2015-01-12 20:03 ` Alexander Smundak
2015-01-22 3:31 ` Alexander Smundak
2015-01-29 1:36 ` Alexander Smundak
2015-01-12 21:00 ` Simon Marchi
2015-01-12 21:22 ` Doug Evans
2015-02-04 22:36 ` Doug Evans
2015-02-12 17:58 ` Alexander Smundak
2015-02-19 2:32 ` Alexander Smundak
2015-02-20 11:12 ` Phil Muldoon
2015-02-26 3:09 ` Alexander Smundak
2015-03-02 22:56 ` Alexander Smundak
2015-03-03 8:46 ` Andy Wingo
2015-03-04 2:36 ` Alexander Smundak
2015-03-04 7:49 ` Andy Wingo
2015-03-09 11:02 ` Phil Muldoon
2015-03-11 2:22 ` Alexander Smundak
2015-03-11 8:49 ` Andy Wingo
2015-03-11 17:34 ` Doug Evans
2015-03-11 18:48 ` Alexander Smundak
2015-03-16 11:29 ` Andy Wingo
2015-03-16 12:01 ` Andy Wingo
2015-03-16 17:25 ` Alexander Smundak
2015-03-17 8:57 ` Andy Wingo
2015-03-17 19:48 ` Alexander Smundak
2015-03-17 21:37 ` Alexander Smundak
2015-03-18 8:54 ` Andy Wingo
2015-03-18 22:57 ` Alexander Smundak
2015-03-23 19:58 ` Doug Evans
2015-03-24 9:06 ` Andy Wingo
2015-03-26 3:31 ` Alexander Smundak
2015-03-26 18:53 ` Eli Zaretskii
2015-03-27 22:29 ` Doug Evans
2015-03-28 1:10 ` Alexander Smundak
2015-03-30 17:45 ` Doug Evans [this message]
2015-03-30 19:49 ` Alexander Smundak
2015-03-31 22:36 ` Doug Evans
2015-04-01 0:09 ` Alexander Smundak
2015-04-01 0:28 ` Doug Evans
2015-03-18 23:25 ` Doug Evans
2015-03-19 0:36 ` Alexander Smundak
2015-03-19 8:12 ` Andy Wingo
2015-03-20 0:15 ` Doug Evans
2015-03-20 2:27 ` Alexander Smundak
2015-03-20 17:48 ` Doug Evans
2015-03-20 8:26 ` Andy Wingo
2015-03-20 18:32 ` Doug Evans
2015-03-17 22:21 ` Doug Evans
2015-03-18 8:57 ` Andy Wingo
2015-03-18 16:48 ` Doug Evans
2015-03-19 8:04 ` Andy Wingo
2015-03-09 9:42 ` Andy Wingo
2015-03-03 0:49 ` Alexander Smundak
2015-03-03 14:38 ` Andy Wingo
2015-03-04 2:52 ` Alexander Smundak
2015-02-20 9:42 ` Phil Muldoon
2015-02-20 9:59 ` Phil Muldoon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=21785.35758.416843.730797@ruffy2.mtv.corp.google.com \
--to=dje@google.com \
--cc=asmundak@google.com \
--cc=gdb-patches@sourceware.org \
--cc=wingo@igalia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).