gdb/python: add mechanism to manage Python initialization functions
authorAndrew Burgess <aburgess@redhat.com>
Fri, 16 Sep 2022 15:08:17 +0000 (16:08 +0100)
committerAndrew Burgess <aburgess@redhat.com>
Fri, 5 May 2023 17:24:42 +0000 (18:24 +0100)
Currently, when we add a new python sub-system to GDB,
e.g. py-inferior.c, we end up having to create a new function like
gdbpy_initialize_inferior, which then has to be called from the
function do_start_initialization in python.c.

In some cases (py-micmd.c and py-tui.c), we have two functions
gdbpy_initialize_*, and gdbpy_finalize_*, with the second being called
from finalize_python which is also in python.c.

This commit proposes a mechanism to manage these initialization and
finalization calls, this means that adding a new Python subsystem will
no longer require changes to python.c or python-internal.h, instead,
the initialization and finalization functions will be registered
directly from the sub-system file, e.g. py-inferior.c, or py-micmd.c.

The initialization and finalization functions are managed through a
new class gdbpy_initialize_file in python-internal.h.  This class
contains a single global vector of all the initialization and
finalization functions.

In each Python sub-system we create a new gdbpy_initialize_file
object, the object constructor takes care of registering the two
callback functions.

Now from python.c we can call static functions on the
gdbpy_initialize_file class which take care of walking the callback
list and invoking each callback in turn.

To slightly simplify the Python sub-system files I added a new macro
GDBPY_INITIALIZE_FILE, which hides the need to create an object.  We
can now just do this:

  GDBPY_INITIALIZE_FILE (gdbpy_initialize_registers);

One possible problem with this change is that there is now no
guaranteed ordering of how the various sub-systems are initialized (or
finalized).  To try and avoid dependencies creeping in I have added a
use of the environment variable GDB_REVERSE_INIT_FUNCTIONS, this is
the same environment variable used in the generated init.c file.

Just like with init.c, when this environment variable is set we
reverse the list of Python initialization (and finalization)
functions.  As there is already a test that starts GDB with the
environment variable set then this should offer some level of
protection against dependencies creeping in - though for full
protection I guess we'd need to run all gdb.python/*.exp tests with
the variable set.

I have tested this patch with the environment variable set, and saw no
regressions, so I think we are fine right now.

One other change of note was for gdbpy_initialize_gdb_readline, this
function previously returned void.  In order to make this function
have the correct signature I've updated its return type to int, and we
now return 0 to indicate success.

All of the other initialize (and finalize) functions have been made
static within their respective sub-system files.

There should be no user visible changes after this commit.

35 files changed:
gdb/python/py-arch.c
gdb/python/py-auto-load.c
gdb/python/py-block.c
gdb/python/py-breakpoint.c
gdb/python/py-cmd.c
gdb/python/py-connection.c
gdb/python/py-disasm.c
gdb/python/py-event.c
gdb/python/py-evtregistry.c
gdb/python/py-finishbreakpoint.c
gdb/python/py-frame.c
gdb/python/py-function.c
gdb/python/py-gdb-readline.c
gdb/python/py-inferior.c
gdb/python/py-infthread.c
gdb/python/py-instruction.c
gdb/python/py-lazy-string.c
gdb/python/py-linetable.c
gdb/python/py-membuf.c
gdb/python/py-micmd.c
gdb/python/py-objfile.c
gdb/python/py-param.c
gdb/python/py-progspace.c
gdb/python/py-record-btrace.c
gdb/python/py-record.c
gdb/python/py-registers.c
gdb/python/py-symbol.c
gdb/python/py-symtab.c
gdb/python/py-tui.c
gdb/python/py-type.c
gdb/python/py-unwind.c
gdb/python/py-value.c
gdb/python/py-xmethods.c
gdb/python/python-internal.h
gdb/python/python.c

