From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29203 invoked by alias); 11 May 2011 07:44:28 -0000 Received: (qmail 29165 invoked by uid 22791); 11 May 2011 07:44:22 -0000 X-SWARE-Spam-Status: No, hits=-0.9 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,KAM_STOCKGEN,RCVD_IN_DNSWL_LOW,RFC_ABUSE_POST,TW_BJ,TW_BP,TW_EG,TW_WB,TW_YB,T_FILL_THIS_FORM_SHORT,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; Wed, 11 May 2011 07:44:03 +0000 Received: by vws4 with SMTP id 4so204263vws.0 for ; Wed, 11 May 2011 00:44:02 -0700 (PDT) Received: by 10.52.99.103 with SMTP id ep7mr1245170vdb.68.1305099841317; Wed, 11 May 2011 00:44:01 -0700 (PDT) MIME-Version: 1.0 Received: by 10.220.61.6 with HTTP; Wed, 11 May 2011 00:43:41 -0700 (PDT) In-Reply-To: References: From: Kevin Pouget Date: Wed, 11 May 2011 07:44:00 -0000 Message-ID: Subject: Re: [RFC] Python Finish Breakpoints To: gdb@sourceware.org, 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-05/txt/msg00274.txt.bz2 Any feedback ... ? On Mon, May 9, 2011 at 10:10 AM, Kevin Pouget wrot= e: > 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). > > > The patch is not supposed to be complete, no CHANGELOG, no > documentation, and certainly more unit tests required, but that will > be ready soon. > > the class gdb.FinishBreakpoint extends gdb.Breakpoint > > the function FinishBreakpoint.__init__ takes the frame to finish as param= eter, > > the function FinishBreakpoint.stop is triggered as usual (gdb.Breakpoint) > > the function FinishBreakpoint.out_of_scope is triggered when GDB > notices (by observing STOP events) that the breakpointed frame is not > in the callstack anymore and GDB did not hit the breakpoint yet > (namely after a `return' command) > > the attribute FinishBreakpoint.out_of_scoped is a flag indicating > whether the breakpointed frame is still the callstack > > * by breakpointed frame I mean the frame into which the breakpoint is > set, not the one that we want to finish (because of sibling calls). > Currently, reading the value of `FinishBreakpoint.out_of_scoped' > actually check if the frame exists and update the value. IF it is not > (=3DTrue), the callback is not triggered, and won't be, until > `out_of_scoped' is re-enabled (set to False) > > > the attribute FinishBreakpoint.return_value gives, if GDB is stopped > at a FinishBreakpoint, the gdb.Value object corresponding to the > return value. > there is one problem behind this function, I had to change the code: > > +++ b/gdb/infrun.c > @@ -5826,7 +5826,7 @@ normal_stop (void) > =A0 /* Save the function value return registers, if we care. > =A0 =A0 =A0We might be about to restore their previous contents. =A0*/ > - =A0if (inferior_thread ()->control.proceed_to_finish) > + =A0/*if (inferior_thread ()->control.proceed_to_finish)*/ > =A0 =A0... > =A0 =A0stop_registers =3D regcache_dup (get_current_regcache ()); > > to correctly set `stop_registers', but I don't really know the > implication of this modification ... > > the testsuite gives some examples about how it works here is a version of the patch which better reflects what I described, some parts were missing in the former post. Kevin -- =46rom 94c7e70354b4eef80352c6306365f37339bc1a5e Mon Sep 17 00:00:00 2001 From: Kevin Pouget Date: Mon, 9 May 2011 15:20:48 -0400 Subject: [PATCH] Python Finish Breakpoints --- =A0gdb/Makefile.in =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 | =A0 =A06 + =A0gdb/breakpoint.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0| =A0 =A02 +- =A0gdb/breakpoint.h =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0| =A0 10 + =A0gdb/infcmd.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0| =A0 19 +- =A0gdb/inferior.h =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0| =A0 =A03 + =A0gdb/infrun.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0| =A0 =A02 +- =A0gdb/python/py-breakpoint.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0| =A0 79 ++--- =A0gdb/python/py-breakpoint.h =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0| =A0 61 ++++ =A0gdb/python/py-finishbreakpoint.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| = =A0384 +++++++++++++++++++++ =A0gdb/python/py-frame.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 | =A0 32 +- =A0gdb/python/python-internal.h =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= | =A0 =A03 + =A0gdb/python/python.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 | =A0 =A01 + =A0gdb/testsuite/gdb.python/py-breakpoint.c =A0 =A0 =A0 =A0 =A0| =A0 16 +- =A0gdb/testsuite/gdb.python/py-breakpoint.exp =A0 =A0 =A0 =A0| =A0 =A07 +- =A0gdb/testsuite/gdb.python/py-finish-breakpoint.exp | =A0 63 ++++ =A0gdb/testsuite/gdb.python/py-finish-breakpoint.py =A0| =A0 21 ++ =A016 files changed, 629 insertions(+), 80 deletions(-) =A0create mode 100644 gdb/python/py-breakpoint.h =A0create mode 100644 gdb/python/py-finishbreakpoint.c =A0create mode 100644 gdb/testsuite/gdb.python/py-finish-breakpoint.exp =A0create mode 100644 gdb/testsuite/gdb.python/py-finish-breakpoint.py diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 5bab360..3955b38 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -279,6 +279,7 @@ SUBDIR_PYTHON_OBS =3D \ =A0 =A0 =A0 =A0py-block.o \ =A0 =A0 =A0 =A0py-bpevent.o \ =A0 =A0 =A0 =A0py-breakpoint.o \ + =A0 =A0 =A0 py-finishbreakpoint.o \ =A0 =A0 =A0 =A0py-cmd.o \ =A0 =A0 =A0 =A0py-continueevent.o \ =A0 =A0 =A0 =A0py-event.o \ @@ -309,6 +310,7 @@ SUBDIR_PYTHON_SRCS =3D \ =A0 =A0 =A0 =A0python/py-block.c \ =A0 =A0 =A0 =A0python/py-bpevent.c \ =A0 =A0 =A0 =A0python/py-breakpoint.c \ + =A0 =A0 =A0 python/py-finishbreakpoint.c \ =A0 =A0 =A0 =A0python/py-cmd.c \ =A0 =A0 =A0 =A0python/py-continueevent.c \ =A0 =A0 =A0 =A0python/py-event.c \ @@ -2038,6 +2040,10 @@ py-breakpoint.o: $(srcdir)/python/py-breakpoint.c =A0 =A0 =A0 =A0$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpoint.c =A0 =A0 =A0 =A0$(POSTCOMPILE) +py-finishbreakpoint.o: $(srcdir)/python/py-finishbreakpoint.c + =A0 =A0 =A0 $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-finishbreakpo= int.c + =A0 =A0 =A0 $(POSTCOMPILE) + =A0py-cmd.o: $(srcdir)/python/py-cmd.c =A0 =A0 =A0 =A0$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-cmd.c =A0 =A0 =A0 =A0$(POSTCOMPILE) diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index b5fc448..eff5e23 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -7330,7 +7330,7 @@ bp_loc_is_permanent (struct bp_location *loc) =A0 =A0as textual description of the location, and COND_STRING =A0 =A0as condition expression. =A0*/ -static void +void =A0create_breakpoint_sal (struct gdbarch *gdbarch, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct symtabs_and_lines sals, = char *addr_string, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 char *cond_string, diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 7a9c2d4..a003651 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -986,6 +986,16 @@ extern int create_breakpoint (struct gdbarch *gdbarch, char *arg, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int enabled, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int internal); +extern void create_breakpoint_sal (struct gdbarch *gdbarch, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struc= t symtabs_and_lines sals, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 char = *addr_string, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 char = *cond_string, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 enum = bptype type, enum bpdisp disposition, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int t= hread, int task, int ignore_count, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struc= t breakpoint_ops *ops, int from_tty, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int e= nabled, int internal, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int d= isplay_canonical); + =A0extern void insert_breakpoints (void); =A0extern int remove_breakpoints (void); diff --git a/gdb/infcmd.c b/gdb/infcmd.c index fce1e8f..c19a04b 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -1378,14 +1378,12 @@ advance_command (char *arg, int from_tty) =A0 until_break_command (arg, from_tty, 1); =A0} -/* Print the result of a function at the end of a 'finish' command. =A0*/ +/* Returns the value of the result at the end of a 'finish' command/BP. = =A0*/ -static void -print_return_value (struct type *func_type, struct type *value_type) +struct value * +get_return_value (struct type *func_type, struct type *value_type) =A0{ =A0 struct gdbarch *gdbarch =3D get_regcache_arch (stop_registers); - =A0struct cleanup *old_chain; - =A0struct ui_stream *stb; =A0 struct value *value; =A0 CHECK_TYPEDEF (value_type); @@ -1415,6 +1413,17 @@ print_return_value (struct type *func_type, struct type *value_type) =A0 =A0 =A0 internal_error (__FILE__, __LINE__, _("bad switch")); =A0 =A0 } + =A0return value; +} +/* Print the result of a function at the end of a 'finish' command. =A0*/ + +static void +print_return_value (struct type *func_type, struct type *value_type) +{ + =A0struct value *value =3D get_return_value(func_type, value_type); + =A0struct cleanup *old_chain; + =A0struct ui_stream *stb; + =A0 if (value) =A0 =A0 { =A0 =A0 =A0 struct value_print_options opts; diff --git a/gdb/inferior.h b/gdb/inferior.h index f8adb6c..b8d5b13 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -285,6 +285,9 @@ extern void detach_command (char *, int); =A0extern void notice_new_inferior (ptid_t, int, int); +extern struct value *get_return_value (struct type *func_type, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 struct type *value_type); + =A0/* Address at which inferior stopped. =A0*/ =A0extern CORE_ADDR stop_pc; diff --git a/gdb/infrun.c b/gdb/infrun.c index 2d6d523..11fd0da 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -5826,7 +5826,7 @@ normal_stop (void) =A0 /* Save the function value return registers, if we care. =A0 =A0 =A0We might be about to restore their previous contents. =A0*/ - =A0if (inferior_thread ()->control.proceed_to_finish) + =A0/*if (inferior_thread ()->control.proceed_to_finish)*/ =A0 =A0 { =A0 =A0 =A0 /* This should not be necessary. =A0*/ =A0 =A0 =A0 if (stop_registers) diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c index 9c33848..db2c411 100644 --- a/gdb/python/py-breakpoint.c +++ b/gdb/python/py-breakpoint.c @@ -17,6 +17,8 @@ =A0 =A0You should have received a copy of the GNU General Public License =A0 =A0along with this program. =A0If not, see . =A0*/ + + =A0#include "defs.h" =A0#include "value.h" =A0#include "exceptions.h" @@ -30,53 +32,18 @@ =A0#include "ada-lang.h" =A0#include "arch-utils.h" =A0#include "language.h" - -static PyTypeObject breakpoint_object_type; +#include "py-breakpoint.h" =A0/* Number of live breakpoints. =A0*/ =A0static int bppy_live; =A0/* Variables used to pass information between the Breakpoint =A0 =A0constructor and the breakpoint-created hook function. =A0*/ -static breakpoint_object *bppy_pending_object; +breakpoint_object *bppy_pending_object; =A0/* Function that is called when a Python condition is evaluated. =A0*/ =A0static char * const stop_func =3D "stop"; -struct breakpoint_object -{ - =A0PyObject_HEAD - - =A0/* The breakpoint number according to gdb. =A0*/ - =A0int number; - - =A0/* The gdb breakpoint object, or NULL if the breakpoint has been - =A0 =A0 deleted. =A0*/ - =A0struct breakpoint *bp; -}; - -/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python - =A0 exception if it is invalid. =A0*/ -#define BPPY_REQUIRE_VALID(Breakpoint) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 \ - =A0 =A0do { =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \ - =A0 =A0 =A0if ((Breakpoint)->bp =3D=3D NULL) =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\ - =A0 =A0 =A0 return PyErr_Format (PyExc_RuntimeError, =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0\ - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0_("Breakpoint %d i= s invalid."), =A0 =A0 =A0 =A0 =A0 =A0\ - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(Breakpoint)->numb= er); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \ - =A0 =A0} while (0) - -/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python - =A0 exception if it is invalid. =A0This macro is for use in setter functi= ons. =A0*/ -#define BPPY_SET_REQUIRE_VALID(Breakpoint) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 \ - =A0 =A0do { =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \ - =A0 =A0 =A0if ((Breakpoint)->bp =3D=3D NULL) =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\ - =A0 =A0 =A0 =A0{ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\ - =A0 =A0 =A0 =A0 PyErr_Format (PyExc_RuntimeError, _("Breakpoint %d is inv= alid."), \ - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (Breakpoint)->number); =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\ - =A0 =A0 =A0 =A0 return -1; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\ - =A0 =A0 =A0 } =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \ - =A0 =A0} while (0) - =A0/* This is used to initialize various gdb.bp_* constants. =A0*/ =A0struct pybp_code =A0{ @@ -806,21 +773,25 @@ gdbpy_breakpoint_created (struct breakpoint *bp) =A0 =A0 } =A0 else =A0 =A0 newbp =3D PyObject_New (breakpoint_object, &breakpoint_object_type); - =A0if (newbp) - =A0 =A0{ - =A0 =A0 =A0newbp->number =3D bp->number; - =A0 =A0 =A0newbp->bp =3D bp; - =A0 =A0 =A0newbp->bp->py_bp_object =3D newbp; - =A0 =A0 =A0Py_INCREF (newbp); - =A0 =A0 =A0++bppy_live; - =A0 =A0} - =A0else - =A0 =A0{ - =A0 =A0 =A0PyErr_SetString (PyExc_RuntimeError, - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0_("Error while creating breakp= oint from GDB.")); - =A0 =A0 =A0gdbpy_print_stack (); - =A0 =A0} + + =A0if (!newbp) + =A0 =A0goto fail; + + =A0newbp->number =3D bp->number; + =A0newbp->bp =3D bp; + =A0newbp->bp->py_bp_object =3D newbp; + + =A0Py_INCREF (newbp); + =A0++bppy_live; + + =A0goto success; + +fail: + =A0PyErr_SetString (PyExc_RuntimeError, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Error while creating breakpoint fr= om GDB.")); + =A0gdbpy_print_stack (); +success: =A0 PyGILState_Release (state); =A0} @@ -971,14 +942,14 @@ static PyMethodDef breakpoint_object_methods[] =3D =A0 { NULL } /* Sentinel. =A0*/ =A0}; -static PyTypeObject breakpoint_object_type =3D +PyTypeObject breakpoint_object_type =3D =A0{ =A0 PyObject_HEAD_INIT (NULL) =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*ob_size*/ =A0 "gdb.Breakpoint", =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_name*/ =A0 sizeof (breakpoint_object), =A0 =A0/*tp_basicsize*/ =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*tp_itemsiz= e*/ - =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*tp_deallo= c*/ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_dea= lloc*/ =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*tp_print*/ =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*tp_getattr= */ =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*tp_setattr= */ @@ -1008,7 +979,7 @@ static PyTypeObject breakpoint_object_type =3D =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_dict */ =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_descr_= get */ =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_descr_= set */ - =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_dicto= ffset */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_di= ctoffset */ =A0 bppy_init, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_init */ =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_alloc = */ =A0 PyType_GenericNew =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_new */ diff --git a/gdb/python/py-breakpoint.h b/gdb/python/py-breakpoint.h new file mode 100644 index 0000000..827f488 --- /dev/null +++ b/gdb/python/py-breakpoint.h @@ -0,0 +1,61 @@ +/* Python interface to breakpoints + + =A0 Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc. + + =A0 This file is part of GDB. + + =A0 This program is free software; you can redistribute it and/or modify + =A0 it under the terms of the GNU General Public License as published by + =A0 the Free Software Foundation; either version 3 of the License, or + =A0 (at your option) any later version. + + =A0 This program is distributed in the hope that it will be useful, + =A0 but WITHOUT ANY WARRANTY; without even the implied warranty of + =A0 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =A0See the + =A0 GNU General Public License for more details. + + =A0 You should have received a copy of the GNU General Public License + =A0 along with this program. =A0If not, see . =A0*/ + +#ifndef GDB_PY_BREAKPOINT_H +#define GDB_PY_BREAKPOINT_H + +/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python + =A0 exception if it is invalid. =A0*/ +#define BPPY_REQUIRE_VALID(Breakpoint) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\ + =A0 =A0do { =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\ + =A0 =A0 =A0if ((Breakpoint)->bp =3D=3D NULL) =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \ + =A0 =A0 =A0 =A0return PyErr_Format (PyExc_RuntimeError, =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\ + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Breakpoint %d = is invalid."), =A0 =A0 =A0 =A0 =A0 =A0\ + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (Breakpoint)->num= ber); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \ + =A0 =A0} while (0) + +/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python + =A0 exception if it is invalid. =A0This macro is for use in setter functi= ons. =A0*/ +#define BPPY_SET_REQUIRE_VALID(Breakpoint) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0\ + =A0 =A0do { =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\ + =A0 =A0 =A0if ((Breakpoint)->bp =3D=3D NULL) =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \ + =A0 =A0 =A0 =A0{ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \ + =A0 =A0 =A0 =A0 =A0PyErr_Format (PyExc_RuntimeError, _("Breakpoint %d is = invalid."), \ + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(Breakpoint)->number); =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\ + =A0 =A0 =A0 =A0 =A0return -1; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0\ + =A0 =A0 =A0 =A0} =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 \ + =A0 =A0} while (0) + +struct breakpoint_object +{ + =A0PyObject_HEAD + + =A0/* The breakpoint number according to gdb. =A0*/ + =A0int number; + + =A0/* The gdb breakpoint object, or NULL if the breakpoint has been + =A0 =A0 deleted. =A0*/ + =A0struct breakpoint *bp; +}; + +/* Variables used to pass information between the Breakpoint + =A0 constructor and the breakpoint-created hook function. =A0*/ +extern breakpoint_object *bppy_pending_object; + +#endif /* GDB_PY_BREAKPOINT_H */ diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpo= int.c new file mode 100644 index 0000000..bccb69f --- /dev/null +++ b/gdb/python/py-finishbreakpoint.c @@ -0,0 +1,384 @@ +/* Python interface to finish breakpoints + + =A0 Copyright (C) 2011 Free Software Foundation, Inc. + + =A0 This file is part of GDB. + + =A0 This program is free software; you can redistribute it and/or modify + =A0 it under the terms of the GNU General Public License as published by + =A0 the Free Software Foundation; either version 3 of the License, or + =A0 (at your option) any later version. + + =A0 This program is distributed in the hope that it will be useful, + =A0 but WITHOUT ANY WARRANTY; without even the implied warranty of + =A0 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =A0See the + =A0 GNU General Public License for more details. + + =A0 You should have received a copy of the GNU General Public License + =A0 along with this program. =A0If not, see . =A0*/ + + + +#include "defs.h" +#include "exceptions.h" +#include "python-internal.h" +#include "breakpoint.h" +#include "py-breakpoint.h" +#include "frame.h" +#include "gdbthread.h" +#include "arch-utils.h" +#include "language.h" +#include "observer.h" +#include "inferior.h" + +static PyTypeObject finish_breakpoint_object_type; + +/* Function that is called when a Python finish bp is found out of scope. = =A0*/ +static char * const outofscope_func =3D "out_of_scope"; + +/* struct implementing the gdb.FinishBreakpoint object by extending + =A0 the gdb.Breakpoint class. =A0*/ +struct finish_breakpoint_object +{ + =A0/* gdb.Breakpoint base class. =A0*/ + =A0struct breakpoint_object py_bp; + =A0/* Flag indicating that the BP is out of the callstack and Python call= back + =A0 =A0 has been triggered. =A0*/ + =A0int out_of_scoped; + =A0/* The function finished by this breakpoint. =A0*/ + =A0struct symbol *function; +}; + +/* Python function to set the 'out_of_scoped' attribute of + =A0 FinishBreakpoint. =A0*/ + +static int +bpfinishpy_set_outofscoped (PyObject *self, PyObject *newvalue, void *clos= ure) +{ + =A0struct finish_breakpoint_object *self_finishbp =3D + =A0 =A0 =A0(struct finish_breakpoint_object *) self; + =A0int cmp; + + =A0BPPY_SET_REQUIRE_VALID (&self_finishbp->py_bp); + + =A0if (newvalue =3D=3D NULL) + =A0 =A0{ + =A0 =A0 =A0PyErr_SetString (PyExc_TypeError, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Cannot delete `out_of_scop= ed' attribute.")); + =A0 =A0 =A0return -1; + =A0 =A0} + =A0else if (! PyBool_Check (newvalue)) + =A0 =A0{ + =A0 =A0 =A0PyErr_SetString (PyExc_TypeError, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("The value of `out_of_scope= d' must be a boolean.")); + =A0 =A0 =A0return -1; + =A0 =A0} + + =A0cmp =3D PyObject_IsTrue (newvalue); + =A0if (cmp < 0) + =A0 =A0return -1; + =A0else + =A0 =A0self_finishbp->out_of_scoped =3D cmp; + + =A0return 0; +} + +/* Python function to update and get the 'out_of_scoped' attribute + =A0 of FinishBreakpoint. =A0*/ + +static PyObject * +bpfinishpy_get_outofscoped (PyObject *self, void *closure) +{ + =A0struct finish_breakpoint_object *self_finishbp =3D + =A0 =A0 =A0(struct finish_breakpoint_object *) self; + + =A0BPPY_REQUIRE_VALID (&self_finishbp->py_bp); + + =A0if (!self_finishbp->out_of_scoped) + =A0 =A0self_finishbp->out_of_scoped =3D + =A0 =A0 =A0 =A0frame_find_by_id(self_finishbp->py_bp.bp->frame_id) =3D=3D= NULL ; + + =A0if (self_finishbp->out_of_scoped) + =A0 =A0Py_RETURN_TRUE; + =A0Py_RETURN_FALSE; +} + +/* Python function to get the 'return_value' attribute of + =A0 FinishBreakpoint. =A0*/ + +static PyObject * +bpfinishpy_get_returnvalue (PyObject *self, void *closure) +{ + =A0struct finish_breakpoint_object *self_finishbp =3D + =A0 =A0 =A0(struct finish_breakpoint_object *) self; + + =A0BPPY_REQUIRE_VALID (&self_finishbp->py_bp); + + =A0if (self_finishbp->function =3D=3D NULL) + =A0 =A0goto return_none; + + =A0/* Ensure that GDB is stopped at this FinishBreakpoint. =A0*/ + =A0if (inferior_thread ()->control.stop_bpstat !=3D NULL) + =A0 =A0{ + =A0 =A0 =A0bpstat bs; + + =A0 =A0 =A0for(bs =3D inferior_thread ()->control.stop_bpstat; + =A0 =A0 =A0 =A0 =A0bs; bs =3D bs->next) + =A0 =A0 =A0 =A0{ + =A0 =A0 =A0 =A0 =A0struct breakpoint *bp =3D bs->breakpoint_at; + =A0 =A0 =A0 =A0 =A0if (bp !=3D NULL + =A0 =A0 =A0 =A0 =A0 =A0 =A0&& (PyObject *) bp->py_bp_object =3D=3D self) + =A0 =A0 =A0 =A0 =A0 =A0{ + =A0 =A0 =A0 =A0 =A0 =A0 =A0struct type *v_type; + + =A0 =A0 =A0 =A0 =A0 =A0 =A0v_type =3D TYPE_TARGET_TYPE (SYMBOL_TYPE + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(self_finishbp->function)); + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (!v_type) + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0internal_error (__FILE__, __LINE__, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("bpfinishpy_get_returnvalue: function h= as no target type")); + + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (TYPE_CODE (v_type) !=3D TYPE_CODE_VOID) + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct value *ret =3D get_return_value + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(SYMBOL_TYPE (self_finishbp->f= unction), v_type); + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0PyObject *return_value =3D value_to_va= lue_object (ret); + + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Py_INCREF (return_value); + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return return_value; + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} + =A0 =A0 =A0 =A0 =A0 =A0 =A0else + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto return_none; + =A0 =A0 =A0 =A0 =A0 =A0} + =A0 =A0 =A0 =A0} + =A0 =A0} + +return_none: + =A0Py_INCREF (Py_None); + =A0return Py_None ; +} + +/* Called when GDB notices that the finish breakpoint BP_OBJ is out of + =A0 the current callstack. If BP_OBJ has the attribute OUT_OF_SCOPED and + =A0 its value is FALSE, trigger the method OUT_OF_SCOPE and set the flag = to + =A0 TRUE. =A0*/ + +void +gdbpy_out_of_scope (struct finish_breakpoint_object *bpfinish_obj) +{ + =A0breakpoint_object *bp_obj =3D (breakpoint_object *) bpfinish_obj; + =A0PyObject *py_obj =3D (PyObject *) bp_obj ; + + =A0if (PyObject_HasAttrString (py_obj, outofscope_func)) + =A0 =A0{ + =A0 =A0 =A0struct gdbarch *garch =3D =A0bp_obj->bp->gdbarch ? + =A0 =A0 =A0 =A0 =A0bp_obj->bp->gdbarch : get_current_arch (); + =A0 =A0 =A0struct cleanup *cleanup =3D ensure_python_env (garch, current_= language); + + =A0 =A0 =A0if (!PyObject_CallMethod (py_obj, outofscope_func, NULL)) + =A0 =A0 =A0 =A0 =A0gdbpy_print_stack (); + + =A0 =A0 =A0do_cleanups (cleanup); + =A0 =A0} + =A0bpfinish_obj->out_of_scoped =3D 1; +} + +/* Python function to create a new breakpoint. =A0*/ + +static int +bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs) +{ + =A0static char *keywords[] =3D { "frame", "internal", NULL }; + =A0breakpoint_object *self_bp =3D (breakpoint_object *) self; + =A0struct finish_breakpoint_object *self_bpfinish =3D + =A0 =A0 =A0(struct finish_breakpoint_object *) self; + =A0int type =3D bp_breakpoint; + =A0PyObject *frame_obj =3D NULL; + =A0struct frame_info *frame, *prev_frame; + =A0struct frame_id frame_id; + =A0struct symtabs_and_lines sals; + =A0struct symtab_and_line sal; + =A0PyObject *internal =3D NULL; + =A0int internal_bp =3D 0; + =A0CORE_ADDR pc ; + =A0volatile struct gdb_exception except; + + =A0if (! PyArg_ParseTupleAndKeywords (args, kwargs, "O|O", keywords, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &= frame_obj, &internal)) + =A0 =A0return -1; + + =A0if (!frame_obj) + =A0 =A0goto invalid_frame; + + =A0frame =3D frame_object_to_frame_info (frame_obj); + =A0if (frame =3D=3D NULL) + =A0 =A0goto invalid_frame; + + =A0prev_frame =3D get_prev_frame(frame); + =A0if (prev_frame =3D=3D 0) + =A0 =A0{ + =A0 =A0 =A0PyErr_SetString (PyExc_ValueError, + =A0 =A0 =A0 =A0 =A0 _("\"FinishBreakpoint\" not meaningful in the outermo= st frame.")); + =A0 =A0 =A0return -1; + =A0 =A0} + + =A0frame_id =3D get_frame_id (prev_frame); + =A0if (frame_id_eq(frame_id, null_frame_id)) + =A0 =A0goto invalid_frame; + + =A0pc =3D get_frame_pc (prev_frame); + + =A0sal =3D find_pc_line (pc, 0); + =A0sal.pc =3D pc; + =A0sals.sals =3D &sal; + =A0sals.nelts =3D 1; + + =A0/* Find the function we will return from. =A0*/ + =A0self_bpfinish->function =3D find_pc_function (get_frame_pc (frame)); + + =A0if (internal) + =A0 =A0{ + =A0 =A0 =A0internal_bp =3D PyObject_IsTrue (internal); + =A0 =A0 =A0if (internal_bp =3D=3D -1) + =A0 =A0 =A0 =A0{ + =A0 =A0 =A0 =A0 =A0PyErr_SetString (PyExc_ValueError, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("The value of `inte= rnal' must be a boolean.")); + =A0 =A0 =A0 =A0 =A0return -1; + =A0 =A0 =A0 =A0} + =A0 =A0} + + =A0bppy_pending_object =3D self_bp; + =A0bppy_pending_object->number =3D -1; + =A0bppy_pending_object->bp =3D NULL; + + =A0TRY_CATCH (except, RETURN_MASK_ALL) + =A0 =A0{ + =A0 =A0 =A0create_breakpoint_sal (python_gdbarch, sals, NULL, NULL, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bp_breakpoint, di= sp_donttouch, -1, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 0, 0, NULL, 0, 1,= internal_bp, 0) ; + =A0 =A0} + =A0if (except.reason < 0) + =A0 =A0{ + =A0 =A0 =A0PyErr_Format (except.reason =3D=3D RETURN_QUIT + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0? PyExc_KeyboardInterrupt : PyExc_= RuntimeError, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"%s", except.message); + =A0 =A0 =A0return -1; + =A0 =A0} + =A0BPPY_SET_REQUIRE_VALID (self_bp); + + =A0self_bp->bp->frame_id =3D frame_id; + + =A0self_bpfinish->out_of_scoped =3D 0; + + =A0return 0; + +invalid_frame: + =A0PyErr_SetString (PyExc_ValueError, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Invalid ID for the `frame' object.= ")); + =A0return -1; +} + +/* Callback for `bpfinishpy_detect_out_scope'*/ + +static int +bpfinishpy_detect_out_scope_cb (struct breakpoint *b, void *args) +{ + =A0struct breakpoint *bp_stopped =3D (struct breakpoint *) args; + =A0PyObject *py_bp =3D (PyObject *) b->py_bp_object; + =A0PyGILState_STATE state; + + =A0/* Prevent python SEGFAULT because of missing thread state. =A0*/ + =A0state =3D PyGILState_Ensure(); + + =A0/* Trigger out_of_scope notification if this is a FinishBreakpoint + =A0 =A0 and GDB is stopped at this bp or its frame is not in the current + =A0 =A0 callstack and the notification has not been sent yet. =A0*/ + =A0if (py_bp !=3D NULL + =A0 =A0 =A0&& PyObject_TypeCheck (py_bp, &finish_breakpoint_object_type) + =A0 =A0 =A0&& (b =3D=3D bp_stopped || frame_find_by_id(b->frame_id) =3D= =3D NULL) + =A0 =A0 =A0&& !((struct finish_breakpoint_object *) py_bp)->out_of_scoped) + =A0 =A0{ + =A0 =A0 =A0gdbpy_out_of_scope ((struct finish_breakpoint_object *) py_bp); + =A0 =A0} + + =A0PyGILState_Release (state); + + =A0return 0; +} + +/* Attached to `stop' notifications, check if the execution has run out + =A0 out of the scope of any FinishBreakpoint before it has been hit. =A0*/ + +static void +bpfinishpy_handle_stop (struct bpstats *bs, int print_frame) +{ + =A0iterate_over_breakpoints (bpfinishpy_detect_out_scope_cb, + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0bs =3D=3D NULL ? N= ULL : bs->breakpoint_at); +} + +/* Initialize the Python finish breakpoint code. =A0*/ + +void +gdbpy_initialize_finishbreakpoints (void) +{ + =A0if (PyType_Ready (&finish_breakpoint_object_type) < 0) + =A0 =A0 =A0return; + + =A0Py_INCREF (&finish_breakpoint_object_type); + =A0PyModule_AddObject (gdb_module, "FinishBreakpoint", + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(PyObject *) &finish_breakpoin= t_object_type); + + =A0observer_attach_normal_stop (bpfinishpy_handle_stop); +} + +static PyGetSetDef finish_breakpoint_object_getset[] =3D { + =A0{ "out_of_scoped", bpfinishpy_get_outofscoped, bpfinishpy_set_outofsco= ped, + =A0 =A0"Boolean telling whether the breakpoint is still within the scope \ +of the current callstack.", NULL }, + =A0{ "return_value", bpfinishpy_get_returnvalue, NULL, + =A0"gdb.Value object representing the return value, if any. \ +None otherwise.", NULL }, + =A0 =A0{ NULL } =A0/* Sentinel. =A0*/ +}; + +static PyTypeObject finish_breakpoint_object_type =3D +{ + =A0PyObject_HEAD_INIT (NULL) + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*ob_siz= e*/ + =A0"gdb.FinishBreakpoint", =A0 =A0 =A0 =A0 /*tp_name*/ + =A0sizeof (struct finish_breakpoint_object), /*tp_basicsize*/ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_ite= msize*/ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_dea= lloc*/ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_pri= nt*/ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_get= attr*/ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_set= attr*/ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_com= pare*/ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_rep= r*/ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_as_= number*/ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_as_= sequence*/ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_as_= mapping*/ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_has= h */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_cal= l*/ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_str= */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_get= attro*/ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_set= attro */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/*tp_as_= buffer*/ + =A0Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, =A0/*tp_flags*/ + =A0"GDB finish breakpoint object", /* tp_doc */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_tr= averse */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_cl= ear */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_ri= chcompare */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_we= aklistoffset */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_it= er */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_it= ernext */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_me= thods */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_me= mbers */ + =A0finish_breakpoint_object_getset,/* tp_getset */ + =A0&breakpoint_object_type, =A0 =A0 =A0 =A0/* tp_base */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_di= ct */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_de= scr_get */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_de= scr_set */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_di= ctoffset */ + =A0bpfinishpy_init, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_init */ + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_al= loc */ + =A00 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_ne= w */ +}; diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c index d7128a9..2109c73 100644 --- a/gdb/python/py-frame.c +++ b/gdb/python/py-frame.c @@ -60,9 +60,10 @@ static PyTypeObject frame_object_type; =A0 =A0object. =A0If the frame doesn't exist anymore (the frame id doesn't =A0 =A0correspond to any frame in the inferior), returns NULL. =A0*/ -static struct frame_info * -frame_object_to_frame_info (frame_object *frame_obj) +struct frame_info * +frame_object_to_frame_info (PyObject *obj) =A0{ + =A0frame_object *frame_obj =3D (frame_object *) obj; =A0 struct frame_info *frame; =A0 frame =3D frame_find_by_id (frame_obj->frame_id); @@ -103,7 +104,7 @@ frapy_is_valid (PyObject *self, PyObject *args) =A0{ =A0 struct frame_info *frame; - =A0frame =3D frame_object_to_frame_info ((frame_object *) self); + =A0frame =3D frame_object_to_frame_info (self); =A0 if (frame =3D=3D NULL) =A0 =A0 Py_RETURN_FALSE; @@ -124,7 +125,7 @@ frapy_name (PyObject *self, PyObject *args) =A0 TRY_CATCH (except, RETURN_MASK_ALL) =A0 =A0 { - =A0 =A0 =A0FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + =A0 =A0 =A0FRAPY_REQUIRE_VALID (self, frame); =A0 =A0 =A0 find_frame_funname (frame, &name, &lang, NULL); =A0 =A0 } @@ -153,7 +154,7 @@ frapy_type (PyObject *self, PyObject *args) =A0 TRY_CATCH (except, RETURN_MASK_ALL) =A0 =A0 { - =A0 =A0 =A0FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + =A0 =A0 =A0FRAPY_REQUIRE_VALID (self, frame); =A0 =A0 =A0 type =3D get_frame_type (frame); =A0 =A0 } @@ -174,7 +175,7 @@ frapy_unwind_stop_reason (PyObject *self, PyObject *arg= s) =A0 TRY_CATCH (except, RETURN_MASK_ALL) =A0 =A0 { - =A0 =A0 =A0FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + =A0 =A0 =A0FRAPY_REQUIRE_VALID (self, frame); =A0 =A0 } =A0 GDB_PY_HANDLE_EXCEPTION (except); @@ -195,7 +196,7 @@ frapy_pc (PyObject *self, PyObject *args) =A0 TRY_CATCH (except, RETURN_MASK_ALL) =A0 =A0 { - =A0 =A0 =A0FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + =A0 =A0 =A0FRAPY_REQUIRE_VALID (self, frame); =A0 =A0 =A0 pc =3D get_frame_pc (frame); =A0 =A0 } @@ -216,7 +217,7 @@ frapy_block (PyObject *self, PyObject *args) =A0 TRY_CATCH (except, RETURN_MASK_ALL) =A0 =A0 { - =A0 =A0 =A0FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + =A0 =A0 =A0FRAPY_REQUIRE_VALID (self, frame); =A0 =A0 =A0 block =3D get_frame_block (frame, NULL); =A0 =A0 } =A0 GDB_PY_HANDLE_EXCEPTION (except); @@ -257,7 +258,7 @@ frapy_function (PyObject *self, PyObject *args) =A0 TRY_CATCH (except, RETURN_MASK_ALL) =A0 =A0 { - =A0 =A0 =A0FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + =A0 =A0 =A0FRAPY_REQUIRE_VALID (self, frame); =A0 =A0 =A0 sym =3D find_pc_function (get_frame_address_in_block (frame)); =A0 =A0 } @@ -319,7 +320,7 @@ frapy_older (PyObject *self, PyObject *args) =A0 TRY_CATCH (except, RETURN_MASK_ALL) =A0 =A0 { - =A0 =A0 =A0FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + =A0 =A0 =A0FRAPY_REQUIRE_VALID (self, frame); =A0 =A0 =A0 prev =3D get_prev_frame (frame); =A0 =A0 =A0 if (prev) @@ -348,7 +349,7 @@ frapy_newer (PyObject *self, PyObject *args) =A0 TRY_CATCH (except, RETURN_MASK_ALL) =A0 =A0 { - =A0 =A0 =A0FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + =A0 =A0 =A0FRAPY_REQUIRE_VALID (self, frame); =A0 =A0 =A0 next =3D get_next_frame (frame); =A0 =A0 =A0 if (next) @@ -377,7 +378,7 @@ frapy_find_sal (PyObject *self, PyObject *args) =A0 TRY_CATCH (except, RETURN_MASK_ALL) =A0 =A0 { - =A0 =A0 =A0FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + =A0 =A0 =A0FRAPY_REQUIRE_VALID (self, frame); =A0 =A0 =A0 find_frame_sal (frame, &sal); =A0 =A0 =A0 sal_obj =3D symtab_and_line_to_sal_object (sal); @@ -433,7 +434,7 @@ frapy_read_var (PyObject *self, PyObject *args) =A0 =A0 =A0 TRY_CATCH (except, RETURN_MASK_ALL) =A0 =A0 =A0 =A0{ - =A0 =A0 =A0 =A0 FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + =A0 =A0 =A0 =A0 FRAPY_REQUIRE_VALID (self, frame); =A0 =A0 =A0 =A0 =A0if (!block) =A0 =A0 =A0 =A0 =A0 =A0block =3D get_frame_block (frame, NULL); @@ -461,7 +462,7 @@ frapy_read_var (PyObject *self, PyObject *args) =A0 TRY_CATCH (except, RETURN_MASK_ALL) =A0 =A0 { - =A0 =A0 =A0FRAPY_REQUIRE_VALID ((frame_object *) self, frame); + =A0 =A0 =A0FRAPY_REQUIRE_VALID (self, frame); =A0 =A0 =A0 val =3D read_var_value (var, frame); =A0 =A0 } @@ -484,12 +485,11 @@ static PyObject * =A0frapy_select (PyObject *self, PyObject *args) =A0{ =A0 struct frame_info *fi; - =A0frame_object *frame =3D (frame_object *) self; =A0 volatile struct gdb_exception except; =A0 TRY_CATCH (except, RETURN_MASK_ALL) =A0 =A0 { - =A0 =A0 =A0FRAPY_REQUIRE_VALID (frame, fi); + =A0 =A0 =A0FRAPY_REQUIRE_VALID (self, fi); =A0 =A0 =A0 select_frame (fi); =A0 =A0 } diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index d3cb788..9ec1981 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -114,6 +114,7 @@ extern PyTypeObject symbol_object_type; =A0extern PyTypeObject event_object_type; =A0extern PyTypeObject events_object_type; =A0extern PyTypeObject stop_event_object_type; +extern PyTypeObject breakpoint_object_type; =A0/* Defined in py-breakpoint.c */ =A0typedef struct breakpoint_object breakpoint_object; @@ -161,6 +162,7 @@ PyObject *block_to_block_object (struct block *block, struct objfile *objfile); =A0PyObject *value_to_value_object (struct value *v); =A0PyObject *type_to_type_object (struct type *); =A0PyObject *frame_info_to_frame_object (struct frame_info *frame); +struct frame_info *frame_object_to_frame_info (PyObject *frame_obj); =A0PyObject *pspace_to_pspace_object (struct program_space *); =A0PyObject *pspy_get_printers (PyObject *, void *); @@ -194,6 +196,7 @@ void gdbpy_initialize_functions (void); =A0void gdbpy_initialize_pspace (void); =A0void gdbpy_initialize_objfile (void); =A0void gdbpy_initialize_breakpoints (void); +void gdbpy_initialize_finishbreakpoints (void); =A0void gdbpy_initialize_lazy_string (void); =A0void gdbpy_initialize_parameters (void); =A0void gdbpy_initialize_thread (void); diff --git a/gdb/python/python.c b/gdb/python/python.c index 8a7bc66..d620382 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -1060,6 +1060,7 @@ Enables or disables printing of Python stack traces."= ), =A0 gdbpy_initialize_pspace (); =A0 gdbpy_initialize_objfile (); =A0 gdbpy_initialize_breakpoints (); + =A0gdbpy_initialize_finishbreakpoints(); =A0 gdbpy_initialize_lazy_string (); =A0 gdbpy_initialize_thread (); =A0 gdbpy_initialize_inferior (); diff --git a/gdb/testsuite/gdb.python/py-breakpoint.c b/gdb/testsuite/gdb.python/py-breakpoint.c index 9a96681..f32ff78 100644 --- a/gdb/testsuite/gdb.python/py-breakpoint.c +++ b/gdb/testsuite/gdb.python/py-breakpoint.c @@ -29,18 +29,32 @@ int add (int i) =A0 return i + i; =A0} +int increase_1(int *a) +{ + =A0*a +=3D 1; + =A0return -5; +} + +void increase(int *a) +{ + =A0increase_1(a); +} =A0int main (int argc, char *argv[]) =A0{ =A0 int foo =3D 5; =A0 int bar =3D 42; =A0 int i; + =A0i =3D 0 ; + =A0/* Break at increase. */ + =A0increase (&i) ; + =A0increase (&i) ; =A0 for (i =3D 0; i < 10; i++) =A0 =A0 { =A0 =A0 =A0 result +=3D multiply (foo); =A0/* Break at multiply. */ =A0 =A0 =A0 result +=3D add (bar); /* Break at add. */ =A0 =A0 } - + =A0 return 0; /* Break at end. */ =A0} diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp index f0a83f1..8755888 100644 --- a/gdb/testsuite/gdb.python/py-breakpoint.exp +++ b/gdb/testsuite/gdb.python/py-breakpoint.exp @@ -44,7 +44,8 @@ gdb_py_test_silent_cmd "python blist =3D gdb.breakpoints()" "Get Breakpoint List" =A0gdb_test "python print blist\[0\]" "" "Check obj exists" =A0gdb_test "python print blist\[0\].location" "main." "Check breakpoint lo= cation" -gdb_breakpoint [gdb_get_line_number "Break at multiply."] +set mult_line [gdb_get_line_number "Break at multiply."] +gdb_breakpoint ${mult_line} =A0gdb_continue_to_breakpoint "Break at multiply." =A0# Check that the Python breakpoint code noted the addition of a @@ -54,7 +55,9 @@ gdb_test "python print len(blist)" "2" "Check for two breakpoints" =A0gdb_test "python print blist\[0\]" "" "Check obj exists" =A0gdb_test "python print blist\[0\].location" "main." "Check breakpoint lo= cation" =A0gdb_test "python print blist\[1\]" "" "Check obj exists" -gdb_test "python print blist\[1\].location" "py-breakpoint\.c:41*" "Check breakpoint location" + +gdb_test "python print blist\[1\].location" "py-breakpoint\.c:${mult_line}= *" \ + =A0 =A0 =A0 =A0 "Check breakpoint location" =A0# Check hit and ignore counts. =A0gdb_test "python print blist\[1\].hit_count" "1" "Check breakpoint hit c= ount" diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint.exp b/gdb/testsuite/gdb.python/py-finish-breakpoint.exp new file mode 100644 index 0000000..febef50 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint.exp @@ -0,0 +1,63 @@ +# Copyright (C) 2010, 2011 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =A0See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. =A0If not, see . + +# This file is part of the GDB testsuite. =A0It tests the mechanism +# exposing values to Python. + +if $tracelevel then { + =A0 =A0strace $tracelevel +} + +load_lib gdb-python.exp + +set testfile "py-breakpoint" +set srcfile ${testfile}.c +set remote_python_file [remote_download host ${srcdir}/${subdir}/py-finish-breakpoint.py] + +if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } { + =A0 =A0return -1 +} + +# Skip all tests if Python scripting is not enabled. +if { [skip_python_tests] } { continue } + +if ![runto_main] then { + =A0 =A0fail "Cannot run to main." + =A0 =A0return 0 +} + +gdb_test "source $remote_python_file" ".*Python script imported.*" "import python scripts" + +gdb_test "python MyBreakpoint(\"increase_1\")" ".*Breakpoint 2.*" "create Python function breakpoint" + +gdb_test "continue" ".*Arrived at MyBreakpoint with 0.*" "check MyBreakpoint hit" +gdb_test "python finishbp =3D MyFinishBreakpoint (gdb.parse_and_eval (\"a\"), gdb.selected_frame ())" ".*Breakpoint 3.*" "set FinishBreakpoint" +gdb_test "python print finishbp.out_of_scoped" ".*False.*" "check out_of_scoped init" +gdb_test "python print finishbp.return_value" ".*None.*" "check return_val= ue" + +gdb_test "continue" ".*MyFinishBreakpoint stop with 1.*#0.*increase.*" "check MyFinishBreakpoint hit" +gdb_test "python print finishbp.return_value" ".*-5.*" "check return_value" +gdb_test "python print finishbp.out_of_scoped" ".*False.*" "check out_of_scoped after hit" +gdb_test "finish" ".*Run til.*" "return to main()" +gdb_test "python print finishbp.return_value" ".*None.*" "check return_val= ue" + +gdb_test "continue" ".*Arrived at MyBreakpoint with 1.*" "check MyBreakpoint second hit" +gdb_test "up" ".*increase_1.*" "go one frame up" +gdb_test_no_output "python finishbp.out_of_scoped =3D False" "re-enable out_of_scoped" +gdb_test_no_output "set confirm off" "disable confirmation" +gdb_test_no_output "return" "return from the frame" + +gdb_test "next" ".*MyFinishBreakpoint out of scope.*" "check Finish breakpoint discard" +gdb_test "python print finishbp.out_of_scoped" ".*True.*" "check out_of_sc= oped" \ No newline at end of file diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint.py b/gdb/testsuite/gdb.python/py-finish-breakpoint.py new file mode 100644 index 0000000..ea82fe9 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint.py @@ -0,0 +1,21 @@ +class MyBreakpoint(gdb.Breakpoint): + =A0 =A0 =A0 def stop(self): + =A0 =A0 =A0 =A0 =A0 =A0 =A0 val =3D gdb.parse_and_eval ("a") + =A0 =A0 =A0 =A0 =A0 =A0 =A0 print "Arrived at MyBreakpoint with %d" % int= (val.dereference()) + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return True + +class MyFinishBreakpoint(gdb.FinishBreakpoint): + =A0 =A0 =A0 def __init__(self, val, frame): + =A0 =A0 =A0 =A0 =A0 =A0 =A0 super (MyFinishBreakpoint, self).__init__ (fr= ame) + =A0 =A0 =A0 =A0 =A0 =A0 =A0 print "MyFinishBreakpoint init" + =A0 =A0 =A0 =A0 =A0 =A0 =A0 self.val =3D val + + =A0 =A0 =A0 def stop(self): + =A0 =A0 =A0 =A0 =A0 =A0 =A0 print "MyFinishBreakpoint stop with %d" % int(self.val.dereference()) + =A0 =A0 =A0 =A0 =A0 =A0 =A0 gdb.execute("where 1") + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return True + + =A0 =A0 =A0 def out_of_scope(self): + =A0 =A0 =A0 =A0 =A0 =A0 =A0 print "MyFinishBreakpoint out of scope..." + +print "Python script imported" \ No newline at end of file -- 1.7.4.4