[PING][PATCH v5] gdb/python: Add BreakpointLocation type
Simon Farre
simon.farre.cx@gmail.com
Mon May 2 15:59:38 GMT 2022
The most recent patch after it had been reviewed by Tom and others. Would
appreciate any further input
Thanks!
On Wed, Apr 20, 2022 at 10:37 AM Simon Farre <simon.farre.cx@gmail.com>
wrote:
> v5:
> PR python/18385
>
> Changes in response to review by Tom Tromey:
> - Replaced manual INCREF/DECREF calls with
> gdbpy_ref ptrs in places where possible.
> - Fixed non-gdb style conforming formatting
> - Get parent of bploc increases ref count of parent.
> - moved bploc Python definition to py-breakpoint.c
>
> The INCREF of self in bppy_get_locations is due
> to the individual locations holding a reference to
> it's owner. This is decremented at de-alloc time.
>
> The reason why this needs to be here is, if the user writes
> for instance;
>
> py loc = gdb.breakpoints()[X].locations[Y]
>
> The breakpoint owner object is immediately going
> out of scope (GC'd/dealloced), and the location
> object requires it to be alive for as long as it is alive.
>
> Thanks for your review, Tom!
>
> v4:
> Fixed remaining doc issues as per request
> by Eli.
>
> v3:
> Rewritten commit message, shortened + reworded,
> added tests.
>
> Currently, the Python API lacks the ability to
> query breakpoints for their installed locations,
> and subsequently, can't query any information about them, or
> enable/disable individual locations.
>
> This patch solves this by adding Python type gdb.BreakpointLocation.
> The type is never instantiated by the user of the Python API directly,
> but is produced by the gdb.Breakpoint.locations attribute returning
> a list of gdb.BreakpointLocation.
>
> gdb.Breakpoint.locations:
> The attribute for retrieving the currently installed breakpoint
> locations for gdb.Breakpoint. Matches behavior of
> the "info breakpoints" command in that it only
> returns the last known or currently inserted breakpoint locations.
>
> BreakpointLocation contains 4 attributes
>
> 3 read-only attributes:
> parent: location owner's Python companion object
> source: file path and line number tuple: (string, long) / None
> address: installed address of the location
>
> 1 writeable attribute:
> enabled: get/set enable/disable this location (bool)
>
> Access/calls to these, can all throw Python exceptions (documented in
> the online documentation), and that's due to the nature
> of how breakpoint locations can be invalidated
> "behind the scenes", either by them being removed
> from the original breakpoint or changed,
> like for instance when a new symbol file is loaded, at
> which point all breakpoint locations are re-created by GDB.
> Therefore this patch has chosen to be non-intrusive:
> it's up to the Python user to re-request the locations if
> they become invalid.
>
> Also there's event handlers that handle new object files etc, if a Python
> user is storing breakpoint locations in some larger state they've
> built up, refreshing the locations is easy and it only comes
> with runtime overhead when the Python user wants to use them.
>
> gdb.BreakpointLocation Python type
> struct "gdbpy_breakpoint_location_object" is found in python-interal.h
>
> It's definition, layout, methods and functions
> is found in the same file as gdb.Breakpoint (py-breakpoint.c)
>
> 1 change were also made to breakpoint.h/c to make it possible
> to enable and disable a bp_location* specifically,
> without having it's LOC_NUM, as this number
> also can change arbitrarily behind the scenes.
>
> Fixed formatting to follow GNU.
>
> Updated docs & news file as per request.
>
> Testsuite: tests the .source attribute and the disabling of
> individual locations.
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=18385
> ---
> gdb/NEWS | 5 +
> gdb/breakpoint.c | 63 +++++
> gdb/breakpoint.h | 5 +
> gdb/doc/python.texi | 50 ++++
> gdb/python/py-breakpoint.c | 242 +++++++++++++++++++
> gdb/python/python-internal.h | 22 ++
> gdb/python/python.c | 1 +
> gdb/testsuite/gdb.python/py-bp-locations.c | 32 +++
> gdb/testsuite/gdb.python/py-bp-locations.exp | 62 +++++
> 9 files changed, 482 insertions(+)
> create mode 100644 gdb/testsuite/gdb.python/py-bp-locations.c
> create mode 100644 gdb/testsuite/gdb.python/py-bp-locations.exp
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 760cb2b7abc..96b6ae04684 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -38,6 +38,11 @@ maintenance info line-table
> This is the same format that GDB uses when printing address, symbol,
> and offset information from the disassembler.
>
> + ** New Python type gdb.BreakpointLocation.
> + The new attribute 'locations' of gdb.Breakpoint returns a list of
> + gdb.BreakpointLocation objects specifying the locations where the
> + breakpoint is inserted into the debuggee.
> +
> *** Changes in GDB 12
>
> * DBX mode is deprecated, and will be removed in GDB 13
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index b21d83d8019..e3106c53fca 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -175,6 +175,8 @@ static void enable_breakpoint_disp (struct breakpoint
> *, enum bpdisp,
>
> static void decref_bp_location (struct bp_location **loc);
>
> +static int find_loc_num_by_location (bp_location* loc);
> +
> static struct bp_location *allocate_bp_location (struct breakpoint *bpt);
>
> /* update_global_location_list's modes of operation wrt to whether to
> @@ -13660,6 +13662,67 @@ enable_disable_bp_num_loc (int bp_num, int
> loc_num, bool enable)
> gdb::observers::breakpoint_modified.notify (loc->owner);
> }
>
> +/* Enable or disable a breakpoint location LOC. ENABLE
> + specifies whether to enable or disable. */
> +
> +void
> +enable_disable_bp_location (bp_location *loc, bool enable)
> +{
> + if (loc == nullptr)
> + error (_("Breakpoint location is invalid."));
> +
> + if (loc->owner == nullptr)
> + error (_("Breakpoint location does not belong to an owner."));
> +
> + if (loc->disabled_by_cond && enable)
> + {
> + int loc_num = find_loc_num_by_location (loc);
> + if (loc_num == -1)
> + error (_("Breakpoint location LOC_NUM could not be found."));
> + else
> + error (_("Breakpoint %d's condition is invalid at location %d, "
> + "cannot enable."), loc->owner->number, loc_num);
> + }
> +
> + if (loc->enabled != enable)
> + {
> + loc->enabled = enable;
> + mark_breakpoint_location_modified (loc);
> + }
> +
> + if (target_supports_enable_disable_tracepoint ()
> + && current_trace_status ()->running && loc->owner
> + && is_tracepoint (loc->owner))
> + target_disable_tracepoint (loc);
> +
> + update_global_location_list (UGLL_DONT_INSERT);
> + gdb::observers::breakpoint_modified.notify (loc->owner);
> +}
> +
> +/* Calculates LOC_NUM for LOC by traversing the bp_location chain of LOC's
> + owner. 1-based indexing. -1 signals NOT FOUND. */
> +
> +static int
> +find_loc_num_by_location (bp_location *loc)
> +{
> + if (loc)
> + {
> + if (loc->owner)
> + {
> + // begin at 1.1, 1.2 ... locs are not 0-indexed at cmdline
> + int loc_num = 1;
> + for (bp_location *it = loc->owner->loc; it != nullptr; it =
> it->next)
> + {
> + if (it == loc)
> + return loc_num;
> + loc_num++;
> + }
> + }
> + return -1;
> + }
> + return -1;
> +}
> +
> /* Enable or disable a range of breakpoint locations. BP_NUM is the
> number of the breakpoint, and BP_LOC_RANGE specifies the
> (inclusive) range of location numbers of that breakpoint to
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index e412c4d4113..b39aaef9c16 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -1803,4 +1803,9 @@ extern void catch_exception_event (enum
> exception_event_kind ex_event,
> const char *regex, bool tempflag,
> int from_tty);
>
> +/* Enable or disable a breakpoint location LOC. ENABLE
> + specifies whether to enable or disable. */
> +
> +extern void enable_disable_bp_location (bp_location *loc, bool enable);
> +
> #endif /* !defined (BREAKPOINT_H) */
> diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
> index 7c414b01d70..fe7f5d85338 100644
> --- a/gdb/doc/python.texi
> +++ b/gdb/doc/python.texi
> @@ -6046,6 +6046,15 @@ the user. It is a string. If the breakpoint does
> not have a location
> attribute is not writable.
> @end defvar
>
> +@defvar Breakpoint.locations
> +Get the most current list of breakpoint locations that are inserted for
> this
> +breakpoint, with elements of type @code{gdb.BreakpointLocation}
> +(described below). This functionality matches that of the
> +@code{info breakpoint} command (@pxref{Set Breaks}), in that it only
> retrieves
> +the most current list of locations, thus the list itself when returned is
> +not updated behind the scenes. This attribute is not writable.
> +@end defvar
> +
> @defvar Breakpoint.expression
> This attribute holds a breakpoint expression, as specified by
> the user. It is a string. If the breakpoint does not have an
> @@ -6066,6 +6075,47 @@ commands, separated by newlines. If there are no
> commands, this
> attribute is @code{None}. This attribute is writable.
> @end defvar
>
> +@subheading Breakpoint Locations
> +
> +A breakpoint location is one of the actual places that a breakpoint has
> been
> +inserted, represented in the Python API by the
> @code{gdb.BreakpointLocation}
> +type. This type is never instantiated by the user directly, but is
> retrieved
> +from @code{Breakpoint.locations} which returns a list of breakpoint
> +locations where it is currently inserted. Breakpoint locations can become
> +invalid if new symbol files are loaded or dynamically loaded libraries are
> +closed. Accessing the attributes of an invalidated breakpoint location
> will
> +throw a @code{RuntimeError} exception. Access the
> @code{Breakpoint.locations}
> +attribute again to retrieve the new and valid breakpoints location list.
> +
> +@defvar BreakpointLocation.source
> +This attribute returns the source file path and line number where this
> location
> +was inserted. The type of the attribute is a tuple of @var{string} and
> +@var{long}. If the breakpoint location doesn't have a source location,
> +it returns None, which is the case for watchpoints and catchpoints.
> +This will throw a @code{RuntimeError} exception if the location
> +has been invalidated. This attribute is not writable.
> +@end defvar
> +
> +@defvar BreakpointLocation.address
> +This attribute returns the address where this location was inserted.
> +This attribute is of type long. This will throw a @code{RuntimeError}
> +exception if the location has been invalidated. This attribute is
> +not writable.
> +@end defvar
> +
> +@defvar BreakpointLocation.enabled
> +This attribute holds the value for whether or not this location is
> enabled.
> +This attribute is writable (boolean). This will throw a
> @code{RuntimeError}
> +exception if the location has been invalidated.
> +@end defvar
> +
> +@defvar BreakpointLocation.parent
> +This attribute holds a reference to the @code{gdb.Breakpoint} owner
> object,
> +from which this @code{gdb.BreakpointLocation} was retrieved from.
> +This will throw a @code{RuntimeError} exception if the location has been
> +invalidated. This attribute is not writable.
> +@end defvar
> +
> @node Finish Breakpoints in Python
> @subsubsection Finish Breakpoints
>
> diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
> index 74de0d90e23..c88d5eaa468 100644
> --- a/gdb/python/py-breakpoint.c
> +++ b/gdb/python/py-breakpoint.c
> @@ -34,6 +34,20 @@
> #include "py-event.h"
> #include "linespec.h"
>
> +extern PyTypeObject breakpoint_location_object_type
> + CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("breakpoint_location_object");
> +
> +struct gdbpy_breakpoint_location_object
> +{
> + PyObject_HEAD
> +
> + /* The gdb breakpoint location object. */
> + bp_location* bp_loc;
> +
> + /* Breakpoint parent. */
> + gdbpy_breakpoint_object *parent;
> +};
> +
> /* Debugging of Python breakpoints. */
>
> static bool pybp_debug;
> @@ -692,6 +706,38 @@ bppy_get_ignore_count (PyObject *self, void *closure)
> return gdb_py_object_from_longest (self_bp->bp->ignore_count).release
> ();
> }
>
> +/* Python function to get the breakpoint locations from an owner
> breakpoint */
> +
> +static PyObject*
> +bppy_get_locations (PyObject *self, void *closure)
> +{
> + using py_bploc_t = gdbpy_breakpoint_location_object;
> + gdbpy_breakpoint_object *self_bp = (gdbpy_breakpoint_object *) self;
> + BPPY_REQUIRE_VALID (self_bp);
> +
> + gdbpy_ref<> list (PyList_New (0));
> + for (bp_location* loc = self_bp->bp->loc; loc; loc = loc->next)
> + {
> + gdbpy_ref<py_bploc_t> py_bploc (PyObject_New (py_bploc_t,
> + &breakpoint_location_object_type));
> + bp_location_ref_ptr ref = bp_location_ref_ptr::new_reference (loc);
> + py_bploc->parent = self_bp;
> +
> + /* The location takes a reference to the owner breakpoint.
> Decrements
> + when they are de-allocated in bplocpy_dealloc */
> + Py_INCREF (self);
> + if (PyList_Append (list.get (), (PyObject *) py_bploc.get ()) != 0)
> + {
> + /* Python C API docs do not describe if elements succesfully
> + added have their ref count decremented if this error is
> thrown.
> + If they don't, we leak references here. */
> + return nullptr;
> + }
> + py_bploc->bp_loc = ref.release ();
> + }
> + return list.release ();
> +}
> +
> /* Internal function to validate the Python parameters/keywords
> provided to bppy_init. */
>
> @@ -1182,6 +1228,20 @@ gdbpy_initialize_breakpoints (void)
> return 0;
> }
>
> +/* Initialize the Python BreakpointLocation code. */
> +
> +int
> +gdbpy_initialize_breakpoint_locations ()
> +{
> + if (PyType_Ready (&breakpoint_location_object_type) < 0)
> + return -1;
> +
> + if (gdb_pymodule_addobject (gdb_module, "BreakpointLocation",
> + (PyObject *) &breakpoint_location_object_type) < 0)
> + return -1;
> + return 0;
> +}
> +
>
>
> /* Helper function that overrides this Python object's
> @@ -1264,6 +1324,8 @@ or None if no condition set."},
> "Whether this breakpoint is a temporary breakpoint."},
> { "pending", bppy_get_pending, NULL,
> "Whether this breakpoint is a pending breakpoint."},
> + { "locations", bppy_get_locations, NULL,
> + "Get locations where this breakpoint was installed"},
> { NULL } /* Sentinel. */
> };
>
> @@ -1330,3 +1392,183 @@ _initialize_py_breakpoint ()
> show_pybp_debug,
> &setdebuglist, &showdebuglist);
> }
> +
> +/* Python function to set the enabled state of a breakpoint location. */
> +
> +static int
> +bplocpy_set_enabled (PyObject *py_self, PyObject *newvalue, void *closure)
> +{
> + gdbpy_breakpoint_location_object *self
> + = (gdbpy_breakpoint_location_object *) py_self;
> + BPPY_SET_REQUIRE_VALID (self->parent);
> + BPLOCPY_SET_REQUIRE_VALID (self->parent, self);
> +
> + if (newvalue == NULL)
> + {
> + PyErr_SetString (PyExc_TypeError,
> + _("Cannot delete 'enabled' attribute."));
> + return -1;
> + }
> + else if (!PyBool_Check (newvalue))
> + {
> + PyErr_SetString (PyExc_TypeError,
> + _("The value of 'enabled' must be a boolean."));
> + return -1;
> + }
> +
> + int cmp = PyObject_IsTrue (newvalue);
> + if (cmp < 0)
> + return -1;
> +
> + try
> + {
> + enable_disable_bp_location (self->bp_loc, cmp == 1);
> + }
> + catch (const gdb_exception &except)
> + {
> + GDB_PY_SET_HANDLE_EXCEPTION (except);
> + }
> + return 0;
> +}
> +
> +/* Python function to test whether or not the breakpoint location is
> enabled. */
> +
> +static PyObject *
> +bplocpy_get_enabled (PyObject *py_self, void *closure)
> +{
> + gdbpy_breakpoint_location_object *self
> + = (gdbpy_breakpoint_location_object *) py_self;
> + BPPY_REQUIRE_VALID (self->parent);
> + BPLOCPY_REQUIRE_VALID (self->parent, self);
> +
> + /* If the owner is disabled, all locations are disabled. */
> + if (self->parent->bp->enable_state == enable_state::bp_disabled)
> + Py_RETURN_FALSE;
> +
> + if (self->bp_loc->enabled == enable_state::bp_enabled)
> + Py_RETURN_TRUE;
> + else
> + Py_RETURN_FALSE;
> +}
> +
> +/* Python function to get address of breakpoint location. */
> +
> +static PyObject *
> +bplocpy_get_address (PyObject *py_self, void *closure)
> +{
> + gdbpy_breakpoint_location_object *self
> + = (gdbpy_breakpoint_location_object *) py_self;
> + BPPY_REQUIRE_VALID (self->parent);
> + BPLOCPY_REQUIRE_VALID (self->parent, self);
> + return PyLong_FromLong (self->bp_loc->address);
> +}
> +
> +/* Python function to get parent of breakpoint location, which
> + is of type gdb.Breakpoint. */
> +
> +static PyObject *
> +bplocpy_get_parent (PyObject *py_self, void *closure)
> +{
> + gdbpy_breakpoint_location_object *self
> + = (gdbpy_breakpoint_location_object *) py_self;
> + BPPY_REQUIRE_VALID (self->parent);
> + BPLOCPY_REQUIRE_VALID (self->parent, self);
> + Py_INCREF (self->parent);
> + return (PyObject *) self->parent;
> +}
> +
> +/* Python function to get the source file name path and line number
> + where this breakpoint location was installed. */
> +
> +static PyObject *
> +bplocpy_get_source_location (PyObject *py_self, void *closure)
> +{
> + gdbpy_breakpoint_location_object *self
> + = (gdbpy_breakpoint_location_object *) py_self;
> + BPPY_REQUIRE_VALID (self->parent);
> + BPLOCPY_REQUIRE_VALID (self->parent, self);
> + if (self->bp_loc->symtab)
> + {
> + gdbpy_ref<> tup (PyTuple_New (2));
> + /* symtab->filename is never NULL. */
> + gdbpy_ref<> filename
> + = host_string_to_python_string (self->bp_loc->symtab->filename);
> +
> + if (PyTuple_SetItem (tup.get (), 0, filename.release ()) == -1
> + || PyTuple_SetItem (tup.get (), 1,
> + PyLong_FromLong (self->bp_loc->line_number)) == -1)
> + {
> + return nullptr;
> + }
> + return tup.release ();
> + }
> + else
> + Py_RETURN_NONE;
> +}
> +
> +/* De-allocation function to be called for the Python object. */
> +
> +static void
> +bplocpy_dealloc (PyObject *py_self)
> +{
> + gdbpy_breakpoint_location_object *self
> + = (gdbpy_breakpoint_location_object *) py_self;
> + bp_location_ref_policy::decref (self->bp_loc);
> + Py_DECREF (self->parent);
> + Py_TYPE (py_self)->tp_free (py_self);
> +}
> +
> +/* Attribute get/set Python definitions. */
> +
> +static gdb_PyGetSetDef bp_location_object_getset[] = {
> + { "enabled", bplocpy_get_enabled, bplocpy_set_enabled,
> + "Boolean telling whether the breakpoint is enabled.", NULL },
> + { "parent", bplocpy_get_parent, NULL,
> + "Get the parent breakpoint object", NULL },
> + { "address", bplocpy_get_address, NULL,
> + "Get install address of this breakpoint location", NULL},
> + { "source", bplocpy_get_source_location, NULL,
> + "Get file and line number where breakpoint was installed", NULL},
> + { NULL } /* Sentinel. */
> +};
> +
> +PyTypeObject breakpoint_location_object_type =
> +{
> + PyVarObject_HEAD_INIT (NULL, 0)
> + "gdb.BreakpointLocation", /*tp_name*/
> + sizeof (gdbpy_breakpoint_location_object), /*tp_basicsize*/
> + 0, /*tp_itemsize*/
> + bplocpy_dealloc, /*tp_dealloc*/
> + 0, /*tp_print*/
> + 0, /*tp_getattr*/
> + 0, /*tp_setattr*/
> + 0, /*tp_compare*/
> + 0, /*tp_repr*/
> + 0, /*tp_as_number*/
> + 0, /*tp_as_sequence*/
> + 0, /*tp_as_mapping*/
> + 0, /*tp_hash */
> + 0, /*tp_call*/
> + 0, /*tp_str*/
> + 0, /*tp_getattro*/
> + 0, /*tp_setattro */
> + 0, /*tp_as_buffer*/
> + Py_TPFLAGS_DEFAULT, /*tp_flags*/
> + "GDB breakpoint location object", /* tp_doc */
> + 0, /* tp_traverse */
> + 0, /* tp_clear */
> + 0, /* tp_richcompare */
> + 0, /* tp_weaklistoffset */
> + 0, /* tp_iter */
> + 0, /* tp_iternext */
> + 0, /* tp_methods */
> + 0, /* tp_members */
> + bp_location_object_getset, /* tp_getset */
> + 0, /* tp_base */
> + 0, /* tp_dict */
> + 0, /* tp_descr_get */
> + 0, /* tp_descr_set */
> + 0, /* tp_dictoffset */
> + 0, /* tp_init */
> + 0, /* tp_alloc */
> +};
> diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
> index d947b96033b..784c3a02b8a 100644
> --- a/gdb/python/python-internal.h
> +++ b/gdb/python/python-internal.h
> @@ -322,6 +322,26 @@ struct gdbpy_breakpoint_object
> } \
> } while (0)
>
> +/* Require that BREAKPOINT and LOCATION's owner are the same; throw a
> Python
> + exception if it is not. */
> +#define BPLOCPY_REQUIRE_VALID(Breakpoint, Location)
> \
> + do {
> \
> + if ((Breakpoint)->bp != (Location)->bp_loc->owner)
> \
> + return PyErr_Format (PyExc_RuntimeError,
> \
> + _("Breakpoint location is invalid."));
> \
> + } while (0)
> +
> +/* Require that BREAKPOINT and LOCATION->OWNER are the same; throw a
> Python
> + exception if it is not. This macro is for use in setter functions. */
> +#define BPLOCPY_SET_REQUIRE_VALID(Breakpoint, Location)
> \
> + do {
> \
> + if ((Breakpoint)->bp != (Location)->bp_loc->owner)
> \
> + {
> \
> + PyErr_Format (PyExc_RuntimeError,
> \
> + _("Breakpoint location is invalid."));
> \
> + return -1;
> \
> + }
> \
> + } while (0)
>
> /* Variables used to pass information between the Breakpoint
> constructor and the breakpoint-created hook function. */
> @@ -505,6 +525,8 @@ int gdbpy_initialize_objfile (void)
> CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
> int gdbpy_initialize_breakpoints (void)
> CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
> +int gdbpy_initialize_breakpoint_locations ()
> + CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
> int gdbpy_initialize_finishbreakpoints (void)
> CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
> int gdbpy_initialize_lazy_string (void)
> diff --git a/gdb/python/python.c b/gdb/python/python.c
> index 7a9c8c1b66e..479cf6a296a 100644
> --- a/gdb/python/python.c
> +++ b/gdb/python/python.c
> @@ -2057,6 +2057,7 @@ do_start_initialization ()
> || gdbpy_initialize_pspace () < 0
> || gdbpy_initialize_objfile () < 0
> || gdbpy_initialize_breakpoints () < 0
> + || gdbpy_initialize_breakpoint_locations () < 0
> || gdbpy_initialize_finishbreakpoints () < 0
> || gdbpy_initialize_lazy_string () < 0
> || gdbpy_initialize_linetable () < 0
> diff --git a/gdb/testsuite/gdb.python/py-bp-locations.c
> b/gdb/testsuite/gdb.python/py-bp-locations.c
> new file mode 100644
> index 00000000000..388f5f28e58
> --- /dev/null
> +++ b/gdb/testsuite/gdb.python/py-bp-locations.c
> @@ -0,0 +1,32 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2022-2022 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. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>.
> */
> +
> +double add (double DoubleA, double DoubleB)
> +{
> + return DoubleA + DoubleB;
> +}
> +
> +int add (int IntA, int IntB)
> +{
> + return IntA + IntB;
> +}
> +
> +int main (void)
> +{
> + double d = add (1.0, 2.0);
> + int i = add (1, 2);
> +}
> diff --git a/gdb/testsuite/gdb.python/py-bp-locations.exp
> b/gdb/testsuite/gdb.python/py-bp-locations.exp
> new file mode 100644
> index 00000000000..b06b62de971
> --- /dev/null
> +++ b/gdb/testsuite/gdb.python/py-bp-locations.exp
> @@ -0,0 +1,62 @@
> +# Copyright (C) 2022-2022 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. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program. If not, see <http://www.gnu.org/licenses/>.
> +
> +if { ![support_displaced_stepping] } {
> + unsupported "displaced stepping"
> + return -1
> +}
> +
> +load_lib gdb-python.exp
> +
> +standard_testfile
> +
> +if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable
> {c++ debug}] != "" } {
> + return -1
> +}
> +
> +save_vars { GDBFLAGS } {
> + clean_restart $testfile
> +}
> +
> +if { [skip_python_tests] } { continue }
> +
> +if ![runto_main] {
> + return -1
> +}
> +
> +# set breakpoint with 2 locations
> +gdb_breakpoint "add"
> +
> +# test that the locations return correct source locations
> +gdb_test "python print(gdb.breakpoints()\[1\].locations\[0\].source)" \
> + ".*('.*py-bp-locations.c', 20).*"
> +gdb_test "python print(gdb.breakpoints()\[1\].locations\[1\].source)" \
> + ".*('.*py-bp-locations.c', 25).*"
> +
> +# disable first location and make sure we don't hit it
> +gdb_test "python gdb.breakpoints()\[1\].locations\[0\].enabled = False" ""
> +gdb_continue_to_breakpoint "" ".*25.*"
> +
> +if ![runto_main] {
> + return -1
> +}
> +
> +gdb_breakpoint "add"
> +# disable "add" master breakpoint and verify all locations are disabled.
> +gdb_test "python gdb.breakpoints()\[1\].enabled = False" "" "disable add
> master breakpoint"
> +gdb_breakpoint 32
> +
> +# Disable "master breakpoint" and test that all locations are disabled.
> +gdb_continue_to_breakpoint "end of main" ".*32.*"
>
> base-commit: 04f4c17c7a14ebb6c2212267b2ebc83f1376fe20
> --
> 2.32.0
>
>
More information about the Gdb-patches
mailing list