index 51559ca7c35e471faa01f35010ec043c6c56939b..4d133d1fe144fac1a1e5e5cd10db8f02f6f46945 100644 (file)
@@ -344,7 +344,7 @@ gdbpy_all_architecture_names (PyObject *self, PyObject *args)
 
 /* Initializes the Architecture class in the gdb module.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_arch (void)
 {
   arch_object_type.tp_new = PyType_GenericNew;
@@ -355,6 +355,10 @@ gdbpy_initialize_arch (void)
                                 (PyObject *) &arch_object_type);
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_arch);
+
+\f
+
 static PyMethodDef arch_object_methods [] = {
   { "name", archpy_name, METH_NOARGS,
     "name () -> String.\n\
index ed6202d794b3e7dc95f9e27d6d85657345bec47d..76ae3af39a026f3eef57d01ff5da17fdba13b7ff 100644 (file)
@@ -56,7 +56,7 @@ info_auto_load_python_scripts (const char *pattern, int from_tty)
   auto_load_info_scripts (pattern, from_tty, &extension_language_python);
 }
 \f
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_auto_load (void)
 {
   add_setshow_boolean_cmd ("python-scripts", class_support,
@@ -95,3 +95,5 @@ Print the list of automatically loaded Python scripts, deprecated."));
 
   return 0;
 }
+
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_auto_load);
index da33d4cdd942849b404c7d52a046db25af17d66d..09fa74d862cac5779d3cb484252b9852e31528cd 100644 (file)
@@ -418,7 +418,7 @@ blpy_iter_is_valid (PyObject *self, PyObject *args)
   Py_RETURN_TRUE;
 }
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_blocks (void)
 {
   block_object_type.tp_new = PyType_GenericNew;
@@ -437,6 +437,8 @@ gdbpy_initialize_blocks (void)
                                 (PyObject *) &block_syms_iterator_object_type);
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_blocks);
+
 \f
 
 static PyMethodDef block_object_methods[] = {
index 880f1b5c1e216e7560365686b0d2ec14abec52d1..becb04c91c157c1191b2122b7ddc9bdffd3f48f3 100644 (file)
@@ -1246,7 +1246,7 @@ gdbpy_breakpoint_modified (struct breakpoint *b)
 \f
 
 /* Initialize the Python breakpoint code.  */
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_breakpoints (void)
 {
   int i;
@@ -1286,7 +1286,7 @@ gdbpy_initialize_breakpoints (void)
 
 /* Initialize the Python BreakpointLocation code.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_breakpoint_locations ()
 {
   if (PyType_Ready (&breakpoint_location_object_type) < 0)
@@ -1450,6 +1450,9 @@ _initialize_py_breakpoint ()
        &setdebuglist, &showdebuglist);
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_breakpoints);
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_breakpoint_locations);
+
 /* Python function to set the enabled state of a breakpoint location.  */
 
 static int
index dbba20407cdd277d7f5fe47a29117e7798d8d29f..20a384d690747a4a330a4a9bfcdfaaf3f8d85d3a 100644 (file)
@@ -551,7 +551,7 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kw)
 
 /* Initialize the 'commands' code.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_commands (void)
 {
   int i;
@@ -601,6 +601,8 @@ gdbpy_initialize_commands (void)
   return 0;
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_commands);
+
 \f
 
 static PyMethodDef cmdpy_object_methods[] =
index 84435eb311914aff51941e1b81723720a6ac1c00..3df12b435bb1ebcfd9c8cc6a3614e63f6c93f0fb 100644 (file)
@@ -285,7 +285,7 @@ connpy_get_connection_details (PyObject *self, void *closure)
 
 /* Python specific initialization for this file.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_connection (void)
 {
   if (PyType_Ready (&connection_object_type) < 0)
@@ -447,6 +447,8 @@ _initialize_py_connection ()
                                             "py-connection");
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_connection);
+
 /* Methods for the gdb.TargetConnection object type.  */
 
 static PyMethodDef connection_object_methods[] =
index 2dabec0013dcc8fe7dbb8ef987ba96e6b41f66b1..6b19b556d0d2fd809c153f661d658a909782eea1 100644 (file)
@@ -1019,7 +1019,7 @@ static struct PyModuleDef python_disassembler_module_def =
 
 /* Called to initialize the Python structures in this file.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_disasm ()
 {
   /* Create the _gdb.disassembler module, and add it to the _gdb module.  */
