gdb/python: add mechanism to manage Python initialization functions

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.
This commit is contained in:
Andrew Burgess 2022-09-16 16:08:17 +01:00
parent a5d3f94c27
commit 3965bff5b9
35 changed files with 254 additions and 158 deletions

View file

@ -344,7 +344,7 @@ gdbpy_all_architecture_names (PyObject *self, PyObject *args)
/* Initializes the Architecture class in the gdb module. */ /* Initializes the Architecture class in the gdb module. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_arch (void) gdbpy_initialize_arch (void)
{ {
arch_object_type.tp_new = PyType_GenericNew; arch_object_type.tp_new = PyType_GenericNew;
@ -355,6 +355,10 @@ gdbpy_initialize_arch (void)
(PyObject *) &arch_object_type); (PyObject *) &arch_object_type);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_arch);
static PyMethodDef arch_object_methods [] = { static PyMethodDef arch_object_methods [] = {
{ "name", archpy_name, METH_NOARGS, { "name", archpy_name, METH_NOARGS,
"name () -> String.\n\ "name () -> String.\n\

View 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); auto_load_info_scripts (pattern, from_tty, &extension_language_python);
} }
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_auto_load (void) gdbpy_initialize_auto_load (void)
{ {
add_setshow_boolean_cmd ("python-scripts", class_support, add_setshow_boolean_cmd ("python-scripts", class_support,
@ -95,3 +95,5 @@ Print the list of automatically loaded Python scripts, deprecated."));
return 0; return 0;
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_auto_load);

View file

@ -418,7 +418,7 @@ blpy_iter_is_valid (PyObject *self, PyObject *args)
Py_RETURN_TRUE; Py_RETURN_TRUE;
} }
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_blocks (void) gdbpy_initialize_blocks (void)
{ {
block_object_type.tp_new = PyType_GenericNew; block_object_type.tp_new = PyType_GenericNew;
@ -437,6 +437,8 @@ gdbpy_initialize_blocks (void)
(PyObject *) &block_syms_iterator_object_type); (PyObject *) &block_syms_iterator_object_type);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_blocks);
static PyMethodDef block_object_methods[] = { static PyMethodDef block_object_methods[] = {

View file

@ -1246,7 +1246,7 @@ gdbpy_breakpoint_modified (struct breakpoint *b)
/* Initialize the Python breakpoint code. */ /* Initialize the Python breakpoint code. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_breakpoints (void) gdbpy_initialize_breakpoints (void)
{ {
int i; int i;
@ -1286,7 +1286,7 @@ gdbpy_initialize_breakpoints (void)
/* Initialize the Python BreakpointLocation code. */ /* Initialize the Python BreakpointLocation code. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_breakpoint_locations () gdbpy_initialize_breakpoint_locations ()
{ {
if (PyType_Ready (&breakpoint_location_object_type) < 0) if (PyType_Ready (&breakpoint_location_object_type) < 0)
@ -1450,6 +1450,9 @@ _initialize_py_breakpoint ()
&setdebuglist, &showdebuglist); &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. */ /* Python function to set the enabled state of a breakpoint location. */
static int static int

View file

@ -551,7 +551,7 @@ cmdpy_init (PyObject *self, PyObject *args, PyObject *kw)
/* Initialize the 'commands' code. */ /* Initialize the 'commands' code. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_commands (void) gdbpy_initialize_commands (void)
{ {
int i; int i;
@ -601,6 +601,8 @@ gdbpy_initialize_commands (void)
return 0; return 0;
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_commands);
static PyMethodDef cmdpy_object_methods[] = static PyMethodDef cmdpy_object_methods[] =

View file

@ -285,7 +285,7 @@ connpy_get_connection_details (PyObject *self, void *closure)
/* Python specific initialization for this file. */ /* Python specific initialization for this file. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_connection (void) gdbpy_initialize_connection (void)
{ {
if (PyType_Ready (&connection_object_type) < 0) if (PyType_Ready (&connection_object_type) < 0)
@ -447,6 +447,8 @@ _initialize_py_connection ()
"py-connection"); "py-connection");
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_connection);
/* Methods for the gdb.TargetConnection object type. */ /* Methods for the gdb.TargetConnection object type. */
static PyMethodDef connection_object_methods[] = static PyMethodDef connection_object_methods[] =

