From patchwork Thu Dec 7 15:12:32 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Muldoon X-Patchwork-Id: 24777 Received: (qmail 58340 invoked by alias); 7 Dec 2017 15:12:40 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 57756 invoked by uid 89); 7 Dec 2017 15:12:39 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.2 spammy= X-HELO: mail-wm0-f67.google.com Received: from mail-wm0-f67.google.com (HELO mail-wm0-f67.google.com) (74.125.82.67) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 07 Dec 2017 15:12:36 +0000 Received: by mail-wm0-f67.google.com with SMTP id 9so13602527wme.4 for ; Thu, 07 Dec 2017 07:12:36 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :mime-version:in-reply-to:content-language; bh=pbmG8zigrEAi0PXO6GhCRAT5davpv78YumjsLVReAzc=; b=LN77spD5tNBjsTNRhsRJL5eQkZXQbdTaCzx8NZMm5t+YrIry/4wQ6kaJUp5jb3zduC 4/EWgaL8cwTOXH3YLWXl2XKmn/jB1+F94KHpVkiid3klxSeA8qZFWzFaaGccJWF9U0QH /Ezl6hAIPMZuXYNpSZE6ZDYHMsL9/iIlw8uVAEj/pU5eDMnYQvSICywrlHmxkY7W15kO e/orYdnnFHw7FsfhrQeqW0RFY1e0ggcVMBtJRsHmW1POrpffVsgXWr74g3SnBZjbIRAj YxihleBmXz1dVKyNsChipxzfzQkSfzQbPsXajnuA3IAQJejaoRht3bG+MTXP7vy8/w5/ mEOA== X-Gm-Message-State: AKGB3mIF2tWsquRv+ocYcAqhV2biE62SuwsdhTNOFpjm9qF+V/PLTaQA dKTXMbaXtNwVWG7tsK4zxHzPe77gidaIDw== X-Google-Smtp-Source: AGs4zMbAsMlH3iy/l3fI/zzZkMS7U9/IByvUxHdf4HOAsqF1LPyLL49ECEyuVb1vtcf5rQvElb+0wQ== X-Received: by 10.28.1.14 with SMTP id 14mr1514338wmb.51.1512659554382; Thu, 07 Dec 2017 07:12:34 -0800 (PST) Received: from ?IPv6:2a02:c7f:ae6a:ed00:4685:ff:fe66:9f4? ([2a02:c7f:ae6a:ed00:4685:ff:fe66:9f4]) by smtp.gmail.com with ESMTPSA id n7sm6101774wra.23.2017.12.07.07.12.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 07 Dec 2017 07:12:32 -0800 (PST) Subject: Re: [python] Allow explicit locations in breakpoints. To: Simon Marchi Cc: Simon Marchi , Keith Seitz , palves@redhat.com, eliz@gnu.org, gdb-patches@sourceware.org References: <04ccc2c4-7827-eedc-d8db-a83a0167acb6@redhat.com> <58311250-9ab1-39d1-99b6-07478bc8c2ab@redhat.com> <4768c7ad-cc3d-5702-fa93-40e9760d4ee8@ericsson.com> <81f2b22a-ba79-cc7c-ee85-95d2d433a90e@ericsson.com> <1765bb88-8ab0-bdcd-8551-69f8dff3bcb9@redhat.com> <31ad8fb7-0e20-13a5-45d1-c9fa67b76e27@ericsson.com> <9e817c74-170d-b7ee-e49b-0287215eab26@ericsson.com> From: Phil Muldoon Message-ID: <22a365d9-48b6-2330-5bbe-13115d0404a7@redhat.com> Date: Thu, 7 Dec 2017 15:12:32 +0000 MIME-Version: 1.0 In-Reply-To: X-IsSubscribed: yes On 07/12/17 14:54, Simon Marchi wrote: > On 2017-12-07 07:15, Phil Muldoon wrote: >> On 07/12/17 10:02, Phil Muldoon wrote: >>> On 23/11/17 22:17, Simon Marchi wrote: >>>> On 2017-11-17 06:02 AM, Phil Muldoon wrote: >> Phil > > Thanks for the git-am format, it's usually easier to apply. However, I can't seem to find the right baseline. Which commit did you base this on? If it is old-ish, would it be possible for you to rebase it to current master? > > Thanks, > > Simon Apologies, my github branch was more behind master than I at first thought. I've attached the update patch. Cheers, Phil From: Phil Muldoon Date: Thu, 7 Dec 2017 15:05:51 +0000 Subject: [PATCH] Implement explicit locations for Python breakpoints. Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit This introduces several new keywords to the bppy_init constructor. The spec parameter is now optional but mutually exclusive to the explicit keywords source, label, function and line. gdb/ChangeLog 2017-12-07 Phil Muldoon * python/py-breakpoint.c (bppy_init): Use string_to_event_location over basic location code. Implement explicit location keywords. (bppy_init_validate_args): New function. * NEWS: Document Python explicit breakpoint locations. doc/ChangeLog 2017-12-07 Phil Muldoon * python.texi (Breakpoints In Python): Add text relating to allowed explicit locations and keywords in gdb.Breakpoints. testsuite/ChangeLog 2017-12-07 Phil Muldoon * gdb.python/py-breakpoint.exp (test_bkpt_explicit_loc): Add new tests for explicit locations. --- gdb/NEWS | 4 + gdb/doc/python.texi | 41 +++++---- gdb/python/py-breakpoint.c | 134 ++++++++++++++++++++++++++--- gdb/testsuite/gdb.python/py-breakpoint.c | 2 +- gdb/testsuite/gdb.python/py-breakpoint.exp | 80 +++++++++++++++++ 5 files changed, 228 insertions(+), 33 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index 2262b259a8..72b4057f4d 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -115,6 +115,10 @@ command allows the setting of a large number of breakpoints via a regex pattern in Python. See the manual for further details. + ** Python breakpoints can now accept explicit locations. See the + manual for a further description of this feature. + + * New features in the GDB remote stub, GDBserver ** GDBserver is now able to start inferior processes with a diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index f411f60d7e..28a7a1a9f5 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -4878,27 +4878,30 @@ represented as Python @code{Long} values. Python code can manipulate breakpoints via the @code{gdb.Breakpoint} class. -@defun Breakpoint.__init__ (spec @r{[}, type @r{[}, wp_class @r{[},internal @r{[},temporary@r{]]]]}) +@defun Breakpoint.__init__ (spec @r{[}, type @r{[}, wp_class @r{[}, internal @r{[}, temporary @r{]}, source @r{]}, function @r{]}, label @r{]}, line @r{]]]]]]]]}) Create a new breakpoint according to @var{spec}, which is a string naming the location of the breakpoint, or an expression that defines a -watchpoint. The contents can be any location recognized by the -@code{break} command, or in the case of a watchpoint, by the -@code{watch} command. The optional @var{type} denotes the breakpoint -to create from the types defined later in this chapter. This argument -can be either @code{gdb.BP_BREAKPOINT} or @code{gdb.BP_WATCHPOINT}; it -defaults to @code{gdb.BP_BREAKPOINT}. The optional @var{internal} -argument allows the breakpoint to become invisible to the user. The -breakpoint will neither be reported when created, nor will it be -listed in the output from @code{info breakpoints} (but will be listed -with the @code{maint info breakpoints} command). The optional -@var{temporary} argument makes the breakpoint a temporary breakpoint. -Temporary breakpoints are deleted after they have been hit. Any -further access to the Python breakpoint after it has been hit will -result in a runtime error (as that breakpoint has now been -automatically deleted). The optional @var{wp_class} argument defines -the class of watchpoint to create, if @var{type} is -@code{gdb.BP_WATCHPOINT}. If a watchpoint class is not provided, it -is assumed to be a @code{gdb.WP_WRITE} class. +watchpoint. The contents can be any location recognized by the +@code{break} command or, in the case of a watchpoint, by the +@code{watch} command. Alternatively, create a new a explicit location +breakpoint (@pxref{Explicit Locations}) according to the +specifications contained in the key words @var{source}, +@var{function}, @var{label} and @var{line}. The optional @var{type} +denotes the breakpoint to create from the types defined later in this +chapter. This argument can be either @code{gdb.BP_BREAKPOINT} or +@code{gdb.BP_WATCHPOINT}; it defaults to @code{gdb.BP_BREAKPOINT}. +The optional @var{internal} argument allows the breakpoint to become +invisible to the user. The breakpoint will neither be reported when +created, nor will it be listed in the output from @code{info +breakpoints} (but will be listed with the @code{maint info +breakpoints} command). The optional @var{temporary} argument makes +the breakpoint a temporary breakpoint. Temporary breakpoints are +deleted after they have been hit. Any further access to the Python +breakpoint after it has been hit will result in a runtime error (as +that breakpoint has now been automatically deleted). The optional +@var{wp_class} argument defines the class of watchpoint to create, if +@var{type} is @code{gdb.BP_WATCHPOINT}. If a watchpoint class is not +provided, it is assumed to be a @code{gdb.WP_WRITE} class. @end defun The available types are represented by constants defined in the @code{gdb} diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c index 2574683ed4..f865317ab3 100644 --- a/gdb/python/py-breakpoint.c +++ b/gdb/python/py-breakpoint.c @@ -32,6 +32,7 @@ #include "language.h" #include "location.h" #include "py-event.h" +#include "linespec.h" /* Number of live breakpoints. */ static int bppy_live; @@ -631,25 +632,104 @@ bppy_get_ignore_count (PyObject *self, void *closure) return PyInt_FromLong (self_bp->bp->ignore_count); } +/* Internal function to validate the Python parameters/keywords + provided to bppy_init. */ + +static int +bppy_init_validate_args (const char *spec, char *source, + char *function, char *label, + char *line, enum bptype type) +{ + /* If spec is defined, ensure that none of the explicit location + keywords are also defined. */ + if (spec != NULL) + { + if (source != NULL || function != NULL || label != NULL || line != NULL) + { + PyErr_SetString (PyExc_RuntimeError, + _("Breakpoints specified with spec cannot " + "have source, function, label or line defined.")); + return -1; + } + } + else + { + /* If spec isn't defined, ensure that the user is not trying to + define a watchpoint with an explicit location. */ + if (type == bp_watchpoint) + { + PyErr_SetString (PyExc_RuntimeError, + _("Watchpoints cannot be set by explicit " + "location parameters.")); + return -1; + } + else + { + /* Otherwise, ensure some explicit locations are defined. */ + if (source == NULL && function == NULL && label == NULL + && line == NULL) + { + PyErr_SetString (PyExc_RuntimeError, + _("Neither spec nor explicit location set.")); + return -1; + } + /* Finally, if source is specified, ensure that line, label + or function are specified too. */ + if (source != NULL && function == NULL && label == NULL + && line == NULL) + { + PyErr_SetString (PyExc_RuntimeError, + _("Specifying a source must also include a " + "line, label or function.")); + return -1; + } + } + } + return 1; +} + /* Python function to create a new breakpoint. */ static int bppy_init (PyObject *self, PyObject *args, PyObject *kwargs) { static const char *keywords[] = { "spec", "type", "wp_class", "internal", - "temporary", NULL }; - const char *spec; - int type = bp_breakpoint; + "temporary","source", "function", + "label", "line", NULL }; + const char *spec = NULL; + enum bptype type = bp_breakpoint; int access_type = hw_write; PyObject *internal = NULL; PyObject *temporary = NULL; + PyObject *lineobj = NULL;; int internal_bp = 0; int temporary_bp = 0; + gdb::unique_xmalloc_ptr line; + char *label = NULL; + char *source = NULL; + char *function = NULL; - if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "s|iiOO", keywords, + if (!gdb_PyArg_ParseTupleAndKeywords (args, kwargs, "|siiOOsssO", keywords, &spec, &type, &access_type, - &internal, &temporary)) + &internal, + &temporary, &source, + &function, &label, &lineobj)) return -1; + + if (lineobj != NULL) + { + if (PyInt_Check (lineobj)) + line.reset (xstrprintf ("%ld", PyInt_AsLong (lineobj))); + else if (PyString_Check (lineobj)) + line = python_string_to_host_string (lineobj); + else + { + PyErr_SetString (PyExc_RuntimeError, + _("Line keyword should be an integer or a string. ")); + return -1; + } + } + if (internal) { internal_bp = PyObject_IsTrue (internal); @@ -664,23 +744,47 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs) return -1; } + if (bppy_init_validate_args (spec, source, function, label, line.get (), + type) == -1) + return -1; + bppy_pending_object = (gdbpy_breakpoint_object *) self; bppy_pending_object->number = -1; bppy_pending_object->bp = NULL; TRY { - gdb::unique_xmalloc_ptr - copy_holder (xstrdup (skip_spaces (spec))); - const char *copy = copy_holder.get (); - switch (type) { case bp_breakpoint: { - event_location_up location - = string_to_event_location_basic (©, current_language, - symbol_name_match_type::WILD); + event_location_up location; + + if (spec != NULL) + { + gdb::unique_xmalloc_ptr + copy_holder (xstrdup (skip_spaces (spec))); + const char *copy = copy_holder.get (); + + location = string_to_event_location (©, + current_language); + } + else + { + struct explicit_location explicit_loc; + + initialize_explicit_location (&explicit_loc); + explicit_loc.source_filename = source; + explicit_loc.function_name = function; + explicit_loc.label_name = label; + + if (line != NULL) + explicit_loc.line_offset = + linespec_parse_line_offset (line.get ()); + + location = new_explicit_location (&explicit_loc); + } + create_breakpoint (python_gdbarch, location.get (), NULL, -1, NULL, 0, @@ -691,8 +795,12 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs) 0, 1, internal_bp, 0); break; } - case bp_watchpoint: + case bp_watchpoint: { + gdb::unique_xmalloc_ptr + copy_holder (xstrdup (skip_spaces (spec))); + char *copy = copy_holder.get (); + if (access_type == hw_write) watch_command_wrapper (copy, 0, internal_bp); else if (access_type == hw_access) diff --git a/gdb/testsuite/gdb.python/py-breakpoint.c b/gdb/testsuite/gdb.python/py-breakpoint.c index df6163e53a..562cab35f7 100644 --- a/gdb/testsuite/gdb.python/py-breakpoint.c +++ b/gdb/testsuite/gdb.python/py-breakpoint.c @@ -24,7 +24,7 @@ int multiply (int i) int add (int i) { - return i + i; + return i + i; /* Break at function add. */ } diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp index 6c39f13696..e89b9b8446 100644 --- a/gdb/testsuite/gdb.python/py-breakpoint.exp +++ b/gdb/testsuite/gdb.python/py-breakpoint.exp @@ -531,6 +531,85 @@ proc_with_prefix test_bkpt_events {} { check_last_event breakpoint_deleted } +proc test_bkpt_explicit_loc {} { + global srcfile testfile + + with_test_prefix test_bkpt_invisible { + # Start with a fresh gdb. + clean_restart ${testfile} + + if ![runto_main] then { + fail "cannot run to main." + return 0 + } + + delete_breakpoints + + set bp_location1 [gdb_get_line_number "Break at multiply."] + set bp_location2 [gdb_get_line_number "Break at add."] + + gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (line=$bp_location1)" \ + "set explicit breakpoint by line" 0 + gdb_continue_to_breakpoint "break at multiply for explicit line" \ + ".*Break at multiply.*" + + gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (line=\"+1\")" \ + "set explicit breakpoint by relative line" 0 + gdb_continue_to_breakpoint "break at add for relative line" \ + ".*Break at add.*" + + delete_breakpoints + gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (line=\"-1\")" \ + "set explicit breakpoint by relative negative line" 0 + gdb_continue_to_breakpoint "break at multiply for negative line" \ + ".*Break at multiply.*" + + delete_breakpoints + gdb_test "python bp1 = gdb.Breakpoint (line=bp1)" \ + "RuntimeError: Line keyword should be an integer or a string.*" \ + "set explicit breakpoint by invalid line type" + + delete_breakpoints + gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (function=\"add\")" \ + "set explicit breakpoint by function" 0 + gdb_continue_to_breakpoint "break at function add for function" \ + ".*Break at function add.*" + + delete_breakpoints + gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (source=\"$srcfile\", function=\"add\")" \ + "set explicit breakpoint by source file and function" 0 + gdb_continue_to_breakpoint "break at function add for source and function" \ + ".*Break at function add.*" + + delete_breakpoints + gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (source=\"$srcfile\", line=\"$bp_location2\")" \ + "set explicit breakpoint by source file and line number" 0 + gdb_continue_to_breakpoint "break at add for source and line" \ + ".*Break at add.*" + + delete_breakpoints + gdb_py_test_silent_cmd "python bp1 = gdb.Breakpoint (\"-source $srcfile -line $bp_location2\")" \ + "set explicit breakpoint by source file and line number in spec" 0 + gdb_continue_to_breakpoint "break at add for source and line in spec" \ + ".*Break at add.*" + + delete_breakpoints + gdb_test "python bp1 = gdb.Breakpoint (source=\"$srcfile\")" \ + "RuntimeError: Specifying a source must also include a line, label or function.*" \ + "set invalid explicit breakpoint by source only" + + gdb_test "python bp1 = gdb.Breakpoint (source=\"foo.c\", line=\"5\")" \ + "No source file named foo.*" \ + "set invalid explicit breakpoint by missing source and line" + gdb_test "python bp1 = gdb.Breakpoint (source=\"$srcfile\", line=\"900\")" \ + "No line 900 in file \"$srcfile\".*" \ + "set invalid explicit breakpoint by source and invalid line" + gdb_test "python bp1 = gdb.Breakpoint (function=\"blah\")" \ + "Function \"blah\" not defined.*" \ + "set invalid explicit breakpoint by missing function" + } +} + test_bkpt_basic test_bkpt_deletion test_bkpt_cond_and_cmds @@ -542,3 +621,4 @@ test_bkpt_temporary test_bkpt_address test_bkpt_pending test_bkpt_events +test_bkpt_explicit_loc -- 2.14.3