@@ -1053,6 +1053,10 @@ gdbpy_initialize_disasm ()
   return 0;
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_disasm);
+
+\f
+
 /* Describe the gdb.disassembler.DisassembleInfo type.  */
 
 PyTypeObject disasm_info_object_type = {
index 3ff31acf85bbe780344653ca7cb9f764ea45e71e..bc3d4a26be0b5a644548eb2cf9b6f0e7f5b6d06e 100644 (file)
@@ -54,7 +54,7 @@ evpy_add_attribute (PyObject *event, const char *name, PyObject *attr)
 
 /* Initialize the Python event code.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_event (void)
 {
   return gdbpy_initialize_event_generic (&event_object_type,
@@ -114,6 +114,8 @@ evpy_emit_event (PyObject *event,
   return 0;
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_event);
+
 static gdb_PyGetSetDef event_object_getset[] =
 {
   { "__dict__", gdb_py_generic_dict, NULL,
index 49c43593381a3c00d8218e48a57c36d4ccc0169b..af50ae21a68977247e7d6e9ed437ad5e9112c51f 100644 (file)
@@ -102,7 +102,7 @@ evregpy_dealloc (PyObject *self)
 
 /* Initialize the Python event registry code.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_eventregistry (void)
 {
   if (PyType_Ready (&eventregistry_object_type) < 0)
@@ -123,6 +123,8 @@ evregpy_no_listeners_p (eventregistry_object *registry)
   return registry == nullptr || PyList_Size (registry->callbacks) == 0;
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_eventregistry);
+
 static PyMethodDef eventregistry_object_methods[] =
 {
   { "connect", evregpy_connect, METH_VARARGS, "Add function" },
index 7122fa820f60c563ce813e90c204bbc63f96c403..bb4591e3a6ba1da282e86d9016c9260873c8170a 100644 (file)
@@ -435,7 +435,7 @@ bpfinishpy_handle_exit (struct inferior *inf)
 
 /* Initialize the Python finish breakpoint code.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_finishbreakpoints (void)
 {
   if (!gdbpy_breakpoint_init_breakpoint_type ())
@@ -456,6 +456,10 @@ gdbpy_initialize_finishbreakpoints (void)
   return 0;
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_finishbreakpoints);
+
+\f
+
 static gdb_PyGetSetDef finish_breakpoint_object_getset[] = {
   { "return_value", bpfinishpy_get_returnvalue, NULL,
   "gdb.Value object representing the return value, if any. \
index 082358effab4f6c43aca690c7cee5d57bb705323..1a55e514e3964acb3aa601b23f6c732fd24c6bb4 100644 (file)
@@ -717,7 +717,7 @@ frapy_richcompare (PyObject *self, PyObject *other, int op)
 
 /* Sets up the Frame API in the gdb module.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_frames (void)
 {
   frame_object_type.tp_new = PyType_GenericNew;
@@ -749,6 +749,8 @@ gdbpy_initialize_frames (void)
                                 (PyObject *) &frame_object_type);
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_frames);
+
 \f
 
 static PyMethodDef frame_object_methods[] = {
index e13f7b02d7f139f272c57a42bc6f674ae2d68f24..0067dee4e18895bc2b8a6cd7d0f836679f2d4150 100644 (file)
@@ -134,7 +134,7 @@ fnpy_init (PyObject *self, PyObject *args, PyObject *kwds)
 
 /* Initialize internal function support.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_functions (void)
 {
   fnpy_object_type.tp_new = PyType_GenericNew;
@@ -145,6 +145,8 @@ gdbpy_initialize_functions (void)
                                 (PyObject *) &fnpy_object_type);
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_functions);
+
 \f
 
 PyTypeObject fnpy_object_type =
index b9294ad9afc47de683f123dff648b6b3b26c767e..124cec8055d0f0bc10ca179adafd7183d2e9ff5e 100644 (file)
@@ -90,7 +90,7 @@ gdbpy_readline_wrapper (FILE *sys_stdin, FILE *sys_stdout,
 
 /* Initialize Python readline support.  */
 
-void
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_gdb_readline (void)
 {
   /* Python's readline module conflicts with GDB's use of readline
@@ -114,5 +114,8 @@ class GdbRemoveReadlineFinder:\n\
 sys.meta_path.append(GdbRemoveReadlineFinder())\n\
 ") == 0)
     PyOS_ReadlineFunctionPointer = gdbpy_readline_wrapper;
+
+  return 0;
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_gdb_readline);
index 8b21f28afbe7f8f93736a922482092b9eb3d2914..982d0f803a0b5c24d30f0a0f40a63d3153de8ece 100644 (file)
@@ -802,7 +802,7 @@ gdbpy_selected_inferior (PyObject *self, PyObject *args)
          inferior_to_inferior_object (current_inferior ()).release ());
 }
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_inferior (void)
 {
   if (PyType_Ready (&inferior_object_type) < 0)
@@ -838,6 +838,10 @@ gdbpy_initialize_inferior (void)
   return 0;
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_inferior);
+
+\f
+
 static gdb_PyGetSetDef inferior_object_getset[] =
 {
   { "num", infpy_get_num, NULL, "ID of inferior, as assigned by GDB.", NULL },
index 9343c8bba70d5bb2355baa8b2106e5e51eb90926..1bd25d013202665e011de11bc49eb45bb260be26 100644 (file)
@@ -361,7 +361,7 @@ gdbpy_selected_thread (PyObject *self, PyObject *args)
   Py_RETURN_NONE;
 }
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_thread (void)
 {
   if (PyType_Ready (&thread_object_type) < 0)
@@ -371,6 +371,10 @@ gdbpy_initialize_thread (void)
                                 (PyObject *) &thread_object_type);
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_thread);
+
+\f
+
 static gdb_PyGetSetDef thread_object_getset[] =
 {
   { "name", thpy_get_name, thpy_set_name,
index ba85a505de4f02d55ddb288e2b47436f900e4f2a..0ba8561d9390e1e6426db18e0fe9912ef337b9fd 100644 (file)
@@ -81,10 +81,12 @@ py_insn_get_insn_type ()
 
 /* Sets up the gdb.Instruction type.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_instruction (void)
 {
   if (py_insn_get_insn_type () == nullptr)
     return -1;
   return 0;
 }
+
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_instruction);
index 9b1205463d45d03a5f2416e7fc35176c401ecc8e..25a22b78af41b33e38448f51f832d584287018b8 100644 (file)
@@ -234,7 +234,7 @@ gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
   return (PyObject *) str_obj;
 }
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_lazy_string (void)
 {
   if (PyType_Ready (&lazy_string_object_type) < 0)
@@ -296,6 +296,8 @@ gdbpy_extract_lazy_string (PyObject *string, CORE_ADDR *addr,
   encoding->reset (lazy->encoding ? xstrdup (lazy->encoding) : NULL);
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_lazy_string);
+
 \f
 
 static PyMethodDef lazy_string_object_methods[] = {
index 6e89c43e65fbb756e73cf4621091e0bca3a5f091..3b173712270bba15a1c12bc00a82e76bfbbf6661 100644 (file)
@@ -285,7 +285,7 @@ ltpy_dealloc (PyObject *self)
 /* Initialize LineTable, LineTableEntry and LineTableIterator
    objects.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_linetable (void)
 {
   if (PyType_Ready (&linetable_object_type) < 0)
@@ -446,6 +446,8 @@ ltpy_iter_is_valid (PyObject *self, PyObject *args)
   Py_RETURN_TRUE;
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_linetable);
+
 \f
 
 static PyMethodDef linetable_object_methods[] = {
index 9390bcfcfc168ed146d06f7e611ab7f42fb308dd..9ff0326c38ff8e57b5a08cc17e47f0ffa2e2783b 100644 (file)
@@ -99,7 +99,7 @@ get_buffer (PyObject *self, Py_buffer *buf, int flags)
 
 /* General Python initialization callback.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_membuf (void)
 {
   membuf_object_type.tp_new = PyType_GenericNew;
@@ -110,6 +110,10 @@ gdbpy_initialize_membuf (void)
                                 (PyObject *) &membuf_object_type);
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_membuf);
+
+\f
+
 static PyBufferProcs buffer_procs =
 {
   get_buffer
index c7c5a609f5611929c0a9955f0daff6e9ff412a56..e86807d049f39ab6eee5d0a42dcaa662021b425f 100644 (file)
@@ -595,7 +595,7 @@ micmdpy_dealloc (PyObject *obj)
 
 /* Python initialization for the MI commands components.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_micommands ()
 {
   micmdpy_object_type.tp_new = PyType_GenericNew;
@@ -614,7 +614,9 @@ gdbpy_initialize_micommands ()
   return 0;
 }
 
-void
+/* Cleanup just before GDB shuts down the Python interpreter.  */
+
+static void
 gdbpy_finalize_micommands ()
 {
   /* mi_command_py objects hold references to micmdpy_object objects.  They must
@@ -737,3 +739,5 @@ _initialize_py_micmd ()
      show_pymicmd_debug,
      &setdebuglist, &showdebuglist);
 }
+
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_micommands, gdbpy_finalize_micommands);
index b15a3fe2dba464dea6f890e7934e9f4eb2f1d091..ad72f3f0423319d1ae4b659ee0f4a8e7847b2b64 100644 (file)
@@ -704,7 +704,7 @@ objfile_to_objfile_object (struct objfile *objfile)
   return gdbpy_ref<>::new_reference (result);
 }
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_objfile (void)
 {
   if (PyType_Ready (&objfile_object_type) < 0)
@@ -714,6 +714,8 @@ gdbpy_initialize_objfile (void)
                                 (PyObject *) &objfile_object_type);
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_objfile);
+
 \f
 
 static PyMethodDef objfile_object_methods[] =
index a1bd4e09788054bae74aab37fe48cef812958af3..3bae2d44ad9822ea7e00a5db0dca86cffc6c9a6a 100644 (file)
@@ -906,7 +906,7 @@ parmpy_dealloc (PyObject *obj)
 }
 
 /* Initialize the 'parameters' module.  */
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_parameters (void)
 {
   int i;
@@ -934,6 +934,8 @@ gdbpy_initialize_parameters (void)
                                 (PyObject *) &parmpy_object_type);
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_parameters);
+
 \f
 
 PyTypeObject parmpy_object_type =
index 571a104641a0c2181aa07b876089eb49354da640..a231d240342170a02dad9039ca704aff5655df5c 100644 (file)
@@ -529,7 +529,7 @@ gdbpy_is_progspace (PyObject *obj)
   return PyObject_TypeCheck (obj, &pspace_object_type);
 }
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_pspace (void)
 {
   if (PyType_Ready (&pspace_object_type) < 0)
@@ -539,6 +539,8 @@ gdbpy_initialize_pspace (void)
                                 (PyObject *) &pspace_object_type);
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_pspace);
+
 \f
 
 static gdb_PyGetSetDef pspace_getset[] =
