From: Tom Tromey Date: Tue, 5 Sep 2017 18:07:00 +0000 (-0600) Subject: Add new_inferior, inferior_deleted, and new_thread events X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7c96f8c1dae023c7d0b1cabc5e50c4d18fd06960;p=binutils-gdb.git Add new_inferior, inferior_deleted, and new_thread events This adds a few new events to gdb's Python layer: new_inferior, inferior_deleted, and new_thread. I wanted to be able to add a combined inferior/thread display window to my GUI, and I needed a few events to make this work. This is PR python/15622. ChangeLog 2017-09-11 Tom Tromey PR python/15622: * NEWS: Add entry. * python/python.c (do_start_initialization): Initialize new event types. * python/python-internal.h (gdbpy_initialize_new_inferior_event) (gdbpy_initialize_inferior_deleted_event) (gdbpy_initialize_new_thread_event): Declare. * python/py-threadevent.c (create_thread_event_object): Add option "thread" parameter. * python/py-inferior.c (new_thread_event_object_type) (new_inferior_event_object_type) (inferior_deleted_event_object_type): Declare. (python_new_inferior, python_inferior_deleted): New functions. (add_thread_object): Emit new_thread event. (gdbpy_initialize_inferior): Attach new functions to corresponding observers. (new_thread, new_inferior, inferior_deleted): Define new event types. * python/py-evts.c (gdbpy_initialize_py_events): Add new registries. * python/py-events.h (events_object) : New fields. * python/py-event.h (create_thread_event_breakpoint): Add optional "thread" parameter. doc/ChangeLog 2017-09-11 Tom Tromey * python.texi (Events In Python): Document new events. testsuite/ChangeLog 2017-09-11 Tom Tromey * gdb.python/py-infthread.exp: Add tests for new_thread event. * gdb.python/py-inferior.exp: Add tests for new inferior events. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 1781ddd9f5e..086fff5aff5 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,30 @@ +2017-09-11 Tom Tromey + + PR python/15622: + * NEWS: Add entry. + * python/python.c (do_start_initialization): Initialize new event + types. + * python/python-internal.h (gdbpy_initialize_new_inferior_event) + (gdbpy_initialize_inferior_deleted_event) + (gdbpy_initialize_new_thread_event): Declare. + * python/py-threadevent.c (create_thread_event_object): Add option + "thread" parameter. + * python/py-inferior.c (new_thread_event_object_type) + (new_inferior_event_object_type) + (inferior_deleted_event_object_type): Declare. + (python_new_inferior, python_inferior_deleted): New functions. + (add_thread_object): Emit new_thread event. + (gdbpy_initialize_inferior): Attach new functions to corresponding + observers. + (new_thread, new_inferior, inferior_deleted): Define new event + types. + * python/py-evts.c (gdbpy_initialize_py_events): Add new + registries. + * python/py-events.h (events_object) : New fields. + * python/py-event.h (create_thread_event_breakpoint): Add optional + "thread" parameter. + 2017-09-10 Andrew Burgess * utils.c (abort_with_message): Don't compare gdb_stderr to NULL, diff --git a/gdb/NEWS b/gdb/NEWS index f6ed6140fae..2e6d48c016a 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -15,6 +15,12 @@ the remote inferior is started by the GDBserver, use the "unset environment" command. +* Python Scripting + + ** New events gdb.new_inferior, gdb.inferior_deleted, and + gdb.new_thread are emitted. See the manual for further + description of these. + * New features in the GDB remote stub, GDBserver ** New "--selftest" command line option runs some GDBserver self diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 72f3d9e7c81..db2f64f2dc6 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,7 @@ +2017-09-11 Tom Tromey + + * python.texi (Events In Python): Document new events. + 2017-09-04 Pedro Alves * gdb.texinfo (Variables) : Document inspecting diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index 32d7939e669..39def2aa6f2 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -2989,6 +2989,39 @@ invalid state; that is, the @code{is_valid} method will return This event carries no payload. It is emitted each time @value{GDBN} presents a prompt to the user. +@item events.new_inferior +This is emitted when a new inferior is created. Note that the +inferior is not necessarily running; in fact, it may not even have an +associated executable. + +The event is of type @code{gdb.NewInferiorEvent}. This has a single +attribute: + +@defvar NewInferiorEvent.inferior +The new inferior, a @code{gdb.Inferior} object. +@end defvar + +@item events.inferior_deleted +This is emitted when an inferior has been deleted. Note that this is +not the same as process exit; it is notified when the inferior itself +is removed, say via @code{remove-inferiors}. + +The event is of type @code{gdb.InferiorDeletedEvent}. This has a single +attribute: + +@defvar NewInferiorEvent.inferior +The inferior that is being removed, a @code{gdb.Inferior} object. +@end defvar + +@item events.new_thread +This is emitted when @value{GDBN} notices a new thread. The event is of +type @code{gdb.NewThreadEvent}, which extends @code{gdb.ThreadEvent}. +This has a single attribute: + +@defvar NewThreadEvent.inferior_thread +The new thread. +@end defvar + @end table @node Threads In Python diff --git a/gdb/python/py-event.h b/gdb/python/py-event.h index ccb851339c8..2f02c5f861c 100644 --- a/gdb/python/py-event.h +++ b/gdb/python/py-event.h @@ -125,7 +125,8 @@ extern int evpy_emit_event (PyObject *event, eventregistry_object *registry); extern PyObject *create_event_object (PyTypeObject *py_type); -extern PyObject *create_thread_event_object (PyTypeObject *py_type); +extern PyObject *create_thread_event_object (PyTypeObject *py_type, + PyObject *thread = nullptr); extern int emit_new_objfile_event (struct objfile *objfile); extern int emit_clear_objfiles_event (void); diff --git a/gdb/python/py-events.h b/gdb/python/py-events.h index 348dabc9225..2275d896e64 100644 --- a/gdb/python/py-events.h +++ b/gdb/python/py-events.h @@ -47,6 +47,9 @@ typedef struct eventregistry_object *exited; eventregistry_object *new_objfile; eventregistry_object *clear_objfiles; + eventregistry_object *new_inferior; + eventregistry_object *inferior_deleted; + eventregistry_object *new_thread; eventregistry_object *inferior_call; eventregistry_object *memory_changed; eventregistry_object *register_changed; diff --git a/gdb/python/py-evts.c b/gdb/python/py-evts.c index 126d18cead4..ad9924190c3 100644 --- a/gdb/python/py-evts.c +++ b/gdb/python/py-evts.c @@ -89,6 +89,15 @@ 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.new_inferior, "new_inferior") < 0) + return -1; + + if (add_new_registry (&gdb_py_events.inferior_deleted, "inferior_deleted") < 0) + return -1; + + if (add_new_registry (&gdb_py_events.new_thread, "new_thread") < 0) + return -1; + if (add_new_registry (&gdb_py_events.breakpoint_created, "breakpoint_created") < 0) return -1; diff --git a/gdb/python/py-inferior.c b/gdb/python/py-inferior.c index f6a24a090f2..d7c6810884f 100644 --- a/gdb/python/py-inferior.c +++ b/gdb/python/py-inferior.c @@ -30,6 +30,13 @@ #include "py-event.h" #include "py-stopevent.h" +extern PyTypeObject new_thread_event_object_type + CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("event_object"); +extern PyTypeObject new_inferior_event_object_type + CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("event_object"); +extern PyTypeObject inferior_deleted_event_object_type + CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("event_object"); + struct threadlist_entry { thread_object *thread_obj; struct threadlist_entry *next; @@ -235,6 +242,60 @@ inferior_to_inferior_object (struct inferior *inferior) return (PyObject *) inf_obj; } +/* Called when a new inferior is created. Notifies any Python event + listeners. */ +static void +python_new_inferior (struct inferior *inf) +{ + if (!gdb_python_initialized) + return; + + gdbpy_enter enter_py (python_gdbarch, python_language); + + if (evregpy_no_listeners_p (gdb_py_events.new_inferior)) + return; + + gdbpy_ref<> inf_obj (inferior_to_inferior_object (inf)); + if (inf_obj == NULL) + { + gdbpy_print_stack (); + return; + } + + gdbpy_ref<> event (create_event_object (&new_inferior_event_object_type)); + if (event == NULL + || evpy_add_attribute (event.get (), "inferior", inf_obj.get ()) < 0 + || evpy_emit_event (event.get (), gdb_py_events.new_inferior) < 0) + gdbpy_print_stack (); +} + +/* Called when an inferior is removed. Notifies any Python event + listeners. */ +static void +python_inferior_deleted (struct inferior *inf) +{ + if (!gdb_python_initialized) + return; + + gdbpy_enter enter_py (python_gdbarch, python_language); + + if (evregpy_no_listeners_p (gdb_py_events.inferior_deleted)) + return; + + gdbpy_ref<> inf_obj (inferior_to_inferior_object (inf)); + if (inf_obj == NULL) + { + gdbpy_print_stack (); + return; + } + + gdbpy_ref<> event (create_event_object (&inferior_deleted_event_object_type)); + if (event == NULL + || evpy_add_attribute (event.get (), "inferior", inf_obj.get ()) < 0 + || evpy_emit_event (event.get (), gdb_py_events.inferior_deleted) < 0) + gdbpy_print_stack (); +} + /* Finds the Python Inferior object for the given PID. Returns a reference, or NULL if PID does not match any inferior object. */ @@ -298,6 +359,15 @@ add_thread_object (struct thread_info *tp) inf_obj->threads = entry; inf_obj->nthreads++; + + if (evregpy_no_listeners_p (gdb_py_events.new_thread)) + return; + + gdbpy_ref<> event (create_thread_event_object (&new_thread_event_object_type, + (PyObject *) thread_obj)); + if (event == NULL + || evpy_emit_event (event.get (), gdb_py_events.new_thread) < 0) + gdbpy_print_stack (); } static void @@ -823,6 +893,8 @@ gdbpy_initialize_inferior (void) observer_attach_register_changed (python_on_register_change); observer_attach_inferior_exit (python_inferior_exit); observer_attach_new_objfile (python_new_objfile); + observer_attach_inferior_added (python_new_inferior); + observer_attach_inferior_removed (python_inferior_deleted); membuf_object_type.tp_new = PyType_GenericNew; if (PyType_Ready (&membuf_object_type) < 0) @@ -970,3 +1042,19 @@ PyTypeObject membuf_object_type = { 0, /* tp_init */ 0, /* tp_alloc */ }; + +GDBPY_NEW_EVENT_TYPE (new_thread, + "gdb.NewThreadEvent", + "NewThreadEvent", + "GDB new thread event object", + thread_event_object_type); +GDBPY_NEW_EVENT_TYPE (new_inferior, + "gdb.NewInferiorEvent", + "NewInferiorEvent", + "GDB new inferior event object", + event_object_type); +GDBPY_NEW_EVENT_TYPE (inferior_deleted, + "gdb.InferiorDeletedEvent", + "InferiorDeletedEvent", + "GDB inferior deleted event object", + event_object_type); diff --git a/gdb/python/py-threadevent.c b/gdb/python/py-threadevent.c index 921744442f7..7211fa26da2 100644 --- a/gdb/python/py-threadevent.c +++ b/gdb/python/py-threadevent.c @@ -48,17 +48,18 @@ get_event_thread (void) } PyObject * -create_thread_event_object (PyTypeObject *py_type) +create_thread_event_object (PyTypeObject *py_type, PyObject *thread) { - PyObject *thread = NULL; - gdbpy_ref<> thread_event_obj (create_event_object (py_type)); if (thread_event_obj == NULL) return NULL; - thread = get_event_thread (); - if (!thread) - return NULL; + if (thread == NULL) + { + thread = get_event_thread (); + if (!thread) + return NULL; + } if (evpy_add_attribute (thread_event_obj.get (), "inferior_thread", diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index ebb83f0cba8..0c3582f180f 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -630,6 +630,12 @@ int gdbpy_initialize_new_objfile_event (void) CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; int gdbpy_initialize_clear_objfiles_event (void) CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; +int gdbpy_initialize_new_inferior_event (void) + CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; +int gdbpy_initialize_inferior_deleted_event (void) + CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; +int gdbpy_initialize_new_thread_event (void) + CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; int gdbpy_initialize_arch (void) CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; int gdbpy_initialize_xmethods (void) diff --git a/gdb/python/python.c b/gdb/python/python.c index b086cef2510..fbb4747c5fa 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -1603,6 +1603,9 @@ do_start_initialization () || gdbpy_initialize_thread_event () < 0 || gdbpy_initialize_new_objfile_event () < 0 || gdbpy_initialize_clear_objfiles_event () < 0 + || gdbpy_initialize_new_inferior_event () < 0 + || gdbpy_initialize_inferior_deleted_event () < 0 + || gdbpy_initialize_new_thread_event () < 0 || gdbpy_initialize_arch () < 0 || gdbpy_initialize_xmethods () < 0 || gdbpy_initialize_unwind () < 0) diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 8d8dc3c04c8..3862a7c861f 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-09-11 Tom Tromey + + * gdb.python/py-infthread.exp: Add tests for new_thread event. + * gdb.python/py-inferior.exp: Add tests for new inferior events. + 2017-09-08 Christoph Weinmann * gdb.fortran/printing-types.exp: New file. diff --git a/gdb/testsuite/gdb.python/py-inferior.exp b/gdb/testsuite/gdb.python/py-inferior.exp index c2ea2c2a4bc..715c693c408 100644 --- a/gdb/testsuite/gdb.python/py-inferior.exp +++ b/gdb/testsuite/gdb.python/py-inferior.exp @@ -214,12 +214,33 @@ with_test_prefix "is_valid" { gdb_test "python print (inf_list\[0\].is_valid())" "True" \ "check inferior validity 1" + gdb_py_test_multiple "install new inferior event handler" \ + "python" "" \ + "my_inferior_count = 1" "" \ + "def new_inf_handler(evt):" "" \ + " global my_inferior_count" "" \ + " if evt.inferior is not None:" "" \ + " my_inferior_count = my_inferior_count + 1" "" \ + "gdb.events.new_inferior.connect(new_inf_handler)" "" \ + "end" "" + gdb_py_test_multiple "install inferior deleted event handler" \ + "python" "" \ + "def del_inf_handler(evt):" "" \ + " global my_inferior_count" "" \ + " if evt.inferior is not None:" "" \ + " my_inferior_count = my_inferior_count - 1" "" \ + "gdb.events.inferior_deleted.connect(del_inf_handler)" "" \ + "end" "" + gdb_test "add-inferior" "Added inferior 2.*" "add empty inferior 2" gdb_py_test_silent_cmd "python inf_list = gdb.inferiors()" "get new list" 1 gdb_test "python print (len(inf_list))" "2" "get inferior list length 2" gdb_test "python print (inf_list\[0\].is_valid())" "True" \ "check inferior validity 2" + gdb_test "python print (my_inferior_count)" "2" \ + "test new-inferior event handler" + gdb_test "python print (inf_list\[1\].is_valid())" "True" \ "check inferior validity 3" @@ -229,6 +250,9 @@ with_test_prefix "is_valid" { gdb_test "python print (inf_list\[1\].is_valid())" "False" \ "check inferior validity 5" + + gdb_test "python print (my_inferior_count)" "1" \ + "test inferior-deleted event handler" } # Test gdb.selected_inferior() diff --git a/gdb/testsuite/gdb.python/py-infthread.exp b/gdb/testsuite/gdb.python/py-infthread.exp index a5fed8d8934..0711d6994e8 100644 --- a/gdb/testsuite/gdb.python/py-infthread.exp +++ b/gdb/testsuite/gdb.python/py-infthread.exp @@ -30,6 +30,16 @@ clean_restart ${testfile} # Skip all tests if Python scripting is not enabled. if { [skip_python_tests] } { continue } +gdb_py_test_multiple "install new_thread event handler" \ + "python" "" \ + "seen_a_thread = False" "" \ + "def thread_handler(evt):" "" \ + " if evt.inferior_thread is not None:" "" \ + " global seen_a_thread" "" \ + " seen_a_thread = True" "" \ + "gdb.events.new_thread.connect(thread_handler)" "" \ + "end" "" + # The following tests require execution. if ![runto_main] then { @@ -37,6 +47,8 @@ if ![runto_main] then { return 0 } +gdb_test "python print(seen_a_thread)" "True" + # Test basic gdb.Inferior attributes and methods. gdb_py_test_silent_cmd "python t0 = gdb.selected_thread ()" "test gdb.selected_thread" 1