diff mbox

[RFA] PR python/15620, PR python/18620 - breakpoint events in Python

Message ID 1463777131-7289-1-git-send-email-tom@tromey.com
State New
Headers show

Commit Message

Tom Tromey May 20, 2016, 8:45 p.m. UTC
This patch adds some breakpoint events to Python.  In particular,
there is a creation event that is emitted when a breakpoint is
created; a modification event that is emitted when a breakpoint
changes somehow; and a deletion event that is emitted when a
breakpoint is deleted.

In this patch, the event's payload is the breakpoint itself.  I
considered making a new event type to hold the breakpoint, but I
didn't see a need.  Still, I thought I would mention this as a spot
where some other choice is possible.

Built and regtested on x86-64 Fedora 23.

2016-05-19  Tom Tromey  <tom@tromey.com>

	PR python/15620, PR python/18620:
	* python/py-evts.c (gdbpy_initialize_py_events): Call
	add_new_registry for new events.
	* python/py-events.h (events_object) <breakpoint_created,
	breakpoint_deleted, breakpoint_modified>: New fields.
	* python/py-breakpoint.c (gdbpy_breakpoint_created): Emit the
	breakpoint changed event.
	(gdbpy_breakpoint_deleted): Emit the breakpoint deleted event.
	(gdbpy_breakpoint_modified): New function.
	(gdbpy_initialize_breakpoints): Attach to the breakpoint modified
	observer.

2016-05-20  Tom Tromey  <tom@tromey.com>

	PR python/15620, PR python/18620:
	* python.texi (Events In Python): Document new breakpoint events.

2016-05-20  Tom Tromey  <tom@tromey.com>

	PR python/15620, PR python/18620:
	* gdb.python/py-breakpoint.exp (connect_event, check_last_event)
	(test_bkpt_events): New procs.
---
 gdb/ChangeLog                              | 14 +++++++++
 gdb/doc/ChangeLog                          |  5 ++++
 gdb/doc/python.texi                        | 15 ++++++++++
 gdb/python/py-breakpoint.c                 | 48 ++++++++++++++++++++++++++++++
 gdb/python/py-events.h                     |  3 ++
 gdb/python/py-evts.c                       | 11 +++++++
 gdb/testsuite/ChangeLog                    |  6 ++++
 gdb/testsuite/gdb.python/py-breakpoint.exp | 41 +++++++++++++++++++++++++
 8 files changed, 143 insertions(+)

Comments

Eli Zaretskii May 20, 2016, 9:18 p.m. UTC | #1
> From: Tom Tromey <tom@tromey.com>
> Cc: Tom Tromey <tom@tromey.com>
> Date: Fri, 20 May 2016 14:45:31 -0600
> 
> 2016-05-19  Tom Tromey  <tom@tromey.com>
> 
> 	PR python/15620, PR python/18620:
> 	* python/py-evts.c (gdbpy_initialize_py_events): Call
> 	add_new_registry for new events.
> 	* python/py-events.h (events_object) <breakpoint_created,
> 	breakpoint_deleted, breakpoint_modified>: New fields.
> 	* python/py-breakpoint.c (gdbpy_breakpoint_created): Emit the
> 	breakpoint changed event.
> 	(gdbpy_breakpoint_deleted): Emit the breakpoint deleted event.
> 	(gdbpy_breakpoint_modified): New function.
> 	(gdbpy_initialize_breakpoints): Attach to the breakpoint modified
> 	observer.
> 
> 2016-05-20  Tom Tromey  <tom@tromey.com>
> 
> 	PR python/15620, PR python/18620:
> 	* python.texi (Events In Python): Document new breakpoint events.
> 
> 2016-05-20  Tom Tromey  <tom@tromey.com>
> 
> 	PR python/15620, PR python/18620:
> 	* gdb.python/py-breakpoint.exp (connect_event, check_last_event)
> 	(test_bkpt_events): New procs.

OK for the documentation part.

Thanks.
Yao Qi July 13, 2016, 1:39 p.m. UTC | #2
Tom Tromey <tom@tromey.com> writes:

Hi Tom,
Patch is good to me.