index 4af86672d26d134069177c7a9694a1f9adffaea8..7802a7d9534759992e14f57942a865703e1e7465 100644 (file)
@@ -816,7 +816,7 @@ static PyMappingMethods btpy_list_mapping_methods =
 
 /* Sets up the btrace record API.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_btrace (void)
 {
   btpy_list_type.tp_new = PyType_GenericNew;
@@ -837,3 +837,5 @@ gdbpy_initialize_btrace (void)
 
   return PyType_Ready (&btpy_list_type);
 }
+
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_btrace);
index 1e40f2cded0ea0425133810c728fbdabfae750ff..5fc64f6aa780c3a62602779766a5f5cc42623a2e 100644 (file)
@@ -544,7 +544,7 @@ static gdb_PyGetSetDef recpy_gap_getset[] = {
 
 /* Sets up the record API in the gdb module.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_record (void)
 {
   recpy_record_type.tp_new = PyType_GenericNew;
@@ -648,3 +648,5 @@ gdbpy_stop_recording (PyObject *self, PyObject *args)
 
   Py_RETURN_NONE;
 }
+
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_record);
index 9531cf7b50259f9cb9ef96e8baeaa1b4a6378963..557f1d963c46e7ed287498aa76daefe30e099c8b 100644 (file)
@@ -427,7 +427,7 @@ gdbpy_parse_register_id (struct gdbarch *gdbarch, PyObject *pyo_reg_id,
 
 /* Initializes the new Python classes from this file in the gdb module.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_registers ()
 {
   register_descriptor_object_type.tp_new = PyType_GenericNew;
@@ -462,6 +462,10 @@ gdbpy_initialize_registers ()
           (PyObject *) &register_descriptor_iterator_object_type));
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_registers);
+
+\f
+
 static PyMethodDef register_descriptor_iterator_object_methods [] = {
   { "find", (PyCFunction) register_descriptor_iter_find,
     METH_VARARGS | METH_KEYWORDS,
index 066a27f0e35c0ebc9dc2da5ab6671e4a9af1692e..ff3d18504e77a7ff353cae3ba219dd6f7c16a6bd 100644 (file)
@@ -618,7 +618,7 @@ gdbpy_lookup_static_symbols (PyObject *self, PyObject *args, PyObject *kw)
   return return_list.release ();
 }
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_symbols (void)
 {
   if (PyType_Ready (&symbol_object_type) < 0)
@@ -687,6 +687,8 @@ gdbpy_initialize_symbols (void)
                                 (PyObject *) &symbol_object_type);
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_symbols);
+
 \f
 
 static gdb_PyGetSetDef symbol_object_getset[] = {
index 86ef72549566d2a36aa64d783d611555f3a08803..26aa8b2fb043db00a0a917ca8fa9ef464cff231e 100644 (file)
@@ -509,7 +509,7 @@ symtab_object_to_symtab (PyObject *obj)
   return ((symtab_object *) obj)->symtab;
 }
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_symtabs (void)
 {
   symtab_object_type.tp_new = PyType_GenericNew;
@@ -528,6 +528,8 @@ gdbpy_initialize_symtabs (void)
                                 (PyObject *) &sal_object_type);
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_symtabs);
+
 \f
 
 static gdb_PyGetSetDef symtab_object_getset[] = {
index 92fa0591e5c3b8270b22ed6809a6b6ae06a8d4d7..84a435ead6877fefdb3b33ad3c32ac46cfaaace6 100644 (file)
@@ -601,7 +601,7 @@ PyTypeObject gdbpy_tui_window_object_type =
 
 /* Initialize this module.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_tui ()
 {
 #ifdef TUI
@@ -615,10 +615,12 @@ gdbpy_initialize_tui ()
 
 /* Finalize this module.  */
 
