This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] Add visible flag to breakpoints.


This patch allows breakpoints to be become invisible to the user.

This is part of a larger effort to improve the Python breakpoint support
within GDB.  One of the use-cases we have in Python is for a command to
set (maybe a large) number of breakpoints to catch predefined
behavior.  However we do not want this to impact the usability or
readability of the existing 'info breakpoints' output.  This patch fixes
that by allowing breakpoints to become invisible to the user.

One of the initial approaches we took was to create our own kind of
Python breakpoint.  This would be much like all of the special case
internal breakpoints that currently exist within GDB.  But these are
too special purpose -- we lose all the general accessibility and
edge-cases behavior within general purpose breakpoints.  And,
ultimately we would have to put all of that code back in, causing code
duplication.  So we decided to add a visible flag.

Currently this visibility flag is only accessible through the Python
breakpoint code.  If the visible keyword is set when the breakpoint is
created, it will not be mentioned (only the new breakpoint observer will
be called), and the breakpoint will not be enumerated via 'info
breakpoints'.  The visibility of a breakpoint can subsequently be
altered via the 'visible' attribute of the Python object which will flip
the visible flag in the breakpoint struct.  Subsequent calls to 'info
breakpoints' will then show the breakpoint.  There are several
assumptions I have made in this patch.

If when the breakpoint it created, the visible flag is set to False:

-- GDB will not mention the breakpoint creation, but will notify any
   observers.
-- The breakpoint will not be enumerated in the 'info breakpoint' list.
-- The breakpoint whether invisible or not, will always be enumerated in
   'maint info breakpoints'
-- The internalvar bpnum is always set to the breakpoint just created,
   regardless of whether the visibility flag is set.

I think these are sane defaults, but I'm open to changing them as we
need too.

What do you think?

Cheers,

Phil

--

2010-09-30  Phil Muldoon  <pmuldoon@redhat.com>

	* python/py-breakpoint.c (bppy_get_visibility): New function.
	(bppy_set_visibility): Ditto.
	(bppy_new): Add visible keyword and pass it as a parameter to
	create_new_breakpoint.
	* breakpoint.h (struct breakpoint): Add visible flag.
	(create_new_breakpoint): Declare.
	* breakpoint.c (breakpoint_visible): New function.
	(breakpoint_1): Check if breakpoint is visible.
	(set_raw_breakpoint_without_location): Set visible to 1.
	(create_breakpoint_sal): Add visible parameter and set visibility.
	Only call mention if breakpoint is visible, else just notify the
	observer.
	(create_breakpoint_sals): Ditto.
	(create_new_breakpoint): Renamed from create_new_breakpoint.  Add
	visible parameter.
	(create_breakpoint): Wrap create_new_breakpoint with default
	visibility set to on.

2010-09-30  Phil Muldoon  <pmuldoon@redhat.com>

	* gdb.texinfo (Breakpoints In Python): Document optional visible
	flag.  Document visible attribute.

2010-09-30  Phil Muldoon  <pmuldoon@redhat.com>

	* gdb.python/py-breakpoint.exp: Add breakpoint visibility tests.

--

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index b4502e7..26cab2c 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -4907,6 +4907,14 @@ user_settable_breakpoint (const struct breakpoint *b)
 	  || is_tracepoint (b)
 	  || is_watchpoint (b));
 }
+
+/* Return non-zero if B is visible to the user.  */
+
+static int
+breakpoint_visible (const struct breakpoint *b)
+{
+  return b->visible;
+}
 	
 /* Print information on user settable breakpoint (watchpoint, etc)
    number BNUM.  If BNUM is -1 print all user-settable breakpoints.
@@ -4939,7 +4947,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)
+			&& breakpoint_visible (b)))
 	  {
 	    int addr_bit, type_len;
 
@@ -5007,7 +5016,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)
+			&& breakpoint_visible (b)))
 	  print_one_breakpoint (b, &last_loc, print_address_bits, allflag);
       }
   }
@@ -5456,6 +5466,7 @@ set_raw_breakpoint_without_location (struct gdbarch *gdbarch,
   b->syscalls_to_be_caught = NULL;
   b->ops = NULL;
   b->condition_not_parsed = 0;
+  b->visible = 1;
 
   /* Add this breakpoint to the end of the chain
      so that a list of breakpoints will come out in order
@@ -6914,7 +6925,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 visible)
 {
   struct breakpoint *b = NULL;
   int i;
@@ -6961,6 +6973,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
 	  b->enable_state = enabled ? bp_enabled : bp_disabled;
 	  b->disposition = disposition;
 	  b->pspace = sals.sals[0].pspace;
+	  b->visible = visible;
 
 	  if (type == bp_static_tracepoint)
 	    {
@@ -7034,7 +7047,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 (visible)
+    mention (b);
+  else
+    /* Just notify observers without printing.  */
+    observer_notify_breakpoint_created (b->number);
+
 }
 
 /* Remove element at INDEX_TO_REMOVE from SAL, shifting other
@@ -7190,7 +7208,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 visible)
 {
   int i;
 
@@ -7201,7 +7219,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, visible);
     }
 }
 
@@ -7474,15 +7493,16 @@ decode_static_tracepoint_spec (char **arg_p)
    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)
+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 visible)
 {
   struct gdb_exception e;
   struct symtabs_and_lines sals;
@@ -7658,7 +7678,7 @@ 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, visible);
 
 	      do_cleanups (old_chain);
 
@@ -7679,7 +7699,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, visible);
     }
   else
     {
@@ -7699,13 +7719,18 @@ create_breakpoint (struct gdbarch *gdbarch,
       b->ops = ops;
       b->enable_state = enabled ? bp_enabled : bp_disabled;
       b->pspace = current_program_space;
+      b->visible = visible;
 
       if (enabled && b->pspace->executing_startup
 	  && (b->type == bp_breakpoint
 	      || b->type == bp_hardware_breakpoint))
 	b->enable_state = bp_startup_disabled;
 
-      mention (b);
+      if (visible)
+	mention (b);
+      else
+	/* Just notify observers without printing.  */
+	observer_notify_breakpoint_created (b->number);
     }
   
   if (sals.nelts > 1)
