From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 10658 invoked by alias); 13 May 2011 09:04:57 -0000 Received: (qmail 10647 invoked by uid 22791); 13 May 2011 09:04:55 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,RFC_ABUSE_POST,T_TO_NO_BRKTS_FREEMAIL X-Spam-Check-By: sourceware.org Received: from mail-vw0-f41.google.com (HELO mail-vw0-f41.google.com) (209.85.212.41) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 13 May 2011 09:04:40 +0000 Received: by vws4 with SMTP id 4so2232633vws.0 for ; Fri, 13 May 2011 02:04:39 -0700 (PDT) Received: by 10.220.124.16 with SMTP id s16mr355706vcr.103.1305277479344; Fri, 13 May 2011 02:04:39 -0700 (PDT) MIME-Version: 1.0 Received: by 10.220.188.139 with HTTP; Fri, 13 May 2011 02:04:19 -0700 (PDT) In-Reply-To: References: From: Kevin Pouget Date: Fri, 13 May 2011 09:04:00 -0000 Message-ID: Subject: Re: [RFC] Python Finish Breakpoints To: gdb@sourceware.org Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-IsSubscribed: yes Mailing-List: contact gdb-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-owner@sourceware.org X-SW-Source: 2011-05/txt/msg00056.txt.bz2 Hello, (sorry for the double post) On Thu, May 12, 2011 at 3:00 PM, Doug Evans wrote: > > Hi. =A0re: > > On Mon, May 9, 2011 at 7:10 AM, Kevin Pouget wro= te: > > Hello, > > > > I would like to discuss with you guys a new Python interface for > > breakpoint handling. Based on the `finish' command, I prepared a > > Python class which allows to catch the return of a given frame. > > Basically, the motivation behind this class is to allow Python script > > to wrap inferior function calls: > > > > with a code like > > int do_something(int *a) > > { > > =A0 *a +=3D 5; > > =A0 sleep(a); > > =A0 return 10; > > } > > which may take a few seconds to execute, there was no way to know the > > updated value of `a' and the return value (`gdb.execute("finish")' > > could do that, but a Ctrl^C during the `sleep' would have screwed up > > your results). > > Plus > > >But globally, my thoughts when I prepared this interface were that it > >shouldn't be much different from a classic breakpoint. I'm not really > >familiar with C++ mechanisms, but I can't see (right now, but I'll > >investigate it) how it differs from setting a BP on the frame above, > >checking for recursion upon BP hit and checking for the scope every > >once in a while. > > This *may* be a reasonable approach in the end, and I am sensitive to > the time invested (that's why I'm replying ... I'd hate for too much > time being spent hacking down a path that ultimately gets abandoned), > but I wonder if another approach would be better. =A0I honestly don't > know if it is, but it feels like it should at least be discussed. > > To me, there's a difference between providing robust handling a > hand-called function finishing and a general "finish" handler. =A0The > semantics are sufficiently different, e.g. w.r.t. > longjmp/c++-exception. > > So first let me ask a clarifying question: Is the main purpose for the > patch to provide robust handling of the different ways an inferior > function call can "exit"? > And if so, maybe (or maybe not, dunno) it would be better to focus on > making that work as desired, as opposed to a general purpose > finish-frame breakpoint handler. > The latter may be sufficiently useful as well of course. =A0At this > point I'd just like to understand the main use-case. thanks for your support, you're right, it appears that I need to explicit what I exactly want to do, which certainly fits in your second proposition, a 'general "finish" handler'. I mainly want to catch normal termination of functions calls, the 'out of scope' notification being almost just a convenient asynchronous / 'best effort' notification. To make it clearer, here is an example of the functionality I want to build up upon FinishBreakpoints: > #include > #include > int > main (int argc, char ** argv) { > -->void * handle =3D dlopen ("/lib64/libm.so.6", RTLD_LAZY); <-- > =A0=A0=A0 if (!handle) { > =A0=A0=A0 =A0=A0=A0 perror("dlopen: "); > =A0=A0=A0 =A0=A0=A0 return 1; > =A0=A0=A0 } > -->double (* cosinus) (double) =3D dlsym (handle, "cos"); <-- > =A0=A0=A0 printf ("%f\n", (* cosinus)(2.0)); > =A0=A0=A0 return 0; > } > (gdb) run > Starting program: /home/kevin/travail/arm/perso/root/sample/gdb-finish/fo= rk > --> DlOpen(0x400768 "/lib64/libm.so.6") =3D 0x601030 <-- > --> DlSym("cos", "/lib64/libm.so.6") =3D 0x3cbd41d580 <-- > -0.416147 > [Inferior 1 (process 8263) exited normally] I want to be able to exploit the interactions between the inferior and a given library (here lib. 'dl'). So in this example, the script (at the bottom of the mail) followed the `dlopen' to catch it's return value > DlOpen(0x400768 "/lib64/libm.so.6") =3D 0x601030 Then it catched the `dlsym' call and worked out the library name matching the handler, and printed the function pointer associated with 'cos'. > DlSym("cos", "/lib64/libm.so.6") =3D 0x3cbd41d580 Let me know if this vision of the feature still looks interesting to you, I'll prepare some tests about the cases Phil mentioned Cordially, Kevin -- import re global dlopen_name global dlopen_handler dlopen_name =3D None dlopen_handler =3D None class DlOpenBreakpoint(gdb.Breakpoint): =A0=A0=A0 def __init__(self): =A0=A0=A0=A0=A0=A0=A0 gdb.Breakpoint.__init__(self, spec=3D"dlopen", intern= al=3D1) =A0=A0=A0=A0=A0=A0=A0 self.silent =3D True =A0=A0=A0 def stop(self): =A0=A0=A0=A0=A0=A0=A0 DlOpenFinishBreakpoint(gdb.newest_frame(), gdb.parse_and_eval("(char*) $rdi")) =A0=A0=A0=A0=A0=A0=A0 return False DlOpenBreakpoint() class DlOpenFinishBreakpoint(gdb.FinishBreakpoint): =A0=A0=A0 def __init__(self, frame, name): =A0=A0=A0=A0=A0=A0=A0 gdb.FinishBreakpoint.__init__(self, frame, internal= =3D1) =A0=A0=A0=A0=A0=A0=A0 self.name =3D name =A0=A0=A0=A0=A0=A0=A0 self.silent =3D True =A0=A0=A0 def stop(self): =A0=A0=A0=A0=A0=A0=A0 global dlopen_name =A0=A0=A0=A0=A0=A0=A0 global dlopen_handler =A0=A0=A0=A0=A0=A0=A0 dlopen_name =3D self.name =A0=A0=A0=A0=A0=A0=A0 dlopen_handler =3D gdb.parse_and_eval("$rax") =A0=A0=A0=A0=A0=A0=A0 print "DlOpen(%s) =3D 0x%x" % (dlopen_name, dlopen_ha= ndler) =A0=A0=A0 def out_of_scope(self): =A0=A0=A0=A0=A0=A0=A0 print "dlopen didn't finish ..." class DlSymBreakpoint(gdb.Breakpoint): =A0=A0=A0 def __init__(self): =A0=A0=A0=A0=A0=A0=A0 gdb.Breakpoint.__init__(self, spec=3D"dlsym", interna= l=3D1) =A0=A0=A0=A0=A0=A0=A0 self.silent =3D True =A0=A0=A0 def stop(self): =A0=A0=A0=A0=A0=A0=A0 global dlopen_name =A0=A0=A0=A0=A0=A0=A0 global dlopen_handler =A0=A0=A0=A0=A0=A0=A0 fct =3D gdb.parse_and_eval("(char *) $rsi") =A0=A0=A0=A0=A0=A0=A0 handler =3D gdb.parse_and_eval("$rdi") =A0=A0=A0=A0=A0=A0=A0 if (dlopen_handler =3D=3D handler): =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 DlSymFinishBreakpoint(gdb.newest_frame(),= fct, dlopen_name) =A0=A0=A0=A0=A0=A0=A0 else: =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 print "Unknown handler" =A0=A0=A0=A0=A0=A0=A0 return False DlSymBreakpoint() class DlSymFinishBreakpoint(gdb.FinishBreakpoint): =A0=A0=A0 def __init__(self, frame, fct, lib): =A0=A0=A0=A0=A0=A0=A0 gdb.FinishBreakpoint.__init__(self, frame, internal= =3D1) =A0=A0=A0=A0=A0=A0=A0 self.fct =3D fct =A0=A0=A0=A0=A0=A0=A0 self.lib =3D lib =A0=A0=A0=A0=A0=A0=A0 self.silent =3D True =A0=A0=A0 def stop(self): =A0=A0=A0=A0=A0=A0=A0 fct_addr =3D gdb.parse_and_eval("$rax") =A0=A0=A0=A0=A0=A0=A0 print "DlSym(%s, %s) =3D 0x%x" % (self.fct, self.lib,= fct_addr)