-void
+static void
 gdbpy_finalize_tui ()
 {
 #ifdef TUI
   gdbpy_tui_window_maker::invalidate_all ();
 #endif /* TUI */
 }
+
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_tui, gdbpy_finalize_tui);
index feb94efb461fb94f232058520af502e1726a1d5d..1088ee39d96e96cc010338bff21fcec65f1f377f 100644 (file)
@@ -1445,7 +1445,7 @@ gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw)
   return type_to_type_object (type);
 }
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_types (void)
 {
   if (PyType_Ready (&type_object_type) < 0)
@@ -1473,6 +1473,8 @@ gdbpy_initialize_types (void)
                                 (PyObject *) &field_object_type);
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_types);
+
 \f
 
 static gdb_PyGetSetDef type_object_getset[] =
index d83979bed2b3bb2fb481424952b1df003151aeb2..1856e41e2a1baafea558abc6da3c9c67079441fe 100644 (file)
@@ -969,23 +969,9 @@ pyuw_on_new_gdbarch (struct gdbarch *newarch)
     }
 }
 
-void _initialize_py_unwind ();
-void
-_initialize_py_unwind ()
-{
-  add_setshow_boolean_cmd
-      ("py-unwind", class_maintenance, &pyuw_debug,
-       _("Set Python unwinder debugging."),
-       _("Show Python unwinder debugging."),
-       _("When on, Python unwinder debugging is enabled."),
-       NULL,
-       show_pyuw_debug,
-       &setdebuglist, &showdebuglist);
-}
-
 /* Initialize unwind machinery.  */
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_unwind (void)
 {
   gdb::observers::architecture_changed.attach (pyuw_on_new_gdbarch,
@@ -1004,6 +990,24 @@ gdbpy_initialize_unwind (void)
       (PyObject *) &unwind_info_object_type);
 }
 