> @@ -917,6 +926,15 @@ gdbpy_breakpoint_deleted (struct breakpoint *b)
>        bp_obj = bp->py_bp_object;
>        if (bp_obj)
>  	{
> +	  if (!evregpy_no_listeners_p (gdb_py_events.breakpoint_deleted))
> +	    {
> +	      PyObject *bp_obj_alias = (PyObject *) bp_obj;

Nit: an empty line is needed here.

> +	      Py_INCREF (bp_obj_alias);
> +	      if (evpy_emit_event (bp_obj_alias,
> +				   gdb_py_events.breakpoint_deleted) < 0)
> +		gdbpy_print_stack ();
> +	    }
> +
>  	  bp_obj->bp = NULL;
>  	  --bppy_live;
>  	  Py_DECREF (bp_obj);
Tom Tromey July 13, 2016, 7:52 p.m. UTC | #3
>>>>> "Yao" == Yao Qi <qiyaoltc@gmail.com> writes:

Yao> Patch is good to me.
[...]
Yao> Nit: an empty line is needed here.

I've fixed this locally.

Tom
diff mbox

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 0968b85..1e0afe6 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,17 @@ 
+2016-05-19  Tom Tromey  <tom@tromey.com>
+
+	PR python/15620, PR python/18620:
+	* python/py-evts.c (gdbpy_initialize_py_events): Call
+	add_new_registry for new events.
+	* python/py-events.h (events_object) <breakpoint_created,
+	breakpoint_deleted, breakpoint_modified>: New fields.
+	* python/py-breakpoint.c (gdbpy_breakpoint_created): Emit the
+	breakpoint changed event.
+	(gdbpy_breakpoint_deleted): Emit the breakpoint deleted event.
+	(gdbpy_breakpoint_modified): New function.
+	(gdbpy_initialize_breakpoints): Attach to the breakpoint modified
+	observer.
+
 2016-05-19  Andreas Schwab  <schwab@suse.de>
 
 	* ia64-libunwind-tdep.c (libunwind_descr): Add cast from void *.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index fe2e3be..0d564bf 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,8 @@ 
+2016-05-20  Tom Tromey  <tom@tromey.com>
+
+	PR python/15620, PR python/18620:
+	* python.texi (Events In Python): Document new breakpoint events.
+
 2016-05-17  Tom Tromey  <tom@tromey.com>
 
 	* gdb.texinfo (Supported Languages): Mention Rust.  Update menu.
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index ffbf89a..5e3a42c 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -2962,6 +2962,21 @@  A gdb.Frame object representing the frame in which the register was modified.
 Denotes which register was modified.
 @end defvar
 
+@item events.breakpoint_created
+This is emitted when a new breakpoint has been created.  The argument
+that is passed is the new @code{gdb.Breakpoint} object.
+
+@item events.breakpoint_modified
+This is emitted when a breakpoint has been modified in some way.  The
+argument that is passed is the new @code{gdb.Breakpoint} object.
+
+@item events.breakpoint_deleted
+This is emitted when a breakpoint is has been deleted.  The argument
+that is passed is the @code{gdb.Breakpoint} object.  When this event
+is emitted, the @code{gdb.Breakpoint} object will already be in its
+invalid state; that is, the @code{is_valid} method will return
+@code{False}.
+
 @end table
 
 @node Threads In Python
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 611a41e..0dce909 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -31,6 +31,7 @@ 
 #include "arch-utils.h"
 #include "language.h"
 #include "location.h"
+#include "py-event.h"
 
 /* Number of live breakpoints.  */
 static int bppy_live;
@@ -897,6 +898,14 @@  gdbpy_breakpoint_created (struct breakpoint *bp)
       gdbpy_print_stack ();
     }
 
+  if (!evregpy_no_listeners_p (gdb_py_events.breakpoint_created))
+    {
+      Py_INCREF (newbp);
+      if (evpy_emit_event ((PyObject *) newbp,
+			   gdb_py_events.breakpoint_created) < 0)
+	gdbpy_print_stack ();
+    }
+
   PyGILState_Release (state);
 }
 
@@ -917,6 +926,15 @@  gdbpy_breakpoint_deleted (struct breakpoint *b)
       bp_obj = bp->py_bp_object;
       if (bp_obj)
 	{
+	  if (!evregpy_no_listeners_p (gdb_py_events.breakpoint_deleted))
+	    {
+	      PyObject *bp_obj_alias = (PyObject *) bp_obj;
+	      Py_INCREF (bp_obj_alias);
+	      if (evpy_emit_event (bp_obj_alias,
+				   gdb_py_events.breakpoint_deleted) < 0)
+		gdbpy_print_stack ();
+	    }
+
 	  bp_obj->bp = NULL;
 	  --bppy_live;
 	  Py_DECREF (bp_obj);
@@ -925,6 +943,35 @@  gdbpy_breakpoint_deleted (struct breakpoint *b)
   PyGILState_Release (state);
 }
 
+/* Callback that is used when a breakpoint is modified.  */
+
+static void
+gdbpy_breakpoint_modified (struct breakpoint *b)
+{
+  int num = b->number;
+  PyGILState_STATE state;
+  struct breakpoint *bp = NULL;
+  gdbpy_breakpoint_object *bp_obj;
+
+  state = PyGILState_Ensure ();
+  bp = get_breakpoint (num);
+  if (bp)
+    {
+      PyObject *bp_obj = (PyObject *) bp->py_bp_object;
+      if (bp_obj)
+	{
+	  if (!evregpy_no_listeners_p (gdb_py_events.breakpoint_modified))
+	    {
+	      Py_INCREF (bp_obj);
+	      if (evpy_emit_event (bp_obj,
+				   gdb_py_events.breakpoint_modified) < 0)
+		gdbpy_print_stack ();
+	    }
+	}
+    }
+  PyGILState_Release (state);
+}
+
 
 
 /* Initialize the Python breakpoint code.  */
