This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [patch] Add visible flag to breakpoints.
- From: Phil Muldoon <pmuldoon at redhat dot com>
- To: Pedro Alves <pedro at codesourcery dot com>
- Cc: gdb-patches at sourceware dot org, dan at codesourcery dot com
- Date: Fri, 08 Oct 2010 13:50:34 +0100
- Subject: Re: [patch] Add visible flag to breakpoints.
- References: <m38w2j72jd.fsf@redhat.com> <20100930144132.GA15652@caradoc.them.org> <m3hbh7qk6w.fsf@redhat.com> <201009301741.32379.pedro@codesourcery.com>
- Reply-to: pmuldoon at redhat dot com
Pedro Alves <pedro@codesourcery.com> writes:
> On Thursday 30 September 2010 17:18:15, Phil Muldoon wrote:
>> The original patch I wrote did use negative numbers for bp_breakpoint
>> type (in fact that patch is a commit in the archer branch:
>> archer-pmuldoon-python-breakpoints). But normal bp_breakpoints with a
>> negative number are still displayed with 'info breakpoints'. Currently
>> the visibility of breakpoints is not decided on their number but their
>> type.
>> breakpoint_1 tests for these in user_settable_breakpoint.
>
> I think that's just cruft and can be replaced by a b->number < 0 check?
Here is a rewritten version of the b->number == internal_breakpoint_count
patch. There are a bits in py-breakpoint.c I had to re-architect to
facilitate this. The ChangeLog entries remain largely the same: I will
rewrite them on patch acceptance.
Tested on X86-64 Fedora/Linux with no regressions
Cheers
Phil
--
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index b4502e7..1516989 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -4939,7 +4939,8 @@ breakpoint_1 (int bnum, int allflag, int (*filter) (const struct breakpoint *))
if (filter && !filter (b))
continue;
- if (allflag || user_settable_breakpoint (b))
+ if (allflag || (user_settable_breakpoint (b)
+ && b->number > 0))
{
int addr_bit, type_len;
@@ -5007,7 +5008,8 @@ breakpoint_1 (int bnum, int allflag, int (*filter) (const struct breakpoint *))
/* We only print out user settable breakpoints unless the
allflag is set. */
- if (allflag || user_settable_breakpoint (b))
+ if (allflag || (user_settable_breakpoint (b)
+ && b->number > 0))
print_one_breakpoint (b, &last_loc, print_address_bits, allflag);
}
}
@@ -6914,7 +6916,8 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
char *cond_string,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
- struct breakpoint_ops *ops, int from_tty, int enabled)
+ struct breakpoint_ops *ops, int from_tty,
+ int enabled, int internal)
{
struct breakpoint *b = NULL;
int i;
@@ -6951,8 +6954,13 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
if (i == 0)
{
b = set_raw_breakpoint (gdbarch, sal, type);
- set_breakpoint_count (breakpoint_count + 1);
- b->number = breakpoint_count;
+ if (internal)
+ b->number = internal_breakpoint_number--;
+ else
+ {
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ }
b->thread = thread;
b->task = task;
@@ -7034,7 +7042,12 @@ Couldn't determine the static tracepoint marker to probe"));
= xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
b->ops = ops;
- mention (b);
+ if (internal)
+ /* Do not mention breakpoints with a negative number, but do
+ notify observers. */
+ observer_notify_breakpoint_created (b->number);
+ else
+ mention (b);
}
/* Remove element at INDEX_TO_REMOVE from SAL, shifting other
@@ -7190,7 +7203,7 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
enum bptype type, enum bpdisp disposition,
int thread, int task, int ignore_count,
struct breakpoint_ops *ops, int from_tty,
- int enabled)
+ int enabled, int internal)
{
int i;
@@ -7201,7 +7214,8 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
create_breakpoint_sal (gdbarch, expanded, addr_string[i],
cond_string, type, disposition,
- thread, task, ignore_count, ops, from_tty, enabled);
+ thread, task, ignore_count, ops,
+ from_tty, enabled, internal);
}
}
@@ -7464,25 +7478,24 @@ decode_static_tracepoint_spec (char **arg_p)
return sals;
}
-/* Set a breakpoint. This function is shared between CLI and MI
- functions for setting a breakpoint. This function has two major
- modes of operations, selected by the PARSE_CONDITION_AND_THREAD
- parameter. If non-zero, the function will parse arg, extracting
- breakpoint location, address and thread. Otherwise, ARG is just the
- location of breakpoint, with condition and thread specified by the
- COND_STRING and THREAD parameters. Returns true if any breakpoint
- was created; false otherwise. */
+/* Set a breakpoint. This function has two major modes of operations,
+ selected by the PARSE_CONDITION_AND_THREAD parameter. If non-zero,
+ the function will parse arg, extracting breakpoint location,
+ address and thread. Otherwise, ARG is just the location of
+ breakpoint, with condition and thread specified by the COND_STRING
+ and THREAD parameters. If INTERNAL is non-zero, the breakpoint
+ number will be allocated from the internal breakpoint count.
+ Returns true if any breakpoint was created; false otherwise. */
int
-create_breakpoint (struct gdbarch *gdbarch,
+create_new_breakpoint (struct gdbarch *gdbarch,
char *arg, char *cond_string, int thread,
int parse_condition_and_thread,
int tempflag, enum bptype type_wanted,
int ignore_count,
enum auto_boolean pending_break_support,
struct breakpoint_ops *ops,
- int from_tty,
- int enabled)
+ int from_tty, int enabled, int internal)
{
struct gdb_exception e;
struct symtabs_and_lines sals;
@@ -7658,12 +7671,15 @@ create_breakpoint (struct gdbarch *gdbarch,
cond_string, type_wanted,
tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops,
- from_tty, enabled);
+ from_tty, enabled, internal);
do_cleanups (old_chain);
/* Get the tracepoint we just created. */
- tp = get_breakpoint (breakpoint_count);
+ if (internal)
+ tp = get_breakpoint (internal_breakpoint_number);
+ else
+ tp = get_breakpoint (breakpoint_count);
gdb_assert (tp != NULL);
/* Given that its possible to have multiple markers with
@@ -7679,7 +7695,7 @@ create_breakpoint (struct gdbarch *gdbarch,
create_breakpoints_sal (gdbarch, sals, addr_string, cond_string,
type_wanted, tempflag ? disp_del : disp_donttouch,
thread, task, ignore_count, ops, from_tty,
- enabled);
+ enabled, internal);
}
else
{
@@ -7688,8 +7704,13 @@ create_breakpoint (struct gdbarch *gdbarch,
make_cleanup (xfree, copy_arg);
b = set_raw_breakpoint_without_location (gdbarch, type_wanted);
- set_breakpoint_count (breakpoint_count + 1);
- b->number = breakpoint_count;
+ if (internal)
+ b->number = internal_breakpoint_number--;
+ else
+ {
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ }
b->thread = -1;
b->addr_string = addr_string[0];
b->cond_string = NULL;
@@ -7705,7 +7726,12 @@ create_breakpoint (struct gdbarch *gdbarch,
|| b->type == bp_hardware_breakpoint))
b->enable_state = bp_startup_disabled;
- mention (b);
+ if (internal)
+ /* Do not mention breakpoints with a negative number, but do
+ notify observers. */
+ observer_notify_breakpoint_created (b->number);
+ else
+ mention (b);
}
if (sals.nelts > 1)
@@ -7727,6 +7753,31 @@ create_breakpoint (struct gdbarch *gdbarch,
return 1;
}
+
+/* Set a breakpoint. This function is shared between CLI and MI
+ functions for setting a breakpoint. It wraps create_new_breakpoint
+ and never asks for an internal breakpoint number to be allocated
+ against the breakpoint. Returns true if any breakpoint was
+ created; false otherwise. */
+
+int
+create_breakpoint (struct gdbarch *gdbarch,
+ char *arg, char *cond_string, int thread,
+ int parse_condition_and_thread,
+ int tempflag, enum bptype type_wanted,
+ int ignore_count,
+ enum auto_boolean pending_break_support,
+ struct breakpoint_ops *ops,
+ int from_tty,
+ int enabled)
+{
+ return create_new_breakpoint (gdbarch, arg, cond_string, thread,
+ parse_condition_and_thread, tempflag,
+ type_wanted, ignore_count,
+ pending_break_support,
+ ops, from_tty, enabled, 0);
+}
+
/* Set a breakpoint.
ARG is a string describing breakpoint address,
condition, and thread.
@@ -11372,7 +11423,7 @@ save_breakpoints (char *filename, int from_tty,
ALL_BREAKPOINTS (tp)
{
/* Skip internal and momentary breakpoints. */
- if (!user_settable_breakpoint (tp))
+ if (!user_settable_breakpoint (tp) || tp->number < 0)
continue;
/* If we have a filter, only save the breakpoints it accepts. */
@@ -11410,7 +11461,7 @@ save_breakpoints (char *filename, int from_tty,
ALL_BREAKPOINTS (tp)
{
/* Skip internal and momentary breakpoints. */
- if (!user_settable_breakpoint (tp))
+ if (!user_settable_breakpoint (tp) || tp->number < 0)
continue;
/* If we have a filter, only save the breakpoints it accepts. */
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 9f7600a..d6cd6c6 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -870,6 +870,18 @@ extern int create_breakpoint (struct gdbarch *gdbarch, char *arg,
int from_tty,
int enabled);
+extern int create_new_breakpoint (struct gdbarch *gdbarch, char *arg,
+ char *cond_string, int thread,
+ int parse_condition_and_thread,
+ int tempflag,
+ enum bptype type_wanted,
+ int ignore_count,
+ enum auto_boolean pending_break_support,
+ struct breakpoint_ops *ops,
+ int from_tty,
+ int enabled,
+ int internal);
+
extern void insert_breakpoints (void);
extern int remove_breakpoints (void);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 0b24718..415efc0 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -22552,7 +22552,7 @@ Return the symbol table's source absolute file name.
Python code can manipulate breakpoints via the @code{gdb.Breakpoint}
class.
-@defmethod Breakpoint __init__ spec @r{[}type@r{]} @r{[}wp_class@r{]}
+@defmethod Breakpoint __init__ spec @r{[}type@r{]} @r{[}wp_class@r{]} @r{[}internal@r{]}
Create a new breakpoint. @var{spec} 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
@@ -22560,7 +22560,12 @@ watchpoint. The contents can be any location recognized by the
command. The optional @var{type} denotes the breakpoint to create
from the types defined later in this chapter. This argument can be
either: @code{BP_BREAKPOINT} or @code{BP_WATCHPOINT}. @var{type}
-defaults to @code{BP_BREAKPOINT}. The optional @var{wp_class}
+defaults to @code{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 @var{internal} argument
+has no effect with watchpoints. The optional @var{wp_class}
argument defines the class of watchpoint to create, if @var{type} is
defined as @code{BP_WATCHPOINT}. If a watchpoint class is not
provided, it is assumed to be a @var{WP_WRITE} class.
@@ -22638,6 +22643,13 @@ determine the actual breakpoint type or use-case. This attribute is not
writable.
@end defivar
+@defivar Breakpoint visible
+This attribute holds the breakpoint's visibility flag---the identifier used to
+determine whether the breakpoint is visible to the user when set, or
+when the @samp{info breakpoints} command is run. This attribute is
+not writable.
+@end defivar
+
The available types are represented by constants defined in the @code{gdb}
module:
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 0c70cbf..6381a19 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -34,17 +34,6 @@ typedef struct breakpoint_object breakpoint_object;
static PyTypeObject breakpoint_object_type;
-/* A dynamically allocated vector of breakpoint objects. Each
- breakpoint has a number. A breakpoint is valid if its slot in this
- vector is non-null. When a breakpoint is deleted, we drop our
- reference to it and zero its slot; this is how we let the Python
- object have a lifetime which is independent from that of the gdb
- breakpoint. */
-static breakpoint_object **bppy_breakpoints;
-
-/* Number of slots in bppy_breakpoints. */
-static int bppy_slots;
-
/* Number of live breakpoints. */
static int bppy_live;
@@ -62,13 +51,20 @@ struct breakpoint_object
/* The gdb breakpoint object, or NULL if the breakpoint has been
deleted. */
struct breakpoint *bp;
+ struct breakpoint_object *next;
};
+/* Top and bottom of the breakpoint chain. We store bottom so we do
+ not have to constantly iterate through the chain when we add a new
+ breakpoint. */
+struct breakpoint_object *top;
+struct breakpoint_object *bottom;
+
/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python
exception if it is invalid. */
#define BPPY_REQUIRE_VALID(Breakpoint) \
do { \
- if (! bpnum_is_valid ((Breakpoint)->number)) \
+ if (Breakpoint == NULL) \
return PyErr_Format (PyExc_RuntimeError, _("Breakpoint %d is invalid."), \
(Breakpoint)->number); \
} while (0)
@@ -77,7 +73,7 @@ struct breakpoint_object
exception if it is invalid. This macro is for use in setter functions. */
#define BPPY_SET_REQUIRE_VALID(Breakpoint) \
do { \
- if (! bpnum_is_valid ((Breakpoint)->number)) \
+ if (Breakpoint == NULL) \
{ \
PyErr_Format (PyExc_RuntimeError, _("Breakpoint %d is invalid."), \
(Breakpoint)->number); \
@@ -85,6 +81,9 @@ struct breakpoint_object
} \
} while (0)
+/* Iterator for Python breakpoints linked-list. */
+#define ALL_PY_BREAKPOINTS(B) for (B = top; B; B = B->next)
+
/* This is used to initialize various gdb.bp_* constants. */
struct pybp_code
{
@@ -115,18 +114,6 @@ static struct pybp_code pybp_watch_types[] =
{NULL} /* Sentinel. */
};
-/* Evaluate to true if the breakpoint NUM is valid, false otherwise. */
-static int
-bpnum_is_valid (int num)
-{
- if (num >=0
- && num < bppy_slots
- && bppy_breakpoints[num] != NULL)
- return 1;
-
- return 0;
-}
-
/* Python function which checks the validity of a breakpoint object. */
static PyObject *
bppy_is_valid (PyObject *self, PyObject *args)
@@ -500,6 +487,20 @@ bppy_get_type (PyObject *self, void *closure)
return PyInt_FromLong (self_bp->bp->type);
}
+/* Python function to get the visibility of the breakpoint. */
+static PyObject *
+bppy_get_visibility (PyObject *self, void *closure)
+{
+ breakpoint_object *self_bp = (breakpoint_object *) self;
+
+ BPPY_REQUIRE_VALID (self_bp);
+
+ if (self_bp->bp->number < 0)
+ Py_RETURN_FALSE;
+
+ Py_RETURN_TRUE;
+}
+
/* Python function to get the breakpoint's number. */
static PyObject *
bppy_get_number (PyObject *self, void *closure)
@@ -566,16 +567,29 @@ static PyObject *
bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
{
PyObject *result;
- static char *keywords[] = { "spec", "type", "wp_class", NULL };
+ static char *keywords[] = { "spec", "type", "wp_class", "internal", NULL };
char *spec;
int type = bp_breakpoint;
int access_type = hw_write;
+ PyObject *internal = NULL;
+ int internal_bp = 0;
volatile struct gdb_exception except;
- if (! PyArg_ParseTupleAndKeywords (args, kwargs, "s|ii", keywords,
- &spec, &type, &access_type))
+ if (! PyArg_ParseTupleAndKeywords (args, kwargs, "s|iiO", keywords,
+ &spec, &type, &access_type, &internal))
return NULL;
+ if (internal)
+ {
+ if (! PyBool_Check (internal))
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("The value of `internal' keyword must be a boolean."));
+ return NULL;
+ }
+ if (internal == Py_True)
+ internal_bp = 1;
+ }
result = subtype->tp_alloc (subtype, 0);
if (! result)
return NULL;
@@ -583,19 +597,22 @@ bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
bppy_pending_object->number = -1;
bppy_pending_object->bp = NULL;
+ /* We do not add the breakpoint to the linked-list yet; GDB
+ has not created the breakpoint. */
+ bppy_pending_object->next = NULL;
TRY_CATCH (except, RETURN_MASK_ALL)
{
switch (type)
{
case bp_breakpoint:
{
- create_breakpoint (python_gdbarch,
- spec, NULL, -1,
- 0,
- 0, bp_breakpoint,
- 0,
- AUTO_BOOLEAN_TRUE,
- NULL, 0, 1);
+ create_new_breakpoint (python_gdbarch,
+ spec, NULL, -1,
+ 0,
+ 0, bp_breakpoint,
+ 0,
+ AUTO_BOOLEAN_TRUE,
+ NULL, 0, 1, internal_bp);
break;
}
case bp_watchpoint:
@@ -634,6 +651,7 @@ PyObject *
gdbpy_breakpoints (PyObject *self, PyObject *args)
{
PyObject *result;
+ breakpoint_object *b;
if (bppy_live == 0)
Py_RETURN_NONE;
@@ -641,16 +659,13 @@ gdbpy_breakpoints (PyObject *self, PyObject *args)
result = PyTuple_New (bppy_live);
if (result)
{
- int i, out = 0;
-
- for (i = 0; out < bppy_live; ++i)
- {
- if (! bppy_breakpoints[i])
- continue;
- Py_INCREF (bppy_breakpoints[i]);
- PyTuple_SetItem (result, out, (PyObject *) bppy_breakpoints[i]);
- ++out;
- }
+ int i = 0;
+ ALL_PY_BREAKPOINTS (b)
+ {
+ Py_INCREF (b);
+ PyTuple_SetItem (result, i, (PyObject *) b);
+ ++i;
+ }
}
return result;
}
@@ -668,9 +683,6 @@ gdbpy_breakpoint_created (int num)
struct breakpoint *bp = NULL;
PyGILState_STATE state;
- if (num < 0)
- return;
-
bp = get_breakpoint (num);
if (! bp)
return;
@@ -682,21 +694,6 @@ gdbpy_breakpoint_created (int num)
&& bp->type != bp_access_watchpoint)
return;
- if (num >= bppy_slots)
- {
- int old = bppy_slots;
-
- bppy_slots = bppy_slots * 2 + 10;
- bppy_breakpoints
- = (breakpoint_object **) xrealloc (bppy_breakpoints,
- (bppy_slots
- * sizeof (breakpoint_object *)));
- memset (&bppy_breakpoints[old], 0,
- (bppy_slots - old) * sizeof (PyObject *));
- }
-
- ++bppy_live;
-
state = PyGILState_Ensure ();
if (bppy_pending_object)
@@ -710,9 +707,27 @@ gdbpy_breakpoint_created (int num)
{
newbp->number = num;
newbp->bp = bp;
- bppy_breakpoints[num] = newbp;
+ newbp->next = NULL;
Py_INCREF (newbp);
}
+ else
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ _("Error while creating breakpoint from GDB."));
+ return;
+ }
+
+ ++bppy_live;
+
+ /* If this is the first breakpoint created, set the top and bottom
+ of the linked list. */
+ if (top == NULL)
+ top = newbp;
+
+ if (bottom)
+ bottom->next = newbp;
+
+ bottom = newbp;
/* Just ignore errors here. */
PyErr_Clear ();
@@ -726,15 +741,28 @@ static void
gdbpy_breakpoint_deleted (int num)
{
PyGILState_STATE state;
+ breakpoint_object *b = NULL;
+ breakpoint_object *prev = NULL;
state = PyGILState_Ensure ();
- if (bpnum_is_valid (num))
- {
- bppy_breakpoints[num]->bp = NULL;
- Py_DECREF (bppy_breakpoints[num]);
- bppy_breakpoints[num] = NULL;
- --bppy_live;
- }
+ ALL_PY_BREAKPOINTS (b)
+ {
+ if (b->number == num)
+ {
+ if (b == top)
+ top = b->next;
+ else
+ prev->next = b->next;
+ if (b == bottom)
+ bottom = prev;
+
+ b->bp = NULL;
+ Py_DECREF (b);
+ --bppy_live;
+ break;
+ }
+ prev = b;
+ }
PyGILState_Release (state);
}
@@ -754,6 +782,9 @@ gdbpy_initialize_breakpoints (void)
PyModule_AddObject (gdb_module, "Breakpoint",
(PyObject *) &breakpoint_object_type);
+ top = NULL;
+ bottom = NULL;
+
observer_attach_breakpoint_created (gdbpy_breakpoint_created);
observer_attach_breakpoint_deleted (gdbpy_breakpoint_deleted);
@@ -816,6 +847,8 @@ or None if no condition set."},
"Commands of the breakpoint, as specified by the user."},
{ "type", bppy_get_type, NULL,
"Type of breakpoint."},
+ { "visible", bppy_get_visibility, NULL,
+ "Whether the breakpoint is visible to the user."},
{ NULL } /* Sentinel. */
};
diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp
index 7da94c4..bdf8300 100644
--- a/gdb/testsuite/gdb.python/py-breakpoint.exp
+++ b/gdb/testsuite/gdb.python/py-breakpoint.exp
@@ -117,6 +117,32 @@ gdb_test "end"
gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" "Get Breakpoint List" 0
gdb_test "python print blist\[len(blist)-1\].commands" "print \"Command for breakpoint has been executed.\".*print result"
+# Start with a fresh gdb.
+clean_restart ${testfile}
+
+if ![runto_main] then {
+ fail "Cannot run to main."
+ return 0
+}
+
+# Test invisible breakpooints.
+delete_breakpoints
+set ibp_location [gdb_get_line_number "Break at multiply."]
+gdb_py_test_silent_cmd "python ibp = gdb.Breakpoint(\"$ibp_location\", internal=False)" "Set invisible breakpoint" 0
+gdb_py_test_silent_cmd "python ilist = gdb.breakpoints()" "Get Breakpoint List" 0
+gdb_test "python print ilist\[0\]" "<gdb.Breakpoint object at $hex>" "Check invisible bp obj exists"
+gdb_test "python print ilist\[0\].location" "py-breakpoint\.c:$ibp_location*" "Check breakpoint location"
+gdb_test "python print ilist\[0\].visible" "True" "Check breakpoint visibility"
+gdb_test "info breakpoints" "py-breakpoint\.c:$ibp_location.*" "Check info breakpoints shows visible breakpoints"
+delete_breakpoints
+gdb_py_test_silent_cmd "python ibp = gdb.Breakpoint(\"$ibp_location\", internal=True)" "Set invisible breakpoint" 0
+gdb_py_test_silent_cmd "python ilist = gdb.breakpoints()" "Get Breakpoint List" 0
+gdb_test "python print ilist\[0\]" "<gdb.Breakpoint object at $hex>" "Check invisible bp obj exists"
+gdb_test "python print ilist\[0\].location" "py-breakpoint\.c:$ibp_location*" "Check breakpoint location"
+gdb_test "python print ilist\[0\].visible" "False" "Check breakpoint visibility"
+gdb_test "info breakpoints" "No breakpoints or watchpoints.*" "Check info breakpoints does not show invisible breakpoints"
+gdb_test "maint info breakpoints" "py-breakpoint\.c:$ibp_location.*" "Check maint info breakpoints shows invisible breakpoints"
+
# Watchpoints
# Start with a fresh gdb.
clean_restart ${testfile}