+void _initialize_py_unwind ();
+void
+_initialize_py_unwind ()
+{
+  add_setshow_boolean_cmd
+      ("py-unwind", class_maintenance, &pyuw_debug,
+       _("Set Python unwinder debugging."),
+       _("Show Python unwinder debugging."),
+       _("When on, Python unwinder debugging is enabled."),
+       NULL,
+       show_pyuw_debug,
+       &setdebuglist, &showdebuglist);
+}
+
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_unwind);
+
+\f
+
 static PyMethodDef pending_frame_object_methods[] =
 {
   { "read_register", (PyCFunction) pending_framepy_read_register,
index 65384c781bc20a54b91a416381a7a36edee422b5..6c62820c63b992b146dee60e8f307973f612af74 100644 (file)
@@ -2056,7 +2056,7 @@ gdbpy_is_value_object (PyObject *obj)
   return PyObject_TypeCheck (obj, &value_object_type);
 }
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_values (void)
 {
   if (PyType_Ready (&value_object_type) < 0)
@@ -2066,6 +2066,8 @@ gdbpy_initialize_values (void)
                                 (PyObject *) &value_object_type);
 }
 
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_values);
+
 \f
 
 static gdb_PyGetSetDef value_object_getset[] = {
index d9fa355e4cb454636cb52023317425563ce489ca..3fca5bf76d4a5aceeb3f698f65205167b8636308 100644 (file)
@@ -599,7 +599,7 @@ python_xmethod_worker::python_xmethod_worker (PyObject *py_worker,
   Py_INCREF (this_type);
 }
 
-int
+static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
 gdbpy_initialize_xmethods (void)
 {
   py_match_method_name = PyUnicode_FromString (match_method_name);
@@ -613,3 +613,5 @@ gdbpy_initialize_xmethods (void)
 
   return 1;
 }
+
+GDBPY_INITIALIZE_FILE (gdbpy_initialize_xmethods);
index 258f5c42537926efecff2dbc85b4af27147b0dcb..dbd33570a78310986e717861972e63abc74addc8 100644 (file)
@@ -488,77 +488,120 @@ struct gdbarch *arch_object_to_gdbarch (PyObject *obj);
 
 extern struct program_space *progspace_object_to_program_space (PyObject *obj);
 
-void gdbpy_initialize_gdb_readline (void);
-int gdbpy_initialize_auto_load (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_values (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_frames (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_instruction (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_btrace (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_record (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_symtabs (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_commands (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_symbols (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_symtabs (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_blocks (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_types (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_functions (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_pspace (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_objfile (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_breakpoints (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_breakpoint_locations ()
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_finishbreakpoints (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_lazy_string (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_linetable (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_parameters (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_thread (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_inferior (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_eventregistry (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_event (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_arch (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_registers ()
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_xmethods (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_unwind (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_tui ()
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-void gdbpy_finalize_tui ();
-int gdbpy_initialize_membuf ()
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_connection ()
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-int gdbpy_initialize_micommands (void)
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
-void gdbpy_finalize_micommands ();
-int gdbpy_initialize_disasm ()
-  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+/* A class for managing the initialization, and finalization functions
+   from all Python files (e.g. gdb/python/py-*.c).
+
+   Within any Python file, create an instance of this class, passing in
+   the initialization function, and, optionally, the finalization
+   function.
+
+   These functions are added to a single global list of functions, which
+   can then be called from do_start_initialization and finalize_python
+   (see python.c) to initialize all the Python files within GDB.  */
+
+class gdbpy_initialize_file
+{
+  /* The type of a function that can be called just after GDB has setup the
+     Python interpreter.  This function will setup any additional Python
+     state required by a particular subsystem.  Return 0 if the setup was
+     successful, or return -1 if setup failed, in which case a Python
+     exception should have been raised.  */
+
+  using gdbpy_initialize_file_ftype = int (*) (void);
+
+  /* The type of a function that can be called just before GDB shuts down
+     the Python interpreter.  This function can cleanup an Python state
+     that is cached within GDB, for example, if GDB is holding any
+     references to Python objects, these should be released before the
+     Python interpreter is shut down.
+
+     There is no error return in this case.  This function is only called
+     when GDB is already shutting down.  The function should make a best
+     effort to clean up, and then return.  */
+
+  using gdbpy_finalize_file_ftype = void (*) (void);
+
+  /* The type for an initialization and finalization function pair.  */
+
+  using callback_pair_t = std::pair<gdbpy_initialize_file_ftype,
+                                   gdbpy_finalize_file_ftype>;
+
+  /* Return the vector of callbacks.  The vector is defined as a static
+     variable within this function so that it will be initialized the first
+     time this function is called.  This is important, as this function is
+     called as part of the global object initialization process; if the
+     vector was a static variable within this class then we could not
+     guarantee that it had been initialized before it was used.  */
+
+  static std::vector<callback_pair_t> &
+  callbacks ()
+  {
+    static std::vector<callback_pair_t> list;
+    return list;
+  }
+
+public:
+
+  /* Register the initialization (INIT) and finalization (FINI) functions
+     for a Python file.  See the comments on the function types above for
+     when these functions will be called.
+
+     Either of these functions can be nullptr, in which case no function
+     will be called.
+
+     The FINI argument is optional, and defaults to nullptr (no function to
+     call).  */
+
+  gdbpy_initialize_file (gdbpy_initialize_file_ftype init,
+                        gdbpy_finalize_file_ftype fini = nullptr)
+  {
+    callbacks ().emplace_back (init, fini);
+  }
+
+  /* Run all the Python file initialize functions and return true.  If any
+     of the initialize functions fails then this function returns false.
+     In the case of failure it is undefined how many of the initialize
+     functions will have been called.  */
+
+  static bool
+  initialize_all ()
+  {
+    /* The initialize_all function should only be called once.  The
+       following check reverses the global list, which will effect this
+       initialize_all call, as well as the later finalize_all call.
+
+       The environment variable checked here is the same as the one checked
+       in the generated init.c file.  */
+    if (getenv ("GDB_REVERSE_INIT_FUNCTIONS") != nullptr)
+      std::reverse (callbacks ().begin (), callbacks ().end ());
+
+    for (const auto &p : gdbpy_initialize_file::callbacks ())
+      {
+       if (p.first != nullptr && p.first () < 0)
+         return false;
+      }
+    return true;
+  }
+
+  /* Run all the Python file finalize functions.  */
+
+  static void
+  finalize_all ()
+  {
+    for (const auto &p : gdbpy_initialize_file::callbacks ())
+      {
+       if (p.second != nullptr)
+         p.second ();
+      }
+  }
+};
+
+/* Macro to simplify registering the initialization and finalization
+   functions for a Python file.  */
+
+#define GDBPY_INITIALIZE_FILE(INIT, ...)                               \
+  static gdbpy_initialize_file                                         \
+    CONCAT(gdbpy_initialize_file_obj_, __LINE__) (INIT, ##__VA_ARGS__)
 
 PyMODINIT_FUNC gdbpy_events_mod_func ();
 
index 168a0009f1b2ab6c1cdbe87ee9eb4d7e0df7520b..fd5a920cbdbf296d36a764be69b56b16c0917f28 100644 (file)
@@ -1955,8 +1955,8 @@ finalize_python (void *ignore)
   (void) PyGILState_Ensure ();
   gdbpy_enter::finalize ();
 
-  gdbpy_finalize_micommands ();
-  gdbpy_finalize_tui ();
+  /* Call the gdbpy_finalize_* functions from every *.c file.  */
+  gdbpy_initialize_file::finalize_all ();
 
   Py_Finalize ();
 
@@ -2144,41 +2144,8 @@ init_done:
                                 gdbpy_gdberror_exc) < 0)
     return false;
 
-  gdbpy_initialize_gdb_readline ();
-
-  if (gdbpy_initialize_auto_load () < 0
-      || gdbpy_initialize_values () < 0
-      || gdbpy_initialize_disasm () < 0
-      || gdbpy_initialize_frames () < 0
-      || gdbpy_initialize_commands () < 0
-      || gdbpy_initialize_instruction () < 0
-      || gdbpy_initialize_record () < 0
-      || gdbpy_initialize_btrace () < 0
-      || gdbpy_initialize_symbols () < 0
-      || gdbpy_initialize_symtabs () < 0
-      || gdbpy_initialize_blocks () < 0
-      || gdbpy_initialize_functions () < 0
-      || gdbpy_initialize_parameters () < 0
-      || gdbpy_initialize_types () < 0
-      || gdbpy_initialize_pspace () < 0
-      || gdbpy_initialize_objfile () < 0
-      || gdbpy_initialize_breakpoints () < 0
-      || gdbpy_initialize_breakpoint_locations () < 0
-      || gdbpy_initialize_finishbreakpoints () < 0
-      || gdbpy_initialize_lazy_string () < 0
-      || gdbpy_initialize_linetable () < 0
-      || gdbpy_initialize_thread () < 0
-      || gdbpy_initialize_inferior () < 0
-      || gdbpy_initialize_eventregistry () < 0
-      || gdbpy_initialize_event () < 0
-      || gdbpy_initialize_arch () < 0
-      || gdbpy_initialize_registers () < 0
-      || gdbpy_initialize_xmethods () < 0
-      || gdbpy_initialize_unwind () < 0
-      || gdbpy_initialize_membuf () < 0
-      || gdbpy_initialize_connection () < 0
-      || gdbpy_initialize_tui () < 0
-      || gdbpy_initialize_micommands () < 0)
+  /* Call the gdbpy_initialize_* functions from every *.c file.  */
+  if (!gdbpy_initialize_file::initialize_all ())
     return false;
 
 #define GDB_PY_DEFINE_EVENT_TYPE(name, py_name, doc, base)     \