From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 35953 invoked by alias); 30 Mar 2015 17:45:27 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 26752 invoked by uid 89); 30 Mar 2015 17:45:23 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.7 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_LOW,SPF_PASS,T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mail-ig0-f202.google.com Received: from mail-ig0-f202.google.com (HELO mail-ig0-f202.google.com) (209.85.213.202) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Mon, 30 Mar 2015 17:45:21 +0000 Received: by igam20 with SMTP id m20so6209588iga.1 for ; Mon, 30 Mar 2015 10:45:19 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:mime-version:content-type :content-transfer-encoding:message-id:date:to:cc:subject:in-reply-to :references; bh=7LAOBwvMfCOfBdHCL6mBSnAfinLJ0P3TeRHZHqc8KIg=; b=Gjw6t1ztG8EEhm/pAMlX1+Oi5puujJUqeweXiFSsiXc0eIfqdJ/1l4kxZ9Q8uIfTXo mnD6r35YF7ywQ1m3ClH+DndJcIysnMXC0MTL7kjQlcWC81NujS8gpEohBcXDbgSFBjIz KcCuATuca5sipZasPg+viFYilVMf2e9D3LvTNCqgHwva2vCFsoBr9fAk8DiChpBul0hZ VFgwyDe1kp8TafBPBirxDVKy70w2Y3fmgsPKTdwd2MFTNVgs4OqFHLvRWvLdc0DU/F1q KXt1vi8YIkzSddXO/xPYpkhDnJhgBF17Lt89vaJILRzDEc2BtKefVa4VNltfdd20o6eh akvg== X-Gm-Message-State: ALoCoQnTUGGYQDaF1L4heA0YjXrhjQwbUO4T4HPbTdamUnoZrKiNBfGgk8eRRX/HGjrFxIDcp14AaEBYvlAEif1xS/shGCsNPXRwHT7EmYSpGfDG3eJuR3bdQRZQ1Ur9HZKw8oz7fEC0lnGADeVVzj/BQ9sAf0NnWZLn7Bb20kXjieUxRjnolp8= X-Received: by 10.182.80.7 with SMTP id n7mr38460207obx.10.1427737519707; Mon, 30 Mar 2015 10:45:19 -0700 (PDT) Received: from corpmail-nozzle1-2.hot.corp.google.com ([100.108.1.103]) by gmr-mx.google.com with ESMTPS id d31si462407yhb.1.2015.03.30.10.45.18 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 30 Mar 2015 10:45:19 -0700 (PDT) Received: from ruffy2.mtv.corp.google.com ([172.17.128.107]) by corpmail-nozzle1-2.hot.corp.google.com with ESMTP id 4cF5DMOz.1; Mon, 30 Mar 2015 10:45:19 -0700 From: Doug Evans MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-ID: <21785.35758.416843.730797@ruffy2.mtv.corp.google.com> Date: Mon, 30 Mar 2015 17:45:00 -0000 To: Alexander Smundak Cc: Andy Wingo , gdb-patches Subject: Re: [RFC] [PATCH] Provide the ability to write the frame unwinder in Python In-Reply-To: References: <21714.40641.510825.30998@ruffy2.mtv.corp.google.com> <54E71694.1080304@redhat.com> <87ioei31uj.fsf@igalia.com> <87d24p19tt.fsf@igalia.com> <54FD7DAA.7010603@redhat.com> <87twxrncld.fsf@igalia.com> <87ioe1dvu2.fsf@igalia.com> <87sid4atms.fsf@igalia.com> <87r3smado6.fsf@igalia.com> <21776.28787.615626.171251@ruffy2.mtv.corp.google.com> <21781.55769.949230.79805@ruffy2.mtv.corp.google.com> X-IsSubscribed: yes X-SW-Source: 2015-03/txt/msg01007.txt.bz2 Alexander Smundak writes: > Addressed eliz@ and dje@ comments. > > gdb/ChangeLog > > 2015-03-28 Sasha Smundak > > * 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 > > * 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___() > + > + def __call__(pending_frame): > + if not : > + return None > + # Create UnwindInfo. Usually the frame is identified by the stack > + # pointer and the program counter. > + sp = pending_frame.read_register() > + pc = pending_frame.read_register() > + 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(, ) > + .... > + > + # 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__))