From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 2882 invoked by alias); 24 Feb 2011 05:29:21 -0000 Received: (qmail 2870 invoked by uid 22791); 24 Feb 2011 05:29:17 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,SPF_HELO_PASS,TW_BJ,TW_DB,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (216.239.44.51) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 24 Feb 2011 05:29:11 +0000 Received: from hpaq7.eem.corp.google.com (hpaq7.eem.corp.google.com [172.25.149.7]) by smtp-out.google.com with ESMTP id p1O5T8nX011697 for ; Wed, 23 Feb 2011 21:29:08 -0800 Received: from vws8 (vws8.prod.google.com [10.241.21.136]) by hpaq7.eem.corp.google.com with ESMTP id p1O5T61H026773 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=NOT) for ; Wed, 23 Feb 2011 21:29:07 -0800 Received: by vws8 with SMTP id 8so169024vws.12 for ; Wed, 23 Feb 2011 21:29:05 -0800 (PST) MIME-Version: 1.0 Received: by 10.220.201.6 with SMTP id ey6mr102483vcb.68.1298525345458; Wed, 23 Feb 2011 21:29:05 -0800 (PST) Received: by 10.220.43.145 with HTTP; Wed, 23 Feb 2011 21:29:05 -0800 (PST) In-Reply-To: References: Date: Thu, 24 Feb 2011 07:02:00 -0000 Message-ID: Subject: Re: [patch] [python] Implement stop_p for gdb.Breakpoint From: Doug Evans To: pmuldoon@redhat.com Cc: gdb-patches@sourceware.org, tromey@redhat.com Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-System-Of-Record: true 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-02/txt/msg00677.txt.bz2 On Wed, Feb 23, 2011 at 6:56 AM, Phil Muldoon wrote: > > This is another submission for the stop_p/eval/condition/whatever-name > that allows Python breakpoints to evaluate arbitrary conditions when a > breakpoint is hit, and accordingly, instruct GDB to stop or continue. > I've decided I would like this patch to be pushed for 7.3, so hence the > resurrection. =A0Lets make this work and fix what needs to be done for > 7.3. > > I believe I have implemented all of the requests from the previous patch > discussion. =A0I eventually renamed eval to stop_p. =A0Also, recently, Tom > wrote a log_printf Python command that uses this feature. I've included > it here, along with a few alterations Tom had to make to Breakpoint > initialization to make that work. > > Here it is. What do you think? Hi. Some nits and comments: - "consistency is good", so if we go with _p for stop_p we need to go with _p for all predicates - are we prepared for that? - are there any existing predicates that don't have _p? - does python have an existing convention? [I used stop_p at the time for clarity's sake. But I think these questions need to be asked.] - I didn't see any tests for log-printf - log.py feels misnamed but since the name isn't exported to the user it's not important enough to find a better name - can printf get an error (e.g. bad memory access) and would one necessarily want execution to halt when that happens? - I can imagine wanting to just see an error message and have execution continue - OTOH while testing a log-printf I would want execution to stop if I misspelled something - we don't have to add the functionality now, but IWBN to at least think about if/how we'd provide it - we probably should document log-printf in the manual - is the logic for deciding whether to stop correct? E.g. if stop_p says "don't stop" and a condition says "stop" will execution continue? It looks like it, but maybe I'm misunderstanding something. > (I've CC'd Tom and Doug directly, purely as a courtesy from the last > discussion.) > > I have the ChangeLog entries, but did not include them in this > patch. =A0I will update them accordingly in the future. > > Tested on x8664 with no regressions. > > Cheers > > Phil > > -- > > diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c > index c9e149b..04603e0 100644 > --- a/gdb/breakpoint.c > +++ b/gdb/breakpoint.c > @@ -72,6 +72,10 @@ > > =A0#include "mi/mi-common.h" > > +#if HAVE_PYTHON > +#include "python/python.h" > +#endif > + > =A0/* Arguments to pass as context to some catch command handlers. =A0*/ > =A0#define CATCH_PERMANENT ((void *) (uintptr_t) 0) > =A0#define CATCH_TEMPORARY ((void *) (uintptr_t) 1) > @@ -4217,6 +4221,12 @@ bpstat_check_breakpoint_conditions (bpstat bs, pti= d_t ptid) > =A0 =A0 =A0 int value_is_zero =3D 0; > =A0 =A0 =A0 struct expression *cond; > > +#if HAVE_PYTHON > + =A0 =A0 =A0/* Evaluate Python breakpoints that have a "condition" > + =A0 =A0 =A0 =A0method implemented. =A0*/ > + =A0 =A0 =A0if (b->py_bp_object) > + =A0 =A0 =A0 bs->stop =3D gdbpy_stop_p (b->py_bp_object); > +#endif > =A0 =A0 =A0 if (is_watchpoint (b)) > =A0 =A0 =A0 =A0cond =3D b->cond_exp; > =A0 =A0 =A0 else > diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile= .in > index 11cf2e6..96b63b6 100644 > --- a/gdb/data-directory/Makefile.in > +++ b/gdb/data-directory/Makefile.in > @@ -56,6 +56,7 @@ PYTHON_FILES =3D \ > =A0 =A0 =A0 =A0gdb/types.py \ > =A0 =A0 =A0 =A0gdb/printing.py \ > =A0 =A0 =A0 =A0gdb/command/__init__.py \ > + =A0 =A0 =A0 gdb/command/log.py \ > =A0 =A0 =A0 =A0gdb/command/pretty_printers.py > > =A0FLAGS_TO_PASS =3D \ > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index f8b7e2d..20a99f7 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -23082,6 +23082,34 @@ argument defines the class of watchpoint to crea= te, if @var{type} is > =A0assumed to be a @var{WP_WRITE} class. > =A0@end defmethod > > +@defop Operation {gdb.Breakpoint} stop_p (self) > +The @code{gdb.Breakpoint} class can be sub-classed and, in > +particular, you may choose to implement the @code{stop_p} method. > +If this method is defined as a sub-class of @code{gdb.Breakpoint}, > +it will be called when the inferior stops at any location of a > +breakpoint which instantiates that sub-class. =A0If the method returns > +@code{True}, the inferior will be stopped at the location of the > +breakpoint, otherwise the inferior will continue. > + > +If there are multiple breakpoints at the same location with a > +@code{stop_p} method, each one will be called regardless of the > +return status of the previous. =A0This ensures that all @code{stop_p} > +methods have a chance to execute at that location. =A0In this scenario > +if one of the methods returns @code{True} but the others return > +@code{False}, the inferior will still be stopped. > + > +Example @code{stop_p} implementation: > + > +@smallexample > +class MyBreakpoint (gdb.Breakpoint): > + =A0 =A0 =A0def stop_p (self): > + =A0 =A0 =A0 =A0inf_val =3D gdb.parse_and_eval("foo") > + =A0 =A0 =A0 =A0if inf_val =3D=3D 3: > + =A0 =A0 =A0 =A0 =A0return True > + =A0 =A0 =A0 =A0return False > +@end smallexample > +@end defop > + > =A0The available watchpoint types represented by constants are defined in= the > =A0@code{gdb} module: > > diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__= .py > index 43975c2..35d4dfc 100644 > --- a/gdb/python/lib/gdb/__init__.py > +++ b/gdb/python/lib/gdb/__init__.py > @@ -14,5 +14,6 @@ > =A0# along with this program. =A0If not, see . > > =A0import gdb.command.pretty_printers > +import gdb.command.log > > =A0gdb.command.pretty_printers.register_pretty_printer_commands() > diff --git a/gdb/python/lib/gdb/command/log.py b/gdb/python/lib/gdb/comma= nd/log.py > new file mode 100644 > index 0000000..4b93b8c > --- /dev/null > +++ b/gdb/python/lib/gdb/command/log.py > @@ -0,0 +1,57 @@ > +# log-printf command > +# Copyright (C) 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 . > + > +import gdb > + > +class _Logbp(gdb.Breakpoint): > + =A0 =A0"A breakpoint that logs using printf." > + > + =A0 =A0def __init__(self, loc, arg): > + =A0 =A0 =A0 =A0super(_Logbp, self).__init__(loc) > + =A0 =A0 =A0 =A0self._cmd =3D 'printf ' + arg > + > + =A0 =A0def stop_p(self): > + =A0 =A0 =A0 =A0gdb.execute(self._cmd, from_tty =3D False) > + =A0 =A0 =A0 =A0return False > + > +class _Logprintf(gdb.Command): > + =A0 =A0"""A variant of printf that logs expressions at a given source l= ocation. > + > +Usage: log-printf LINESPEC -- PRINTF-ARGS > + > +LINESPEC is any linespec of the forms accepted by `break'. > +A plain `--' separates the linespec from the remaining arguments, > +which are of the form accepted by the `printf' command. > + > +This command installs a special breakpoint to do its work. > +You can disable the effects of this command by disabling or deleting > +that breakpoint.""" > + > + =A0 =A0def __init__(self): > + =A0 =A0 =A0 =A0super(_Logprintf, self).__init__('log-printf', > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 gdb.COMMAND_BREAKPOINTS, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 # Arguable. > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 gdb.COMPLETE_SYMBOL) > + > + =A0 =A0def invoke(self, arg, from_tty): > + =A0 =A0 =A0 =A0dashes =3D arg.find(' -- ') > + =A0 =A0 =A0 =A0if dashes =3D=3D -1: > + =A0 =A0 =A0 =A0 =A0 =A0raise gdb.GdbError("could not find ` -- '") > + =A0 =A0 =A0 =A0linespec =3D arg[0 : dashes] > + =A0 =A0 =A0 =A0format =3D arg[(dashes + 4):] > + =A0 =A0 =A0 =A0_Logbp(linespec, format) > + > +_Logprintf() > diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c > index bfad002..4551416 100644 > --- a/gdb/python/py-breakpoint.c > +++ b/gdb/python/py-breakpoint.c > @@ -28,6 +28,8 @@ > =A0#include "observer.h" > =A0#include "cli/cli-script.h" > =A0#include "ada-lang.h" > +#include "arch-utils.h" > +#include "language.h" > > =A0static PyTypeObject breakpoint_object_type; > > @@ -586,10 +588,9 @@ bppy_get_ignore_count (PyObject *self, void *closure) > =A0} > > =A0/* Python function to create a new breakpoint. =A0*/ > -static PyObject * > -bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs) > +static int > +bppy_init (PyObject *self, PyObject *args, PyObject *kwargs) > =A0{ > - =A0PyObject *result; > =A0 static char *keywords[] =3D { "spec", "type", "wp_class", "internal",= NULL }; > =A0 char *spec; > =A0 int type =3D bp_breakpoint; > @@ -600,19 +601,16 @@ bppy_new (PyTypeObject *subtype, PyObject *args, Py= Object *kwargs) > > =A0 if (! PyArg_ParseTupleAndKeywords (args, kwargs, "s|iiO", keywords, > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &= spec, &type, &access_type, &internal)) > - =A0 =A0return NULL; > + =A0 =A0return -1; > > =A0 if (internal) > =A0 =A0 { > =A0 =A0 =A0 internal_bp =3D PyObject_IsTrue (internal); > =A0 =A0 =A0 if (internal_bp =3D=3D -1) > - =A0 =A0 =A0 return NULL; > + =A0 =A0 =A0 return -1; > =A0 =A0 } > > - =A0result =3D subtype->tp_alloc (subtype, 0); > - =A0if (! result) > - =A0 =A0return NULL; > - =A0bppy_pending_object =3D (breakpoint_object *) result; > + =A0bppy_pending_object =3D (breakpoint_object *) self; > =A0 bppy_pending_object->number =3D -1; > =A0 bppy_pending_object->bp =3D NULL; > > @@ -649,14 +647,14 @@ bppy_new (PyTypeObject *subtype, PyObject *args, Py= Object *kwargs) > =A0 =A0 } > =A0 if (except.reason < 0) > =A0 =A0 { > - =A0 =A0 =A0subtype->tp_free (result); > - =A0 =A0 =A0return PyErr_Format (except.reason =3D=3D RETURN_QUIT > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0? PyExc_KeyboardInte= rrupt : PyExc_RuntimeError, > - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"%s", except.message= ); > + =A0 =A0 =A0PyErr_Format (except.reason =3D=3D RETURN_QUIT > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ? PyExc_KeyboardInterrupt : PyExc_R= untimeError, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "%s", except.message); > + =A0 =A0 =A0return -1; > =A0 =A0 } > > - =A0BPPY_REQUIRE_VALID ((breakpoint_object *) result); > - =A0return result; > + =A0BPPY_SET_REQUIRE_VALID ((breakpoint_object *) self); > + =A0return 0; > =A0} > > > @@ -707,6 +705,47 @@ gdbpy_breakpoints (PyObject *self, PyObject *args) > =A0 return PyList_AsTuple (list); > =A0} > > +/* Call the "stop_p" method (if implemented) in the breakpoint class. = =A0If > + =A0 the method returns True, the inferior =A0will be stopped at the > + =A0 breakpoint. =A0Otherwise the inferior will be allowed to continue. = =A0*/ > + > +int > +gdbpy_stop_p (struct breakpoint_object *bp_obj) > +{ > + =A0int should_stop =3D 1; > + =A0char *method =3D "stop_p"; > + > + =A0PyObject *py_bp =3D (PyObject *) bp_obj; > + =A0struct breakpoint *b =3D bp_obj->bp; > + =A0struct gdbarch *garch =3D b->gdbarch ? b->gdbarch : get_current_arch= (); > + =A0struct cleanup *cleanup =3D ensure_python_env (garch, current_langua= ge); > + > + =A0if (PyObject_HasAttrString (py_bp, method)) > + =A0 =A0{ > + =A0 =A0 =A0PyObject *result =3D PyObject_CallMethod (py_bp, method, NUL= L); > + > + =A0 =A0 =A0if (result) > + =A0 =A0 =A0 { > + =A0 =A0 =A0 =A0 int evaluate =3D PyObject_IsTrue (result); > + > + =A0 =A0 =A0 =A0 if (evaluate =3D=3D -1) > + =A0 =A0 =A0 =A0 =A0 gdbpy_print_stack (); > + > + =A0 =A0 =A0 =A0 /* If the evaluate function returns False that means the > + =A0 =A0 =A0 =A0 =A0 =A0Python breakpoint wants GDB to continue. =A0*/ > + =A0 =A0 =A0 =A0 if (!evaluate) > + =A0 =A0 =A0 =A0 =A0 should_stop =3D 0; > + > + =A0 =A0 =A0 =A0 Py_DECREF (result); > + =A0 =A0 =A0 } > + =A0 =A0 =A0else > + =A0 =A0 =A0 gdbpy_print_stack (); > + =A0 =A0} > + =A0do_cleanups (cleanup); > + > + =A0return should_stop; > +} > + > > > =A0/* Event callback functions. =A0*/ > @@ -793,7 +832,6 @@ gdbpy_initialize_breakpoints (void) > =A0{ > =A0 int i; > > - =A0breakpoint_object_type.tp_new =3D bppy_new; > =A0 if (PyType_Ready (&breakpoint_object_type) < 0) > =A0 =A0 return; > > @@ -899,7 +937,7 @@ static PyTypeObject breakpoint_object_type =3D > =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*tp_getat= tro*/ > =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*tp_setat= tro*/ > =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*tp_as_bu= ffer*/ > - =A0Py_TPFLAGS_DEFAULT, =A0 =A0 =A0 =A0 =A0 =A0/*tp_flags*/ > + =A0Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, =A0/*tp_flags*/ > =A0 "GDB breakpoint object", =A0 =A0 =A0 /* tp_doc */ > =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_trav= erse */ > =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_clea= r */ > @@ -909,5 +947,13 @@ static PyTypeObject breakpoint_object_type =3D > =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_iter= next */ > =A0 breakpoint_object_methods, =A0 =A0 /* tp_methods */ > =A0 0, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_memb= ers */ > - =A0breakpoint_object_getset =A0 =A0 =A0 /* tp_getset */ > + =A0breakpoint_object_getset, =A0 =A0 =A0/* tp_getset */ > + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_bas= e */ > + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_dic= t */ > + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_des= cr_get */ > + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_des= cr_set */ > + =A00, =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* tp_dic= toffset */ > + =A0bppy_init, =A0 =A0 =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 /* tp_all= oc */ > + =A0PyType_GenericNew =A0 =A0 =A0 =A0 =A0 =A0 =A0/* tp_new */ > =A0}; > diff --git a/gdb/python/python.h b/gdb/python/python.h > index 58d97fc..801282e 100644 > --- a/gdb/python/python.h > +++ b/gdb/python/python.h > @@ -22,6 +22,8 @@ > > =A0#include "value.h" > > +struct breakpoint_object; > + > =A0extern int gdbpy_global_auto_load; > > =A0extern void finish_python_initialization (void); > @@ -41,4 +43,6 @@ void preserve_python_values (struct objfile *objfile, h= tab_t copied_types); > > =A0void load_auto_scripts_for_objfile (struct objfile *objfile); > > +int gdbpy_stop_p (struct breakpoint_object *bp_obj); > + > =A0#endif /* GDB_PYTHON_H */ > diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/g= db.python/py-breakpoint.exp > index 6b33284..51ea126 100644 > --- a/gdb/testsuite/gdb.python/py-breakpoint.exp > +++ b/gdb/testsuite/gdb.python/py-breakpoint.exp > @@ -198,3 +198,76 @@ gdb_py_test_silent_cmd =A0"python wp1 =3D gdb.Breakp= oint (\"result\", type=3Dgdb.BP_WA > =A0gdb_test "info breakpoints" "No breakpoints or watchpoints.*" "Check i= nfo breakpoints does not show invisible breakpoints" > =A0gdb_test "maint info breakpoints" ".*hw watchpoint.*result.*" "Check m= aint info breakpoints shows invisible breakpoints" > =A0gdb_test "continue" ".*\[Ww\]atchpoint.*result.*Old value =3D 0.*New v= alue =3D 25.*" "Test watchpoint write" > + > +# Breakpoints that have an evaluation function. > + > +# Start with a fresh gdb. > +clean_restart ${testfile} > + > +if ![runto_main] then { > + =A0 =A0fail "Cannot run to main." > + =A0 =A0return 0 > +} > +delete_breakpoints > + > +gdb_py_test_multiple "Sub-class a breakpoint" \ > + =A0"python" "" \ > + =A0"class bp_eval (gdb.Breakpoint):" "" \ > + =A0" =A0 inf_i =3D 0" "" \ > + =A0" =A0 count =3D 0" "" \ > + =A0" =A0 def stop_p (self):" "" \ > + =A0" =A0 =A0 =A0self.count =3D self.count + 1" "" \ > + =A0" =A0 =A0 =A0self.inf_i =3D gdb.parse_and_eval(\"i\")" "" \ > + =A0" =A0 =A0 =A0if self.inf_i =3D=3D 3:" "" \ > + =A0" =A0 =A0 =A0 =A0return True" "" \ > + =A0" =A0 =A0 =A0return False" "" \ > + =A0"end" "" > + > +gdb_py_test_multiple "Sub-class a second breakpoint" \ > + =A0"python" "" \ > + =A0"class bp_also_eval (gdb.Breakpoint):" "" \ > + =A0" =A0 count =3D 0" "" \ > + =A0" =A0 def stop_p (self):" "" \ > + =A0" =A0 =A0 =A0self.count =3D self.count + 1" "" \ > + =A0" =A0 =A0 =A0if self.count =3D=3D 9:" "" \ > + =A0" =A0 =A0 =A0 =A0return True" "" \ > + =A0" =A0 =A0 =A0return False" "" \ > + =A0"end" "" > + > +set bp_location2 [gdb_get_line_number "Break at multiply."] > +set end_location [gdb_get_line_number "Break at end."] > +gdb_py_test_silent_cmd =A0"python eval_bp1 =3D bp_eval(\"$bp_location2\"= )" "Set breakpoint" 0 > +gdb_py_test_silent_cmd =A0"python also_eval_bp1 =3D bp_also_eval(\"$bp_l= ocation2\")" "Set breakpoint" 0 > +gdb_py_test_silent_cmd =A0"python never_eval_bp1 =3D bp_also_eval(\"$end= _location\")" "Set breakpoint" 0 > +gdb_continue_to_breakpoint "Break at multiply." ".*/$srcfile:$bp_locatio= n2.*" > +gdb_test "print i" "3" "Check inferior value matches python accounting" > +gdb_test "python print eval_bp1.inf_i" "3" "Check python accounting matc= hes inferior" > +gdb_test "python print also_eval_bp1.count" "4" \ > + =A0 =A0"Check non firing same-location breakpoint eval function was als= o called at each stop." > +gdb_test "python print eval_bp1.count" "4" \ > + =A0 =A0"Check non firing same-location breakpoint eval function was als= o called at each stop." > + > +delete_breakpoints > +gdb_breakpoint [gdb_get_line_number "Break at multiply."] > +gdb_py_test_silent_cmd =A0"python check_eval =3D bp_eval(\"$bp_location2= \")" "Set breakpoint" 0 > +gdb_test "python print check_eval.count" "0" \ > + =A0 =A0"Test that evaluate function has not been yet executed (ie count= =3D 0)" > +gdb_continue_to_breakpoint "Break at multiply." ".*/$srcfile:$bp_locatio= n2.*" > +gdb_test "python print check_eval.count" "1" \ > + =A0 =A0"Test that evaluate function is run when location also has norma= l bp" > + > +gdb_py_test_multiple "Sub-class a watchpoint" \ > + =A0"python" "" \ > + =A0"class wp_eval (gdb.Breakpoint):" "" \ > + =A0" =A0 def stop_p (self):" "" \ > + =A0" =A0 =A0 =A0self.result =3D gdb.parse_and_eval(\"result\")" "" \ > + =A0" =A0 =A0 =A0if self.result =3D=3D 788:" "" \ > + =A0" =A0 =A0 =A0 =A0return True" "" \ > + =A0" =A0 =A0 =A0return False" "" \ > + =A0"end" "" > + > +delete_breakpoints > +gdb_py_test_silent_cmd =A0"python wp1 =3D wp_eval (\"result\", type=3Dgd= b.BP_WATCHPOINT, wp_class=3Dgdb.WP_WRITE)" "Set watchpoint" 0 > +gdb_test "continue" ".*\[Ww\]atchpoint.*result.*Old value =3D.*New value= =3D 788.*" "Test watchpoint write" > +gdb_test "python print never_eval_bp1.count" "0" \ > + =A0 =A0"Check that this unrelated breakpoints eval function was never c= alled." > >