From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8463 invoked by alias); 13 Oct 2011 14:34:12 -0000 Received: (qmail 8290 invoked by uid 22791); 13 Oct 2011 14:34:10 -0000 X-SWARE-Spam-Status: No, hits=-2.1 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,TW_BJ X-Spam-Check-By: sourceware.org Received: from mail-vx0-f169.google.com (HELO mail-vx0-f169.google.com) (209.85.220.169) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 13 Oct 2011 14:33:51 +0000 Received: by vcbfk1 with SMTP id fk1so100195vcb.0 for ; Thu, 13 Oct 2011 07:33:51 -0700 (PDT) Received: by 10.220.213.132 with SMTP id gw4mr306243vcb.52.1318516431120; Thu, 13 Oct 2011 07:33:51 -0700 (PDT) MIME-Version: 1.0 Received: by 10.220.180.75 with HTTP; Thu, 13 Oct 2011 07:33:31 -0700 (PDT) In-Reply-To: References: From: Kevin Pouget Date: Thu, 13 Oct 2011 14:34:00 -0000 Message-ID: Subject: Re: [RFC] Python Finish Breakpoints To: Tom Tromey Cc: gdb-patches@sourceware.org Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-IsSubscribed: yes 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 X-SW-Source: 2011-10/txt/msg00394.txt.bz2 On Mon, May 30, 2011 at 11:28 AM, Kevin Pouget wro= te: >> Kevin> breakpoint.h: >> Kevin> enum py_bp_type >> Kevin> =A0 { >> Kevin> =A0 =A0 py_bp_none, =A0 =A0 =A0 =A0 /* No Python object. =A0*/ >> >> I don't think this one is needed. >> >> Kevin> =A0 =A0 py_bp_standard, =A0 =A0 /* Ordinary breakpoint object. = =A0*/ >> Kevin> =A0 =A0 py_bp_finish =A0 =A0 =A0 =A0/* FinishBreakpoint object. = =A0*/ >> >> These should be uppercase, but it seems to me that if there are just 2 >> states you might as well use an ordinary boolean(-ish) flag. > > OK, I wanted to let a room free for further Python-specific breakpoint > handling, but if you feel like it's not necessary ... > I changed it to "int is_py_finish_bp" > >> Kevin> as per your two comments, I now only store the `struct type' =A0o= f the >> Kevin> function and the return value, >> >> You need to store a gdb.Type wrapper. >> A 'struct type' can also be invalidated when an objfile is destroyed. > > I wouldn't mind, but I can't see how gdb.Type ensures validity, as far > as I've seen, there is no "is_valid" method and I can't and no further > verification during the Python -> C translation: > > struct type * > type_object_to_type (PyObject *obj) > { > =A0if (! PyObject_TypeCheck (obj, &type_object_type)) > =A0 =A0return NULL; > =A0return ((type_object *) obj)->type; > } > > >> Kevin> diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.exp= b/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.exp >> >> Tom> Funny file name. >> >> Kevin> funny but correct, or too funny? ;) >> >> It is more usual in the gdb test suite to give the .cc and .exp files >> the same base name. > > so py-finish-breakpoint2.{exp,cc,py} should look more serious! > >>> Other cases to consider are - >>> * inferior exec >>> * inferior exit >>> * explicit inferior function call >>> * "return" command >> Kevin> I'll work on the tests for the next version of the patch ("return" >> Kevin> should already be covered) >> >> I will wait for this to do more review. > > these situations should now be covered in `'py-finish-breakpoint.exp" > >> Kevin> @defivar FinishBreakpoint out_of_scope_notif >> Kevin> This attribute will be @code{True} until the @code{out_of_scope} = method has >> Kevin> been called and @code{False} afterwards. This attribute is writea= ble, so out >> Kevin> of scope notifications can be re-enabled. >> Kevin> @end defivar >> >> I still don't really understand under what circumstances it is useful >> for a program to set this attribute. >> >> Kevin> - avoid calling `out_of_scope' every normal_stop when the breakpo= int >> Kevin> is not anymore in the callstack >> >> I think it would be ok to just leave this up to the subclass to handle. > > I thought about just getting rid of this part of the patch, but it > really seem important to me. > Here is a (pseudo-code) example to try to demonstrate that: > > function inner (param) { > =A0if (param) > =A0 =A0return 1 > =A0else > =A0 =A0throw exception > } > > function outter (param) { > =A0return innter(param) > } > > function main () { > =A0try: > =A0 =A0outter (TRUE) > =A0except: > =A0 =A0pass > > =A0try: > =A0 =A0outter (FALSE) > =A0except: > =A0 =A0pass > > =A0try: > =A0 =A0outter (TRUE) > =A0except: > =A0 =A0pass > } > > in a Python script, you want to know the return value of OUTTER (in a > script --> you don't know the actual shape of the Main function -- for > instance think about the 'write(2)` function which returns the size of > the data actually written) > > you'll need one gdb.Breakpoint and several gdb.FinishBreakpoint: > > class OutterBreakpoint(gdb.Breakpoint): > =A0def __init__(self): > =A0 =A0gdb.Breakpoint.__init__(self, "outter", internal=3DTrue) > =A0 =A0self.silent =3D True > > =A0def stop(): > =A0 =A0OutterFinishBreakpoint(gdb.newest_frame()) > =A0 =A0return False > > class OutterFinishBreakpoint(gdb.FinishBreakpoint): > =A0def stop(): > =A0 =A0print "outter finished with :", self.return_value > =A0 =A0self.enable =3D False > =A0 =A0gdb.post_event(self.delete) > > =A0def out_of_scope() > =A0 =A0self.enable =3D False > =A0 =A0gdb.post_event(self.delete) > > This `out_of_scope' function is the easiest way to cleanup the > FinishBreakpoint when the finished function didn't return correctly > (and is only useful in this situation, I admit) > >> Kevin> - allow the script to re-activate notification when it wants to >> Kevin> 're-use' the FinishBreakpoint (instead of deleting it / creating = a new >> Kevin> one) >> >> I am not sure when this makes sense. > > that's the opposite situation, you know know the function will only be > triggered from one (limitted set of) place, so you don't want to > create/delete BPs each time: > > > class OutterBreakpoint(gdb.Breakpoint): > =A0... > =A0def stop(): > =A0 =A0if self.finish is None: > =A0 =A0 =A0 =A0self.finish =3D OutterFinishBreakpoint(gdb.newest_frame()) > =A0 =A0return False > > class OutterFinishBreakpoint(gdb.FinishBreakpoint): > =A0... > =A0def stop(): > =A0 =A0 #don't delete > =A0 =A0 #treat normal termination > > =A0def out_of_scope(): > =A0 =A0 #treat exception termination > =A0 =A0 self.out_of_scope_notif =3D True # allows to catch further > exception termination > > > I also added a verification which checks that `out_of_scope' =A0is only > trigged for the inferior for the inferior which owns the breakpoint: > > +bpfinishpy_detect_out_scope_cb (struct breakpoint *b, void *args) > ... > + =A0 =A0 =A0else if (finish_bp->out_of_scope_notif > + =A0 =A0 =A0 =A0 =A0&& b->pspace =3D=3D current_inferior()->pspace > + =A0 =A0 =A0 =A0 =A0&& (!target_has_registers || frame_find_by_id(b->fra= me_id) =3D=3D NULL)) > + =A0 =A0 =A0 =A0{ > + =A0 =A0 =A0 =A0 =A0bpfinishpy_out_of_scope (finish_bp); > + =A0 =A0 =A0 =A0} Hello, I would like to come back on this patch discussion, I know it has been a while since the last post (May 30th), but I was waiting for my copyright assignment to be ready, and then had to empty the patches already in the pipe. it appeared that the most stormy part was related to the FinishBreakpoint.out_of_scope() callback: > @defop Operation {gdb.Breakpoint} out_of_scope (self) > In some circonstances (eg, @code{longjmp}, C++ exceptions, @value{GDBN} > @code{return} command, ...), a function may not properly terminate, and t= hus > never hit a @{code} FinishBreakpoint. When @value{GDBN} notices such a > situation, the @code{out_of_scope} function will be triggered. I'll try a last time to convince you about its necessity, then I'll consider dropping it off ! The main rational behind this callback is housekeeping: I'm building new functionalities on top of the Python interface, and I would like it to be invisible to the user (eg, when GDB performs a 'next/finish', you don't want to let the internal breakpoints in the inferior when the commands returns, in any situation. In the case of FinishBreakpoints, I would like to easily know if when the BP became meaningless (that is, the exec ran out of the scope where the FBP can be trigged) and time has come to remove it. Does it make sense? Thanks, Kevin