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
attribute is @code{None}. This attribute is writable.
@end defvar
+@subheading Breakpoint Locations
+
+A breakpoint location is one of the actual places where a breakpoint has been
+set, 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 set. 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 set. 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 set.
+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.owner
+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
+
+@defvar BreakpointLocation.function
+This attribute gets the name of the function where this location was set.
+If no function could be found this attribute returns @code{None}.
+This will throw a @code{RuntimeError} exception if the location has
+been invalidated. This attribute is not writable.
+@end defvar
+
+@defvar BreakpointLocation.fullname
+This attribute gets the full name of where this location was set. If no
+full name could be found, this attribute returns @code{None}.
+This will throw a @code{RuntimeError} exception if the location has
+been invalidated. This attribute is not writable.
+@end defvar
+
+@defvar BreakpointLocation.thread_groups
+This attribute gets the thread groups it was set in. It returns a @code{List}
+of the thread group ID's. 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
#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
+
+ /* An owning reference to the gdb breakpoint location object. */
+ bp_location *bp_loc;
+
+ /* An owning reference to the location's breakpoint owner. */
+ gdbpy_breakpoint_object *owner;
+};
+
+/* Require that BREAKPOINT and LOCATION->OWNER are the same; throw a Python
+ exception if they are 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 they are 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)
+
/* Debugging of Python breakpoints. */
static bool pybp_debug;
return gdb_py_object_from_longest (self_bp->bp->ignore_count).release ();
}
+/* Python function to get the breakpoint locations of an owner breakpoint. */
+
+static PyObject *
+bppy_get_locations (PyObject *self, void *closure)
+{
+ using py_bploc_t = gdbpy_breakpoint_location_object;
+ auto *self_bp = (gdbpy_breakpoint_object *) self;
+ BPPY_REQUIRE_VALID (self_bp);
+
+ gdbpy_ref<> list (PyList_New (0));
+ if (list == nullptr)
+ return nullptr;
+
+ for (bp_location *loc : self_bp->bp->locations ())
+ {
+ gdbpy_ref<py_bploc_t> py_bploc
+ (PyObject_New (py_bploc_t, &breakpoint_location_object_type));
+ if (py_bploc == nullptr)
+ return nullptr;
+
+ bp_location_ref_ptr ref = bp_location_ref_ptr::new_reference (loc);
+ /* The location takes a reference to the owner breakpoint.
+ Decrements when they are de-allocated in bplocpy_dealloc */
+ Py_INCREF (self);
+ py_bploc->owner = self_bp;
+ py_bploc->bp_loc = ref.release ();
+ if (PyList_Append (list.get (), (PyObject *) py_bploc.get ()) != 0)
+ return nullptr;
+ }
+ return list.release ();
+}
+
/* Internal function to validate the Python parameters/keywords
provided to bppy_init. */
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;
+}
+
\f
/* Helper function that overrides this Python object's
"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 set"},
{ NULL } /* Sentinel. */
};
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)
+{
+ auto *self = (gdbpy_breakpoint_location_object *) py_self;
+ BPPY_SET_REQUIRE_VALID (self->owner);
+ BPLOCPY_SET_REQUIRE_VALID (self->owner, self);
+
+ if (newvalue == nullptr)
+ {
+ 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)
+{
+ auto *self = (gdbpy_breakpoint_location_object *) py_self;
+ BPPY_REQUIRE_VALID (self->owner);
+ BPLOCPY_REQUIRE_VALID (self->owner, self);
+
+ if (self->bp_loc->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)
+{
+ auto *self = (gdbpy_breakpoint_location_object *) py_self;
+ BPPY_REQUIRE_VALID (self->owner);
+ BPLOCPY_REQUIRE_VALID (self->owner, self);
+ return gdb_py_object_from_ulongest (self->bp_loc->address).release ();
+}
+
+/* Python function to get owner of breakpoint location, which
+ is of type gdb.Breakpoint. */
+
+static PyObject *
+bplocpy_get_owner (PyObject *py_self, void *closure)
+{
+ auto *self = (gdbpy_breakpoint_location_object *) py_self;
+ BPPY_REQUIRE_VALID (self->owner);
+ BPLOCPY_REQUIRE_VALID (self->owner, self);
+ Py_INCREF (self->owner);
+ return (PyObject *) self->owner;
+}
+
+/* Python function to get the source file name path and line number
+ where this breakpoint location was set. */
+
+static PyObject *
+bplocpy_get_source_location (PyObject *py_self, void *closure)
+{
+ auto *self = (gdbpy_breakpoint_location_object *) py_self;
+ BPPY_REQUIRE_VALID (self->owner);
+ BPLOCPY_REQUIRE_VALID (self->owner, self);
+ if (self->bp_loc->symtab)
+ {
+ gdbpy_ref<> tup (PyTuple_New (2));
+ if (tup == nullptr)
+ return nullptr;
+ /* symtab->filename is never NULL. */
+ gdbpy_ref<> filename
+ = host_string_to_python_string (self->bp_loc->symtab->filename);
+ if (filename == nullptr)
+ return nullptr;
+ auto line = gdb_py_object_from_ulongest (self->bp_loc->line_number);
+ if (line == nullptr)
+ return nullptr;
+ if (PyTuple_SetItem (tup.get (), 0, filename.release ()) == -1
+ || PyTuple_SetItem (tup.get (), 1, line.release ()) == -1)
+ return nullptr;
+ return tup.release ();
+ }
+ else
+ Py_RETURN_NONE;
+}
+
+/* Python function to get the function name of where this location was set. */
+
+static PyObject *
+bplocpy_get_function (PyObject *py_self, void *closure)
+{
+ auto *self = (gdbpy_breakpoint_location_object *) py_self;
+ BPPY_REQUIRE_VALID (self->owner);
+ BPLOCPY_REQUIRE_VALID (self->owner, self);
+ const auto fn_name = self->bp_loc->function_name.get ();
+ if (fn_name != nullptr)
+ return host_string_to_python_string (fn_name).release ();
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+bplocpy_get_thread_groups (PyObject *py_self, void *closure)
+{
+ auto *self = (gdbpy_breakpoint_location_object *) py_self;
+ BPPY_REQUIRE_VALID (self->owner);
+ BPLOCPY_REQUIRE_VALID (self->owner, self);
+ gdbpy_ref<> list (PyList_New (0));
+ if (list == nullptr)
+ return nullptr;
+ for (inferior *inf : all_inferiors ())
+ {
+ if (inf->pspace == self->bp_loc->pspace)
+ {
+ gdbpy_ref<> num = gdb_py_object_from_ulongest (inf->num);
+ if (num == nullptr)
+ return nullptr;
+ if (PyList_Append (list.get (), num.release ()) != 0)
+ return nullptr;
+ }
+ }
+ return list.release ();
+}
+
+static PyObject *
+bplocpy_get_fullname (PyObject *py_self, void *closure)
+{
+ auto *self = (gdbpy_breakpoint_location_object *) py_self;
+ BPPY_REQUIRE_VALID (self->owner);
+ BPLOCPY_REQUIRE_VALID (self->owner, self);
+ const auto symtab = self->bp_loc->symtab;
+ if (symtab != nullptr && symtab->fullname != nullptr)
+ {
+ gdbpy_ref<> fullname
+ = host_string_to_python_string (symtab->fullname);
+ return fullname.release ();
+ }
+ Py_RETURN_NONE;
+}
+
+/* De-allocation function to be called for the Python object. */
+
+static void
+bplocpy_dealloc (PyObject *py_self)
+{
+ auto *self = (gdbpy_breakpoint_location_object *) py_self;
+ bp_location_ref_ptr decrementing_ref {self->bp_loc};
+ Py_XDECREF (self->owner);
+ 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 },
+ { "owner", bplocpy_get_owner, NULL,
+ "Get the breakpoint owner object", NULL },
+ { "address", bplocpy_get_address, NULL,
+ "Get address of where this location was set", NULL},
+ { "source", bplocpy_get_source_location, NULL,
+ "Get file and line number of where this location was set", NULL},
+ { "function", bplocpy_get_function, NULL,
+ "Get function of where this location was set", NULL },
+ { "fullname", bplocpy_get_fullname, NULL,
+ "Get fullname of where this location was set", NULL },
+ { "thread_groups", bplocpy_get_thread_groups, NULL,
+ "Get thread groups where this location is in", 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 */
+};