View file

@ -1019,7 +1019,7 @@ static struct PyModuleDef python_disassembler_module_def =
/* Called to initialize the Python structures in this file. */ /* Called to initialize the Python structures in this file. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_disasm () gdbpy_initialize_disasm ()
{ {
/* Create the _gdb.disassembler module, and add it to the _gdb module. */ /* Create the _gdb.disassembler module, and add it to the _gdb module. */
@ -1053,6 +1053,10 @@ gdbpy_initialize_disasm ()
return 0; return 0;
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_disasm);
/* Describe the gdb.disassembler.DisassembleInfo type. */ /* Describe the gdb.disassembler.DisassembleInfo type. */
PyTypeObject disasm_info_object_type = { PyTypeObject disasm_info_object_type = {

View file

@ -54,7 +54,7 @@ evpy_add_attribute (PyObject *event, const char *name, PyObject *attr)
/* Initialize the Python event code. */ /* Initialize the Python event code. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_event (void) gdbpy_initialize_event (void)
{ {
return gdbpy_initialize_event_generic (&event_object_type, return gdbpy_initialize_event_generic (&event_object_type,
@ -114,6 +114,8 @@ evpy_emit_event (PyObject *event,
return 0; return 0;
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_event);
static gdb_PyGetSetDef event_object_getset[] = static gdb_PyGetSetDef event_object_getset[] =
{ {
{ "__dict__", gdb_py_generic_dict, NULL, { "__dict__", gdb_py_generic_dict, NULL,

View file

@ -102,7 +102,7 @@ evregpy_dealloc (PyObject *self)
/* Initialize the Python event registry code. */ /* Initialize the Python event registry code. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_eventregistry (void) gdbpy_initialize_eventregistry (void)
{ {
if (PyType_Ready (&eventregistry_object_type) < 0) 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; return registry == nullptr || PyList_Size (registry->callbacks) == 0;
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_eventregistry);
static PyMethodDef eventregistry_object_methods[] = static PyMethodDef eventregistry_object_methods[] =
{ {
{ "connect", evregpy_connect, METH_VARARGS, "Add function" }, { "connect", evregpy_connect, METH_VARARGS, "Add function" },

View file

@ -435,7 +435,7 @@ bpfinishpy_handle_exit (struct inferior *inf)
/* Initialize the Python finish breakpoint code. */ /* Initialize the Python finish breakpoint code. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_finishbreakpoints (void) gdbpy_initialize_finishbreakpoints (void)
{ {
if (!gdbpy_breakpoint_init_breakpoint_type ()) if (!gdbpy_breakpoint_init_breakpoint_type ())
@ -456,6 +456,10 @@ gdbpy_initialize_finishbreakpoints (void)
return 0; return 0;
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_finishbreakpoints);
static gdb_PyGetSetDef finish_breakpoint_object_getset[] = { static gdb_PyGetSetDef finish_breakpoint_object_getset[] = {
{ "return_value", bpfinishpy_get_returnvalue, NULL, { "return_value", bpfinishpy_get_returnvalue, NULL,
"gdb.Value object representing the return value, if any. \ "gdb.Value object representing the return value, if any. \

View file

@ -717,7 +717,7 @@ frapy_richcompare (PyObject *self, PyObject *other, int op)
/* Sets up the Frame API in the gdb module. */ /* Sets up the Frame API in the gdb module. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_frames (void) gdbpy_initialize_frames (void)
{ {
frame_object_type.tp_new = PyType_GenericNew; frame_object_type.tp_new = PyType_GenericNew;
@ -749,6 +749,8 @@ gdbpy_initialize_frames (void)
(PyObject *) &frame_object_type); (PyObject *) &frame_object_type);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_frames);
static PyMethodDef frame_object_methods[] = { static PyMethodDef frame_object_methods[] = {

View file

@ -134,7 +134,7 @@ fnpy_init (PyObject *self, PyObject *args, PyObject *kwds)
/* Initialize internal function support. */ /* Initialize internal function support. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_functions (void) gdbpy_initialize_functions (void)
{ {
fnpy_object_type.tp_new = PyType_GenericNew; fnpy_object_type.tp_new = PyType_GenericNew;
@ -145,6 +145,8 @@ gdbpy_initialize_functions (void)
(PyObject *) &fnpy_object_type); (PyObject *) &fnpy_object_type);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_functions);
PyTypeObject fnpy_object_type = PyTypeObject fnpy_object_type =

View file

@ -90,7 +90,7 @@ gdbpy_readline_wrapper (FILE *sys_stdin, FILE *sys_stdout,
/* Initialize Python readline support. */ /* Initialize Python readline support. */
void static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_gdb_readline (void) gdbpy_initialize_gdb_readline (void)
{ {
/* Python's readline module conflicts with GDB's use of readline /* Python's readline module conflicts with GDB's use of readline
@ -114,5 +114,8 @@ class GdbRemoveReadlineFinder:\n\
sys.meta_path.append(GdbRemoveReadlineFinder())\n\ sys.meta_path.append(GdbRemoveReadlineFinder())\n\
") == 0) ") == 0)
PyOS_ReadlineFunctionPointer = gdbpy_readline_wrapper; PyOS_ReadlineFunctionPointer = gdbpy_readline_wrapper;
return 0;
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_gdb_readline);

View file

@ -802,7 +802,7 @@ gdbpy_selected_inferior (PyObject *self, PyObject *args)
inferior_to_inferior_object (current_inferior ()).release ()); inferior_to_inferior_object (current_inferior ()).release ());
} }
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_inferior (void) gdbpy_initialize_inferior (void)
{ {
if (PyType_Ready (&inferior_object_type) < 0) if (PyType_Ready (&inferior_object_type) < 0)
@ -838,6 +838,10 @@ gdbpy_initialize_inferior (void)
return 0; return 0;
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_inferior);
static gdb_PyGetSetDef inferior_object_getset[] = static gdb_PyGetSetDef inferior_object_getset[] =
{ {
{ "num", infpy_get_num, NULL, "ID of inferior, as assigned by GDB.", NULL }, { "num", infpy_get_num, NULL, "ID of inferior, as assigned by GDB.", NULL },

View file

@ -361,7 +361,7 @@ gdbpy_selected_thread (PyObject *self, PyObject *args)
Py_RETURN_NONE; Py_RETURN_NONE;
} }
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_thread (void) gdbpy_initialize_thread (void)
{ {
if (PyType_Ready (&thread_object_type) < 0) if (PyType_Ready (&thread_object_type) < 0)
@ -371,6 +371,10 @@ gdbpy_initialize_thread (void)
(PyObject *) &thread_object_type); (PyObject *) &thread_object_type);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_thread);
static gdb_PyGetSetDef thread_object_getset[] = static gdb_PyGetSetDef thread_object_getset[] =
{ {
{ "name", thpy_get_name, thpy_set_name, { "name", thpy_get_name, thpy_set_name,

View file

@ -81,10 +81,12 @@ py_insn_get_insn_type ()
/* Sets up the gdb.Instruction type. */ /* Sets up the gdb.Instruction type. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_instruction (void) gdbpy_initialize_instruction (void)
{ {
if (py_insn_get_insn_type () == nullptr) if (py_insn_get_insn_type () == nullptr)
return -1; return -1;
return 0; return 0;
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_instruction);

View file

@ -234,7 +234,7 @@ gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
return (PyObject *) str_obj; return (PyObject *) str_obj;
} }
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_lazy_string (void) gdbpy_initialize_lazy_string (void)
{ {
if (PyType_Ready (&lazy_string_object_type) < 0) 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); encoding->reset (lazy->encoding ? xstrdup (lazy->encoding) : NULL);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_lazy_string);
static PyMethodDef lazy_string_object_methods[] = { static PyMethodDef lazy_string_object_methods[] = {

View file

@ -285,7 +285,7 @@ ltpy_dealloc (PyObject *self)
/* Initialize LineTable, LineTableEntry and LineTableIterator /* Initialize LineTable, LineTableEntry and LineTableIterator
objects. */ objects. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_linetable (void) gdbpy_initialize_linetable (void)
{ {
if (PyType_Ready (&linetable_object_type) < 0) if (PyType_Ready (&linetable_object_type) < 0)
@ -446,6 +446,8 @@ ltpy_iter_is_valid (PyObject *self, PyObject *args)
Py_RETURN_TRUE; Py_RETURN_TRUE;
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_linetable);
static PyMethodDef linetable_object_methods[] = { static PyMethodDef linetable_object_methods[] = {

View file

@ -99,7 +99,7 @@ get_buffer (PyObject *self, Py_buffer *buf, int flags)
/* General Python initialization callback. */ /* General Python initialization callback. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_membuf (void) gdbpy_initialize_membuf (void)
{ {
membuf_object_type.tp_new = PyType_GenericNew; membuf_object_type.tp_new = PyType_GenericNew;
@ -110,6 +110,10 @@ gdbpy_initialize_membuf (void)
(PyObject *) &membuf_object_type); (PyObject *) &membuf_object_type);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_membuf);
static PyBufferProcs buffer_procs = static PyBufferProcs buffer_procs =
{ {
get_buffer get_buffer

View file

@ -595,7 +595,7 @@ micmdpy_dealloc (PyObject *obj)
/* Python initialization for the MI commands components. */ /* Python initialization for the MI commands components. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_micommands () gdbpy_initialize_micommands ()
{ {
micmdpy_object_type.tp_new = PyType_GenericNew; micmdpy_object_type.tp_new = PyType_GenericNew;
@ -614,7 +614,9 @@ gdbpy_initialize_micommands ()
return 0; return 0;
} }
void /* Cleanup just before GDB shuts down the Python interpreter. */
static void
gdbpy_finalize_micommands () gdbpy_finalize_micommands ()
{ {
/* mi_command_py objects hold references to micmdpy_object objects. They must /* mi_command_py objects hold references to micmdpy_object objects. They must
@ -737,3 +739,5 @@ _initialize_py_micmd ()
show_pymicmd_debug, show_pymicmd_debug,
&setdebuglist, &showdebuglist); &setdebuglist, &showdebuglist);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_micommands, gdbpy_finalize_micommands);

View file

@ -704,7 +704,7 @@ objfile_to_objfile_object (struct objfile *objfile)
return gdbpy_ref<>::new_reference (result); return gdbpy_ref<>::new_reference (result);
} }
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_objfile (void) gdbpy_initialize_objfile (void)
{ {
if (PyType_Ready (&objfile_object_type) < 0) if (PyType_Ready (&objfile_object_type) < 0)
@ -714,6 +714,8 @@ gdbpy_initialize_objfile (void)
(PyObject *) &objfile_object_type); (PyObject *) &objfile_object_type);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_objfile);
static PyMethodDef objfile_object_methods[] = static PyMethodDef objfile_object_methods[] =

View file

@ -906,7 +906,7 @@ parmpy_dealloc (PyObject *obj)
} }
/* Initialize the 'parameters' module. */ /* Initialize the 'parameters' module. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_parameters (void) gdbpy_initialize_parameters (void)
{ {
int i; int i;
@ -934,6 +934,8 @@ gdbpy_initialize_parameters (void)
(PyObject *) &parmpy_object_type); (PyObject *) &parmpy_object_type);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_parameters);
PyTypeObject parmpy_object_type = PyTypeObject parmpy_object_type =

View file

@ -529,7 +529,7 @@ gdbpy_is_progspace (PyObject *obj)
return PyObject_TypeCheck (obj, &pspace_object_type); return PyObject_TypeCheck (obj, &pspace_object_type);
} }
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_pspace (void) gdbpy_initialize_pspace (void)
{ {
if (PyType_Ready (&pspace_object_type) < 0) if (PyType_Ready (&pspace_object_type) < 0)
@ -539,6 +539,8 @@ gdbpy_initialize_pspace (void)
(PyObject *) &pspace_object_type); (PyObject *) &pspace_object_type);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_pspace);
static gdb_PyGetSetDef pspace_getset[] = static gdb_PyGetSetDef pspace_getset[] =

View file

@ -816,7 +816,7 @@ static PyMappingMethods btpy_list_mapping_methods =
/* Sets up the btrace record API. */ /* Sets up the btrace record API. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_btrace (void) gdbpy_initialize_btrace (void)
{ {
btpy_list_type.tp_new = PyType_GenericNew; btpy_list_type.tp_new = PyType_GenericNew;
@ -837,3 +837,5 @@ gdbpy_initialize_btrace (void)
return PyType_Ready (&btpy_list_type); return PyType_Ready (&btpy_list_type);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_btrace);

View file

@ -544,7 +544,7 @@ static gdb_PyGetSetDef recpy_gap_getset[] = {
/* Sets up the record API in the gdb module. */ /* Sets up the record API in the gdb module. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_record (void) gdbpy_initialize_record (void)
{ {
recpy_record_type.tp_new = PyType_GenericNew; recpy_record_type.tp_new = PyType_GenericNew;
@ -648,3 +648,5 @@ gdbpy_stop_recording (PyObject *self, PyObject *args)
Py_RETURN_NONE; Py_RETURN_NONE;
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_record);

View 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. */ /* Initializes the new Python classes from this file in the gdb module. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_registers () gdbpy_initialize_registers ()
{ {
register_descriptor_object_type.tp_new = PyType_GenericNew; register_descriptor_object_type.tp_new = PyType_GenericNew;
@ -462,6 +462,10 @@ gdbpy_initialize_registers ()
(PyObject *) &register_descriptor_iterator_object_type)); (PyObject *) &register_descriptor_iterator_object_type));
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_registers);
static PyMethodDef register_descriptor_iterator_object_methods [] = { static PyMethodDef register_descriptor_iterator_object_methods [] = {
{ "find", (PyCFunction) register_descriptor_iter_find, { "find", (PyCFunction) register_descriptor_iter_find,
METH_VARARGS | METH_KEYWORDS, METH_VARARGS | METH_KEYWORDS,

View file

@ -618,7 +618,7 @@ gdbpy_lookup_static_symbols (PyObject *self, PyObject *args, PyObject *kw)
return return_list.release (); return return_list.release ();
} }
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_symbols (void) gdbpy_initialize_symbols (void)
{ {
if (PyType_Ready (&symbol_object_type) < 0) if (PyType_Ready (&symbol_object_type) < 0)
@ -687,6 +687,8 @@ gdbpy_initialize_symbols (void)
(PyObject *) &symbol_object_type); (PyObject *) &symbol_object_type);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_symbols);
static gdb_PyGetSetDef symbol_object_getset[] = { static gdb_PyGetSetDef symbol_object_getset[] = {

View file

@ -509,7 +509,7 @@ symtab_object_to_symtab (PyObject *obj)
return ((symtab_object *) obj)->symtab; return ((symtab_object *) obj)->symtab;
} }
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_symtabs (void) gdbpy_initialize_symtabs (void)
{ {
symtab_object_type.tp_new = PyType_GenericNew; symtab_object_type.tp_new = PyType_GenericNew;
@ -528,6 +528,8 @@ gdbpy_initialize_symtabs (void)
(PyObject *) &sal_object_type); (PyObject *) &sal_object_type);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_symtabs);
static gdb_PyGetSetDef symtab_object_getset[] = { static gdb_PyGetSetDef symtab_object_getset[] = {

View file

@ -601,7 +601,7 @@ PyTypeObject gdbpy_tui_window_object_type =
/* Initialize this module. */ /* Initialize this module. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_tui () gdbpy_initialize_tui ()
{ {
#ifdef TUI #ifdef TUI
@ -615,10 +615,12 @@ gdbpy_initialize_tui ()
/* Finalize this module. */ /* Finalize this module. */
void static void
gdbpy_finalize_tui () gdbpy_finalize_tui ()
{ {
#ifdef TUI #ifdef TUI
gdbpy_tui_window_maker::invalidate_all (); gdbpy_tui_window_maker::invalidate_all ();
#endif /* TUI */ #endif /* TUI */
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_tui, gdbpy_finalize_tui);

View file

@ -1445,7 +1445,7 @@ gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw)
return type_to_type_object (type); return type_to_type_object (type);
} }
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_types (void) gdbpy_initialize_types (void)
{ {
if (PyType_Ready (&type_object_type) < 0) if (PyType_Ready (&type_object_type) < 0)
@ -1473,6 +1473,8 @@ gdbpy_initialize_types (void)
(PyObject *) &field_object_type); (PyObject *) &field_object_type);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_types);
static gdb_PyGetSetDef type_object_getset[] = static gdb_PyGetSetDef type_object_getset[] =

View 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. */ /* Initialize unwind machinery. */
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_unwind (void) gdbpy_initialize_unwind (void)
{ {
gdb::observers::architecture_changed.attach (pyuw_on_new_gdbarch, gdb::observers::architecture_changed.attach (pyuw_on_new_gdbarch,
@ -1004,6 +990,24 @@ gdbpy_initialize_unwind (void)
(PyObject *) &unwind_info_object_type); (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);
static PyMethodDef pending_frame_object_methods[] = static PyMethodDef pending_frame_object_methods[] =
{ {
{ "read_register", (PyCFunction) pending_framepy_read_register, { "read_register", (PyCFunction) pending_framepy_read_register,

View file

@ -2056,7 +2056,7 @@ gdbpy_is_value_object (PyObject *obj)
return PyObject_TypeCheck (obj, &value_object_type); return PyObject_TypeCheck (obj, &value_object_type);
} }
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_values (void) gdbpy_initialize_values (void)
{ {
if (PyType_Ready (&value_object_type) < 0) if (PyType_Ready (&value_object_type) < 0)
@ -2066,6 +2066,8 @@ gdbpy_initialize_values (void)
(PyObject *) &value_object_type); (PyObject *) &value_object_type);
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_values);
static gdb_PyGetSetDef value_object_getset[] = { static gdb_PyGetSetDef value_object_getset[] = {

View file

@ -599,7 +599,7 @@ python_xmethod_worker::python_xmethod_worker (PyObject *py_worker,
Py_INCREF (this_type); Py_INCREF (this_type);
} }
int static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
gdbpy_initialize_xmethods (void) gdbpy_initialize_xmethods (void)
{ {
py_match_method_name = PyUnicode_FromString (match_method_name); py_match_method_name = PyUnicode_FromString (match_method_name);
@ -613,3 +613,5 @@ gdbpy_initialize_xmethods (void)
return 1; return 1;
} }
GDBPY_INITIALIZE_FILE (gdbpy_initialize_xmethods);

View file

@ -488,77 +488,120 @@ struct gdbarch *arch_object_to_gdbarch (PyObject *obj);
extern struct program_space *progspace_object_to_program_space (PyObject *obj); extern struct program_space *progspace_object_to_program_space (PyObject *obj);
void gdbpy_initialize_gdb_readline (void); /* A class for managing the initialization, and finalization functions
int gdbpy_initialize_auto_load (void) from all Python files (e.g. gdb/python/py-*.c).
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
int gdbpy_initialize_values (void) Within any Python file, create an instance of this class, passing in
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; the initialization function, and, optionally, the finalization
int gdbpy_initialize_frames (void) function.
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
int gdbpy_initialize_instruction (void) These functions are added to a single global list of functions, which
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; can then be called from do_start_initialization and finalize_python
int gdbpy_initialize_btrace (void) (see python.c) to initialize all the Python files within GDB. */
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
int gdbpy_initialize_record (void) class gdbpy_initialize_file
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; {
int gdbpy_initialize_symtabs (void) /* The type of a function that can be called just after GDB has setup the
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; Python interpreter. This function will setup any additional Python
int gdbpy_initialize_commands (void) state required by a particular subsystem. Return 0 if the setup was
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; successful, or return -1 if setup failed, in which case a Python
int gdbpy_initialize_symbols (void) exception should have been raised. */
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
int gdbpy_initialize_symtabs (void) using gdbpy_initialize_file_ftype = int (*) (void);
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
int gdbpy_initialize_blocks (void) /* The type of a function that can be called just before GDB shuts down
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; the Python interpreter. This function can cleanup an Python state
int gdbpy_initialize_types (void) that is cached within GDB, for example, if GDB is holding any
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; references to Python objects, these should be released before the
int gdbpy_initialize_functions (void) Python interpreter is shut down.
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
int gdbpy_initialize_pspace (void) There is no error return in this case. This function is only called
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; when GDB is already shutting down. The function should make a best
int gdbpy_initialize_objfile (void) effort to clean up, and then return. */
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
int gdbpy_initialize_breakpoints (void) using gdbpy_finalize_file_ftype = void (*) (void);
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
int gdbpy_initialize_breakpoint_locations () /* The type for an initialization and finalization function pair. */
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
int gdbpy_initialize_finishbreakpoints (void) using callback_pair_t = std::pair<gdbpy_initialize_file_ftype,
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; gdbpy_finalize_file_ftype>;
int gdbpy_initialize_lazy_string (void)
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; /* Return the vector of callbacks. The vector is defined as a static
int gdbpy_initialize_linetable (void) variable within this function so that it will be initialized the first
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; time this function is called. This is important, as this function is
int gdbpy_initialize_parameters (void) called as part of the global object initialization process; if the
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; vector was a static variable within this class then we could not
int gdbpy_initialize_thread (void) guarantee that it had been initialized before it was used. */
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
int gdbpy_initialize_inferior (void) static std::vector<callback_pair_t> &
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; callbacks ()
int gdbpy_initialize_eventregistry (void) {
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; static std::vector<callback_pair_t> list;
int gdbpy_initialize_event (void) return list;
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; }
int gdbpy_initialize_arch (void)
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; public:
int gdbpy_initialize_registers ()
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; /* Register the initialization (INIT) and finalization (FINI) functions
int gdbpy_initialize_xmethods (void) for a Python file. See the comments on the function types above for
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; when these functions will be called.
int gdbpy_initialize_unwind (void)
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; Either of these functions can be nullptr, in which case no function
int gdbpy_initialize_tui () will be called.
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
void gdbpy_finalize_tui (); The FINI argument is optional, and defaults to nullptr (no function to
int gdbpy_initialize_membuf () call). */
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
int gdbpy_initialize_connection () gdbpy_initialize_file (gdbpy_initialize_file_ftype init,
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; gdbpy_finalize_file_ftype fini = nullptr)
int gdbpy_initialize_micommands (void) {
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; callbacks ().emplace_back (init, fini);
void gdbpy_finalize_micommands (); }
int gdbpy_initialize_disasm ()
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION; /* 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 (); PyMODINIT_FUNC gdbpy_events_mod_func ();

View file

@ -1955,8 +1955,8 @@ finalize_python (void *ignore)
(void) PyGILState_Ensure (); (void) PyGILState_Ensure ();
gdbpy_enter::finalize (); gdbpy_enter::finalize ();
gdbpy_finalize_micommands (); /* Call the gdbpy_finalize_* functions from every *.c file. */
gdbpy_finalize_tui (); gdbpy_initialize_file::finalize_all ();
Py_Finalize (); Py_Finalize ();
@ -2144,41 +2144,8 @@ init_done:
gdbpy_gdberror_exc) < 0) gdbpy_gdberror_exc) < 0)
return false; return false;
gdbpy_initialize_gdb_readline (); /* Call the gdbpy_initialize_* functions from every *.c file. */
if (!gdbpy_initialize_file::initialize_all ())
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)
return false; return false;
#define GDB_PY_DEFINE_EVENT_TYPE(name, py_name, doc, base) \ #define GDB_PY_DEFINE_EVENT_TYPE(name, py_name, doc, base) \