Make 'import gdb.events' work
authorTom Tromey <tromey@adacore.com>
Fri, 3 Jun 2022 13:59:49 +0000 (07:59 -0600)
committerTom Tromey <tromey@adacore.com>
Tue, 5 Jul 2022 16:28:39 +0000 (10:28 -0600)
Pierre-Marie noticed that, while gdb.events is a Python module, it
can't be imported.  This patch changes how this module is created, so
that it can be imported, while also ensuring that the module is always
visible, just as it was in the past.

This new approach required one non-obvious change -- when running
gdb.base/warning.exp, where --data-directory is intentionally not
found, the event registries can now be nullptr.  Consequently, this
patch probably also requires

    https://sourceware.org/pipermail/gdb-patches/2022-June/189796.html

Note that this patch obsoletes

    https://sourceware.org/pipermail/gdb-patches/2022-June/189797.html

gdb/python/lib/gdb/__init__.py
gdb/python/py-evtregistry.c
gdb/python/py-evts.c
gdb/python/python-internal.h
gdb/python/python.c
gdb/testsuite/gdb.python/py-events.exp

index a52f6b46413952decfbbe0d7c90fae78925557eb..17ee6a19e14a96b75c7c3eb6b3279f21e0be033a 100644 (file)
@@ -27,6 +27,11 @@ else:
 
 from _gdb import *
 
+# Historically, gdb.events was always available, so ensure it's
+# still available without an explicit import.
+import _gdbevents as events
+sys.modules['gdb.events'] = events
+
 
 class _GdbFile(object):
     # These two are needed in Python 3
index ef96c483f47c27572bcc72ee546b2327aa177720..f3a7f0ca244f8b169faa19d24c2c21e611f55057 100644 (file)
@@ -118,7 +118,9 @@ gdbpy_initialize_eventregistry (void)
 bool
 evregpy_no_listeners_p (eventregistry_object *registry)
 {
-  return PyList_Size (registry->callbacks) == 0;
+  /* REGISTRY can be nullptr if gdb failed to find the data directory
+     at startup.  */
+  return registry == nullptr || PyList_Size (registry->callbacks) == 0;
 }
 
 static PyMethodDef eventregistry_object_methods[] =
index 23a5d75ae21beeb41f0110764c0e919446200578..ca9326a1469c101aadf5bf429512f4578315dff4 100644 (file)
@@ -23,7 +23,7 @@
 static struct PyModuleDef EventModuleDef =
 {
   PyModuleDef_HEAD_INIT,
-  "gdb.events",
+  "_gdbevents",
   NULL,
   -1,
   NULL,
@@ -33,7 +33,8 @@ static struct PyModuleDef EventModuleDef =
   NULL
 };
 
-/* Initialize python events.  */
+/* Helper function to add a single event registry to the events
+   module.  */
 
 static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 add_new_registry (eventregistry_object **registryp, const char *name)
@@ -48,24 +49,21 @@ add_new_registry (eventregistry_object **registryp, const char *name)
                                 (PyObject *)(*registryp));
 }
 
-int
-gdbpy_initialize_py_events (void)
+/* Create and populate the _gdbevents module.  Note that this is
+   always created, see the base gdb __init__.py.  */
+
+PyMODINIT_FUNC
+gdbpy_events_mod_func ()
 {
   gdb_py_events.module = PyModule_Create (&EventModuleDef);
+  if (gdb_py_events.module == nullptr)
+    return nullptr;
 
-  if (!gdb_py_events.module)
-    return -1;
-
-#define GDB_PY_DEFINE_EVENT(name)                              \
+#define GDB_PY_DEFINE_EVENT(name)                                      \
   if (add_new_registry (&gdb_py_events.name, #name) < 0)       \
-    return -1;
+    return nullptr;
 #include "py-all-events.def"
 #undef GDB_PY_DEFINE_EVENT
 
-  if (gdb_pymodule_addobject (gdb_module,
-                             "events",
-                             (PyObject *) gdb_py_events.module) < 0)
-    return -1;
-
-  return 0;
+  return gdb_py_events.module;
 }
index 5ff9989af83cd255263f81535e0e884d4ee91366..5d296a73e9ac09a0b733f75ea7fc66eb4dfa8bff 100644 (file)
@@ -521,8 +521,6 @@ int gdbpy_initialize_eventregistry (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 int gdbpy_initialize_event (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_py_events (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 int gdbpy_initialize_arch (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 int gdbpy_initialize_registers ()
@@ -543,6 +541,8 @@ void gdbpy_finalize_micommands ();
 int gdbpy_initialize_disasm ()
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 
+PyMODINIT_FUNC gdbpy_events_mod_func ();
+
 /* A wrapper for PyErr_Fetch that handles reference counting for the
    caller.  */
 class gdbpy_err_fetch
index 8f526bba84ec13cacf831330e00b6466f11959e0..2f1a00e629cb681b7c6401ceb9c887dafaf6235c 100644 (file)
@@ -2005,11 +2005,20 @@ do_start_initialization ()
      remain alive for the duration of the program's execution, so
      it is not freed after this call.  */
   Py_SetProgramName (progname_copy);
-
-  /* Define _gdb as a built-in module.  */
-  PyImport_AppendInittab ("_gdb", init__gdb_module);
 #endif
 
+  /* Define all internal modules.  These are all imported (and thus
+     created) during initialization.  */
+  struct _inittab mods[3] =
+  {
+    { "_gdb", init__gdb_module },
+    { "_gdbevents", gdbpy_events_mod_func },
+    { nullptr, nullptr }
+  };
+
+  if (PyImport_ExtendInittab (mods) < 0)
+    return false;
+
   Py_Initialize ();
 #if PY_VERSION_HEX < 0x03090000
   /* PyEval_InitThreads became deprecated in Python 3.9 and will
@@ -2077,7 +2086,6 @@ do_start_initialization ()
       || gdbpy_initialize_thread () < 0
       || gdbpy_initialize_inferior () < 0
       || gdbpy_initialize_eventregistry () < 0
-      || gdbpy_initialize_py_events () < 0
       || gdbpy_initialize_event () < 0
       || gdbpy_initialize_arch () < 0
       || gdbpy_initialize_registers () < 0
index a9ababbc40c20b60eeb1bda28a67bc95ada95358..94762739cd45612cd1f69ee39ac61264599761b8 100644 (file)
@@ -38,6 +38,8 @@ clean_restart ${testfile}
 
 if { [skip_python_tests] } { continue }
 
+gdb_test_no_output "python import gdb.events"
+
 set pyfile [gdb_remote_download host ${srcdir}/${subdir}/py-events.py]
 gdb_test_no_output "source ${pyfile}" "load python file"