@@ -7727,6 +7752,34 @@ create_breakpoint (struct gdbarch *gdbarch,
   return 1;
 }
 
+
+/* 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.  */
+
+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, 1);
+}
+
 /* Set a breakpoint. 
    ARG is a string describing breakpoint address,
    condition, and thread.
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 9f7600a..3c3b5d0 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -557,6 +557,13 @@ struct breakpoint
        breakpoints, we will use this index to try to find the same
        marker again.  */
     int static_trace_marker_id_idx;
+
+    /* Python breakpoints are allowed to specify whether the
+       breakpoint will be visible to the user via 'info breakpoints'.
+       This is to enable Python scripts to set many breakpoints in
+       commands/functions without impacting the readability of the
+       'info breakpoints' command.  */
+    int visible;
   };
 
 typedef struct breakpoint *breakpoint_p;
@@ -870,6 +877,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 visible);
+
 extern void insert_breakpoints (void);
 
 extern int remove_breakpoints (void);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 0b24718..1fa6faa 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{[}visible@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{visible} argument
+allows the breakpoint to become invisible to the user.  The breakpoint
+will neither be reported when created, or will it be enumerated in the
+output from @samp{info breakpoints} (but will be enumerated with the
+@samp{maint info breakpoints} command).  The @var{visible} 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,12 @@ 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 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..acbaab2 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -500,6 +500,40 @@ bppy_get_type (PyObject *self, void *closure)
   return PyInt_FromLong (self_bp->bp->type);
 }
 
+/* Python function to get the visibility state of the breakpoint.  */
+static PyObject *
+bppy_get_visibility (PyObject *self, void *closure)
+{
+  breakpoint_object *self_bp = (breakpoint_object *) self;
+
+  BPPY_REQUIRE_VALID (self_bp);
+
+  return PyInt_FromLong (self_bp->bp->visible);
+}
+
+/* Python function to set the visibility state of a breakpoint.  */
+static int
+bppy_set_visibility (PyObject *self, PyObject *newvalue, void *closure)
+{
+  breakpoint_object *self_bp = (breakpoint_object *) self;
+
+  BPPY_SET_REQUIRE_VALID (self_bp);
+
+  if (newvalue == NULL || ! PyBool_Check (newvalue))
+    {
+      PyErr_SetString (PyExc_TypeError,
+		       _("Value must be True or False."));
+      return -1;
+    }
+
+  if (newvalue == Py_True)
+    self_bp->bp->visible = 1;
+  else
+    self_bp->bp->visible = 0;
+
+  return 0;
+}
+
 /* Python function to get the breakpoint's number.  */
 static PyObject *
 bppy_get_number (PyObject *self, void *closure)
@@ -566,14 +600,15 @@ 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", "visible", NULL };
   char *spec;
   int type = bp_breakpoint;
   int access_type = hw_write;
+  int visible = 1;
   volatile struct gdb_exception except;
 
-  if (! PyArg_ParseTupleAndKeywords (args, kwargs, "s|ii", keywords,
-				     &spec, &type, &access_type))
+  if (! PyArg_ParseTupleAndKeywords (args, kwargs, "s|iii", keywords,
+				     &spec, &type, &access_type, &visible))
     return NULL;
 
   result = subtype->tp_alloc (subtype, 0);
@@ -589,13 +624,13 @@ bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
 	{
 	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, visible);
 	    break;
 	  }
         case bp_watchpoint:
@@ -816,6 +851,9 @@ 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, bppy_set_visibility,
+    "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 07a7362..dc78a92 100644
--- a/gdb/testsuite/gdb.python/py-breakpoint.exp
+++ b/gdb/testsuite/gdb.python/py-breakpoint.exp
@@ -126,6 +126,30 @@ 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\", visible=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" "0" "Check breakpoint visibility"
+gdb_test "python print ilist\[0\].number == gdb.parse_and_eval(\"\$bpnum\")" "True" "Check that bpnum has been updated"
+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"
+gdb_py_test_silent_cmd "python ilist\[0\].visible = True" "Set visibility to True" 0
+gdb_test "info breakpoints" "py-breakpoint\.c:$ibp_location.*" "Check info breakpoints shows visible breakpoints"
+gdb_py_test_silent_cmd "python ilist\[0\].visible = False" "Set visibility to True" 0
+gdb_test "info breakpoints" "No breakpoints or watchpoints.*" "Check info breakpoints does not show invisible breakpoints"
+
 # Watchpoints
 # Start with a fresh gdb.
 clean_restart ${testfile}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]