@@ -943,6 +990,7 @@  gdbpy_initialize_breakpoints (void)
 
   observer_attach_breakpoint_created (gdbpy_breakpoint_created);
   observer_attach_breakpoint_deleted (gdbpy_breakpoint_deleted);
+  observer_attach_breakpoint_modified (gdbpy_breakpoint_modified);
 
   /* Add breakpoint types constants.  */
   for (i = 0; pybp_codes[i].name; ++i)
diff --git a/gdb/python/py-events.h b/gdb/python/py-events.h
index 9ecee4c..1d74558 100644
--- a/gdb/python/py-events.h
+++ b/gdb/python/py-events.h
@@ -50,6 +50,9 @@  typedef struct
   eventregistry_object *inferior_call;
   eventregistry_object *memory_changed;
   eventregistry_object *register_changed;
+  eventregistry_object *breakpoint_created;
+  eventregistry_object *breakpoint_deleted;
+  eventregistry_object *breakpoint_modified;
 
   PyObject *module;
 
diff --git a/gdb/python/py-evts.c b/gdb/python/py-evts.c
index 95827e4..961c247 100644
--- a/gdb/python/py-evts.c
+++ b/gdb/python/py-evts.c
@@ -89,6 +89,17 @@  gdbpy_initialize_py_events (void)
   if (add_new_registry (&gdb_py_events.clear_objfiles, "clear_objfiles") < 0)
     return -1;
 
+  if (add_new_registry (&gdb_py_events.breakpoint_created,
+			"breakpoint_created") < 0)
+    return -1;
+
+  if (add_new_registry (&gdb_py_events.breakpoint_deleted,
+			"breakpoint_deleted") < 0)
+    return -1;
+  if (add_new_registry (&gdb_py_events.breakpoint_modified,
+			"breakpoint_modified") < 0)
+    return -1;
+
   if (gdb_pymodule_addobject (gdb_module,
 			      "events",
 			      (PyObject *) gdb_py_events.module) < 0)
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index a773c63..b518e64 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,9 @@ 
+2016-05-20  Tom Tromey  <tom@tromey.com>
+
+	PR python/15620, PR python/18620:
+	* gdb.python/py-breakpoint.exp (connect_event, check_last_event)
+	(test_bkpt_events): New procs.
+
 2016-05-18  Simon Marchi  <simon.marchi@ericsson.com>
 
 	* gdb.mi/mi-threads-interrupt.c: New file.
diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp
index d1d1b22..e926c76 100644
--- a/gdb/testsuite/gdb.python/py-breakpoint.exp
+++ b/gdb/testsuite/gdb.python/py-breakpoint.exp
@@ -494,6 +494,46 @@  proc test_bkpt_address {} {
 	".*Breakpoint ($decimal)+ at .*$srcfile, line ($decimal)+\."
 }
 
+# Helper proc to install an event listener for a given breakpoint
+# event.  NAME is the name of the event to listen for.
+proc connect_event {name} {
+    set lambda "lambda x: note_event(\"$name\")"
+    gdb_test_no_output "python gdb.events.$name.connect($lambda)" \
+	"install $name event listener"
+}
+
+# Helper proc to check that the most recently emitted breakpoint event
+# is EXPECTED.
+proc check_last_event {expected} {
+    gdb_test "python print (last_bp_event)" $expected \
+	"check for $expected event"
+}
+
+proc test_bkpt_events {} {
+    global testfile
+
+    clean_restart ${testfile}
+
+    gdb_py_test_multiple "Create event handler" \
+	"python" "" \
+	"def note_event(arg):" "" \
+	"  global last_bp_event" "" \
+	"  last_bp_event = arg" "" \
+	"end" ""
+    gdb_test_no_output "python last_bp_event = None"
+
+    connect_event breakpoint_created
+    connect_event breakpoint_modified
+    connect_event breakpoint_deleted
+
+    gdb_breakpoint [gdb_get_line_number "Break at add."]
+    check_last_event breakpoint_created
+    gdb_test_no_output "disable 1"
+    check_last_event breakpoint_modified
+    gdb_test_no_output "delete 1"
+    check_last_event breakpoint_deleted
+}
+
 test_bkpt_basic
 test_bkpt_deletion
 test_bkpt_cond_and_cmds
@@ -503,3 +543,4 @@  test_bkpt_internal
 test_bkpt_eval_funcs
 test_bkpt_temporary
 test_bkpt_address
+test_bkpt_events