From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18033 invoked by alias); 14 Nov 2013 17:49:09 -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 18024 invoked by uid 89); 14 Nov 2013 17:49:08 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=1.6 required=5.0 tests=AWL,BAYES_50,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,RDNS_NONE,SPF_PASS autolearn=no version=3.3.2 X-HELO: mail-pb0-f48.google.com Received: from Unknown (HELO mail-pb0-f48.google.com) (209.85.160.48) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Thu, 14 Nov 2013 17:49:07 +0000 Received: by mail-pb0-f48.google.com with SMTP id mc17so2346018pbc.21 for ; Thu, 14 Nov 2013 09:48:59 -0800 (PST) X-Received: by 10.68.130.169 with SMTP id of9mr2612078pbb.79.1384451339154; Thu, 14 Nov 2013 09:48:59 -0800 (PST) Received: from seba.sebabeach.org.gmail.com (173-13-178-50-sfba.hfc.comcastbusiness.net. [173.13.178.50]) by mx.google.com with ESMTPSA id bp5sm52940590pbb.18.2013.11.14.09.48.57 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 14 Nov 2013 09:48:58 -0800 (PST) From: Doug Evans To: gdb-patches@sourceware.org, pmuldoon@redhat.com, palves@redhat.com, eliz@gnu.org Subject: [PATCH, doc RFA] Allow CLI and Python conditions to be set on same breakpoint References: Date: Thu, 14 Nov 2013 17:58:00 -0000 In-Reply-To: (Doug Evans's message of "Tue, 12 Nov 2013 21:50:02 -0800") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-IsSubscribed: yes X-SW-Source: 2013-11/txt/msg00378.txt.bz2 Hi. Way back when this was added I wanted to prevent both CLI and Python conditions from being set on the same breakpoint because it wasn't clear there wouldn't be any problems allowing both. [And it's easier to relax restrictions than to impose them after the fact.] Enough time has passed and I can't think of a reason to keep the current restriction. This patch removes the restriction. I couldn't find a doc change that's necessary. I added something to the Python section to say setting both is OK. Regression tested on amd64-linux. Ok to check in? 2013-11-14 Doug Evans * breakpoint.c (condition_command): Allow CLI condition and Python condition to be set on same breakpoint. (bpstat_check_breakpoint_conditions): Handle both CLI and Python conditions being present. * python/py-breakpoint.c (local_setattro): Delete. (breakpoint_object_type): Update. doc/ * gdb.texinfo (Breakpoints In Python): Mention that a CLI condition and Python condition are allowed on the same breakpoint. testsuite/ * gdb.python/py-breakpoint.c: Verify able to set CLI condition and Python condition on same breakpoint. diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 5bfed9d..4baac57 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -1048,14 +1048,6 @@ condition_command (char *arg, int from_tty) ALL_BREAKPOINTS (b) if (b->number == bnum) { - /* Check if this breakpoint has a Python object assigned to - it, and if it has a definition of the "stop" - method. This method and conditions entered into GDB from - the CLI are mutually exclusive. */ - if (b->py_bp_object - && gdbpy_breakpoint_has_py_cond (b->py_bp_object)) - error (_("Cannot set a condition where a Python 'stop' " - "method has been defined in the breakpoint.")); set_breakpoint_condition (b, p, from_tty); if (is_breakpoint (b)) @@ -5112,8 +5104,12 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid) int thread_id = pid_to_thread_id (ptid); const struct bp_location *bl; struct breakpoint *b; - int value_is_zero = 0; - struct expression *cond; + struct expression *cli_cond; + /* Non-zero if there's a CLI condition *and* it evaluates to true. */ + int cli_cond_is_true = 0; + int have_py_cond = 0; + /* Non-zero if there's a Python condition *and* it evaluates to true. */ + int py_cond_is_true = 0; gdb_assert (bs->stop); @@ -5142,20 +5138,33 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid) return; } + /* The default is to stop when the breakpoint is reached. + However, if the breakpoint has any condition (either from the CLI, or + from Python, or both), then only stop if at least one of the conditions + is TRUE. */ + /* Evaluate Python breakpoints that have a "stop" method implemented. */ if (b->py_bp_object) - bs->stop = gdbpy_should_stop (b->py_bp_object); + { + /* We have to call this even if there is no "stop" method in order + to call the FinishBreakpoint pre,post stop hooks. */ + int py_should_stop = gdbpy_should_stop (b->py_bp_object); + + have_py_cond = gdbpy_breakpoint_has_py_cond (b->py_bp_object); + if (have_py_cond) + py_cond_is_true = py_should_stop; + } if (is_watchpoint (b)) { struct watchpoint *w = (struct watchpoint *) b; - cond = w->cond_exp; + cli_cond = w->cond_exp; } else - cond = bl->cond; + cli_cond = bl->cond; - if (cond && b->disposition != disp_del_at_next_stop) + if (cli_cond && b->disposition != disp_del_at_next_stop) { int within_current_scope = 1; struct watchpoint * w; @@ -5205,25 +5214,35 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid) within_current_scope = 0; } if (within_current_scope) - value_is_zero - = catch_errors (breakpoint_cond_eval, cond, + { + int cond_result = + catch_errors (breakpoint_cond_eval, cli_cond, "Error in testing breakpoint condition:\n", RETURN_MASK_ALL); + + /* See breakpoint_cond_eval for why it returns the inverted CLI + condition. */ + cli_cond_is_true = !cond_result; + } else { warning (_("Watchpoint condition cannot be tested " "in the current scope")); /* If we failed to set the right context for this watchpoint, unconditionally report it. */ - value_is_zero = 0; + cli_cond_is_true = 1; } /* FIXME-someday, should give breakpoint #. */ value_free_to_mark (mark); } - if (cond && value_is_zero) + /* Stop if any condition says so. */ + if (cli_cond || have_py_cond) { - bs->stop = 0; + /* bs->stop is already set, so we only have to handle the negative + result: Only continue if all conditions are false. */ + if (!cli_cond_is_true && !py_cond_is_true) + bs->stop = 0; } else if (b->ignore_count > 0) { diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 84acd5c..c872960 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -27196,6 +27196,12 @@ methods have a chance to execute at that location. In this scenario if one of the methods returns @code{True} but the others return @code{False}, the inferior will still be stopped. +A breakpoint may have both a normal breakpoint condition +(@pxref{Conditions, ,Break Conditions}) and a Python +@code{gdb.Breakpoint.stop} condition. +Both will be evaluated and if either return @code{True} then the +inferior will be stopped, otherwise the inferior will continue. + You should not alter the execution state of the inferior (i.e.@:, step, next, etc.), alter the current frame context (i.e.@:, change the current active frame), or alter, add or delete any breakpoint. As a general diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c index e83471e..6bc96e2 100644 --- a/gdb/python/py-breakpoint.c +++ b/gdb/python/py-breakpoint.c @@ -933,37 +933,6 @@ gdbpy_initialize_breakpoints (void) -/* Helper function that overrides this Python object's - PyObject_GenericSetAttr to allow extra validation of the attribute - being set. */ - -static int -local_setattro (PyObject *self, PyObject *name, PyObject *v) -{ - breakpoint_object *obj = (breakpoint_object *) self; - char *attr = python_string_to_host_string (name); - - if (attr == NULL) - return -1; - - /* If the attribute trying to be set is the "stop" method, - but we already have a condition set in the CLI, disallow this - operation. */ - if (strcmp (attr, stop_func) == 0 && obj->bp->cond_string) - { - xfree (attr); - PyErr_SetString (PyExc_RuntimeError, - _("Cannot set 'stop' method. There is an " \ - "existing GDB condition attached to the " \ - "breakpoint.")); - return -1; - } - - xfree (attr); - - return PyObject_GenericSetAttr ((PyObject *)self, name, v); -} - static PyGetSetDef breakpoint_object_getset[] = { { "enabled", bppy_get_enabled, bppy_set_enabled, "Boolean telling whether the breakpoint is enabled.", NULL }, @@ -1034,7 +1003,7 @@ PyTypeObject breakpoint_object_type = 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ - (setattrofunc)local_setattro, /*tp_setattro */ + 0, /*tp_setattro */ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ "GDB breakpoint object", /* tp_doc */ diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp index e2a169b..03c4f92 100644 --- a/gdb/testsuite/gdb.python/py-breakpoint.exp +++ b/gdb/testsuite/gdb.python/py-breakpoint.exp @@ -257,25 +257,39 @@ gdb_test "python print (also_eval_bp1.count)" "4" \ gdb_test "python print (eval_bp1.count)" "4" \ "Check non firing same-location breakpoint eval function was also called at each stop." +# Test mixed CLI/Python breakpoint conditions. + delete_breakpoints set cond_bp [gdb_get_line_number "Break at multiply."] gdb_py_test_silent_cmd "python eval_bp1 = bp_eval(\"$cond_bp\")" "Set breakpoint" 0 set test_cond {cond $bpnum} -gdb_test "$test_cond \"foo==3\"" "Cannot set a condition where a Python.*" \ - "Check you cannot add a CLI condition to a Python breakpoint that" \ +gdb_test_no_output "$test_cond \"foo==3\"" \ + "Check you can add a CLI condition to a Python breakpoint that" \ "has defined stop" + +if ![runto_main] then { + fail "Cannot run to main." + return 0 +} +delete_breakpoints gdb_py_test_silent_cmd "python eval_bp2 = basic(\"$cond_bp\")" "Set breakpoint" 0 -gdb_py_test_silent_cmd "python eval_bp2.condition = \"1==1\"" "Set a condition" 0 +gdb_py_test_silent_cmd "python eval_bp2.condition = \"i==3\"" "Set a condition" 0 gdb_py_test_multiple "Construct an eval function" \ "python" "" \ "def stop_func ():" "" \ - " return True" "" \ + " return gdb.parse_and_eval(\"i\") == 1" "" \ "end" "" +gdb_py_test_silent_cmd "python eval_bp2.stop = stop_func" \ + "Assign stop function to a breakpoint that has a condition" 1 +gdb_continue_to_breakpoint "Break at multiply." ".*/$srcfile:$bp_location2.*" +gdb_test "print i" "1" "Check python condition triggered" +gdb_continue_to_breakpoint "Break at multiply." ".*/$srcfile:$bp_location2.*" +gdb_test "print i" "3" "Check cli condition triggered" -gdb_test "python eval_bp2.stop = stop_func" \ - "RuntimeError: Cannot set 'stop' method.*" \ - "Assign stop function to a breakpoint that has a condition" - +if ![runto_main] then { + fail "Cannot run to main." + return 0 +} delete_breakpoints gdb_breakpoint [gdb_get_line_number "Break at multiply."] gdb_py_test_silent_cmd "python check_eval = bp_eval(\"$bp_location2\")" "Set breakpoint" 0