|  | /* Python interface to program spaces. | 
|  |  | 
|  | Copyright (C) 2010-2024 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | #include "python-internal.h" | 
|  | #include "charset.h" | 
|  | #include "progspace.h" | 
|  | #include "objfiles.h" | 
|  | #include "language.h" | 
|  | #include "arch-utils.h" | 
|  | #include "solib.h" | 
|  | #include "block.h" | 
|  | #include "py-event.h" | 
|  | #include "observable.h" | 
|  | #include "inferior.h" | 
|  |  | 
|  | struct pspace_object | 
|  | { | 
|  | PyObject_HEAD | 
|  |  | 
|  | /* The corresponding pspace.  */ | 
|  | struct program_space *pspace; | 
|  |  | 
|  | /* Dictionary holding user-added attributes. | 
|  | This is the __dict__ attribute of the object.  */ | 
|  | PyObject *dict; | 
|  |  | 
|  | /* The pretty-printer list of functions.  */ | 
|  | PyObject *printers; | 
|  |  | 
|  | /* The frame filter list of functions.  */ | 
|  | PyObject *frame_filters; | 
|  |  | 
|  | /* The frame unwinder list.  */ | 
|  | PyObject *frame_unwinders; | 
|  |  | 
|  | /* The type-printer list.  */ | 
|  | PyObject *type_printers; | 
|  |  | 
|  | /* The debug method list.  */ | 
|  | PyObject *xmethods; | 
|  |  | 
|  | /* The missing debug handler list.  */ | 
|  | PyObject *missing_debug_handlers; | 
|  | }; | 
|  |  | 
|  | extern PyTypeObject pspace_object_type | 
|  | CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("pspace_object"); | 
|  |  | 
|  | /* Clear the PSPACE pointer in a Pspace object and remove the reference.  */ | 
|  | struct pspace_deleter | 
|  | { | 
|  | void operator() (pspace_object *obj) | 
|  | { | 
|  | /* This is a fiction, but we're in a nasty spot: The pspace is in the | 
|  | process of being deleted, we can't rely on anything in it.  Plus | 
|  | this is one time when the current program space and current inferior | 
|  | are not in sync: All inferiors that use PSPACE may no longer exist. | 
|  | We don't need to do much here, and since "there is always an inferior" | 
|  | using the current inferior's arch suffices. | 
|  | Note: We cannot call get_current_arch because it may try to access | 
|  | the target, which may involve accessing data in the pspace currently | 
|  | being deleted.  */ | 
|  | gdbarch *arch = current_inferior ()->arch (); | 
|  |  | 
|  | gdbpy_enter enter_py (arch); | 
|  | gdbpy_ref<pspace_object> object (obj); | 
|  | object->pspace = NULL; | 
|  | } | 
|  | }; | 
|  |  | 
|  | static const registry<program_space>::key<pspace_object, pspace_deleter> | 
|  | pspy_pspace_data_key; | 
|  |  | 
|  | /* Require that PSPACE_OBJ be a valid program space ID.  */ | 
|  | #define PSPY_REQUIRE_VALID(pspace_obj)				\ | 
|  | do {								\ | 
|  | if (pspace_obj->pspace == nullptr)				\ | 
|  | {								\ | 
|  | PyErr_SetString (PyExc_RuntimeError,			\ | 
|  | _("Program space no longer exists."));	\ | 
|  | return NULL;						\ | 
|  | }								\ | 
|  | } while (0) | 
|  |  | 
|  | /* An Objfile method which returns the objfile's file name, or None.  */ | 
|  |  | 
|  | static PyObject * | 
|  | pspy_get_filename (PyObject *self, void *closure) | 
|  | { | 
|  | pspace_object *obj = (pspace_object *) self; | 
|  |  | 
|  | if (obj->pspace) | 
|  | { | 
|  | struct objfile *objfile = obj->pspace->symfile_object_file; | 
|  |  | 
|  | if (objfile) | 
|  | return (host_string_to_python_string (objfile_name (objfile)) | 
|  | .release ()); | 
|  | } | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | /* Implement the gdb.Progspace.symbol_file attribute.  Retun the | 
|  | gdb.Objfile corresponding to the currently loaded symbol-file, or None | 
|  | if no symbol-file is loaded.  If the Progspace is invalid then raise an | 
|  | exception.  */ | 
|  |  | 
|  | static PyObject * | 
|  | pspy_get_symbol_file (PyObject *self, void *closure) | 
|  | { | 
|  | pspace_object *obj = (pspace_object *) self; | 
|  |  | 
|  | PSPY_REQUIRE_VALID (obj); | 
|  |  | 
|  | struct objfile *objfile = obj->pspace->symfile_object_file; | 
|  |  | 
|  | if (objfile != nullptr) | 
|  | return objfile_to_objfile_object (objfile).release (); | 
|  |  | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | /* Implement the gdb.Progspace.executable_filename attribute.  Retun a | 
|  | string containing the name of the current executable, or None if no | 
|  | executable is currently set.  If the Progspace is invalid then raise an | 
|  | exception.  */ | 
|  |  | 
|  | static PyObject * | 
|  | pspy_get_exec_file (PyObject *self, void *closure) | 
|  | { | 
|  | pspace_object *obj = (pspace_object *) self; | 
|  |  | 
|  | PSPY_REQUIRE_VALID (obj); | 
|  |  | 
|  | const char *filename = obj->pspace->exec_filename (); | 
|  | if (filename != nullptr) | 
|  | return host_string_to_python_string (filename).release (); | 
|  |  | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | static void | 
|  | pspy_dealloc (PyObject *self) | 
|  | { | 
|  | pspace_object *ps_self = (pspace_object *) self; | 
|  |  | 
|  | Py_XDECREF (ps_self->dict); | 
|  | Py_XDECREF (ps_self->printers); | 
|  | Py_XDECREF (ps_self->frame_filters); | 
|  | Py_XDECREF (ps_self->frame_unwinders); | 
|  | Py_XDECREF (ps_self->type_printers); | 
|  | Py_XDECREF (ps_self->xmethods); | 
|  | Py_XDECREF (ps_self->missing_debug_handlers); | 
|  | Py_TYPE (self)->tp_free (self); | 
|  | } | 
|  |  | 
|  | /* Initialize a pspace_object. | 
|  | The result is a boolean indicating success.  */ | 
|  |  | 
|  | static int | 
|  | pspy_initialize (pspace_object *self) | 
|  | { | 
|  | self->pspace = NULL; | 
|  |  | 
|  | self->dict = PyDict_New (); | 
|  | if (self->dict == NULL) | 
|  | return 0; | 
|  |  | 
|  | self->printers = PyList_New (0); | 
|  | if (self->printers == NULL) | 
|  | return 0; | 
|  |  | 
|  | self->frame_filters = PyDict_New (); | 
|  | if (self->frame_filters == NULL) | 
|  | return 0; | 
|  |  | 
|  | self->frame_unwinders = PyList_New (0); | 
|  | if (self->frame_unwinders == NULL) | 
|  | return 0; | 
|  |  | 
|  | self->type_printers = PyList_New (0); | 
|  | if (self->type_printers == NULL) | 
|  | return 0; | 
|  |  | 
|  | self->xmethods = PyList_New (0); | 
|  | if (self->xmethods == NULL) | 
|  | return 0; | 
|  |  | 
|  | self->missing_debug_handlers = PyList_New (0); | 
|  | if (self->missing_debug_handlers == nullptr) | 
|  | return 0; | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | PyObject * | 
|  | pspy_get_printers (PyObject *o, void *ignore) | 
|  | { | 
|  | pspace_object *self = (pspace_object *) o; | 
|  |  | 
|  | Py_INCREF (self->printers); | 
|  | return self->printers; | 
|  | } | 
|  |  | 
|  | static int | 
|  | pspy_set_printers (PyObject *o, PyObject *value, void *ignore) | 
|  | { | 
|  | pspace_object *self = (pspace_object *) o; | 
|  |  | 
|  | if (! value) | 
|  | { | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | "cannot delete the pretty_printers attribute"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (! PyList_Check (value)) | 
|  | { | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | "the pretty_printers attribute must be a list"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Take care in case the LHS and RHS are related somehow.  */ | 
|  | gdbpy_ref<> tmp (self->printers); | 
|  | Py_INCREF (value); | 
|  | self->printers = value; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Return the Python dictionary attribute containing frame filters for | 
|  | this program space.  */ | 
|  | PyObject * | 
|  | pspy_get_frame_filters (PyObject *o, void *ignore) | 
|  | { | 
|  | pspace_object *self = (pspace_object *) o; | 
|  |  | 
|  | Py_INCREF (self->frame_filters); | 
|  | return self->frame_filters; | 
|  | } | 
|  |  | 
|  | /* Set this object file's frame filters dictionary to FILTERS.  */ | 
|  | static int | 
|  | pspy_set_frame_filters (PyObject *o, PyObject *frame, void *ignore) | 
|  | { | 
|  | pspace_object *self = (pspace_object *) o; | 
|  |  | 
|  | if (! frame) | 
|  | { | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | "cannot delete the frame filter attribute"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (! PyDict_Check (frame)) | 
|  | { | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | "the frame filter attribute must be a dictionary"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Take care in case the LHS and RHS are related somehow.  */ | 
|  | gdbpy_ref<> tmp (self->frame_filters); | 
|  | Py_INCREF (frame); | 
|  | self->frame_filters = frame; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Return the list of the frame unwinders for this program space.  */ | 
|  |  | 
|  | PyObject * | 
|  | pspy_get_frame_unwinders (PyObject *o, void *ignore) | 
|  | { | 
|  | pspace_object *self = (pspace_object *) o; | 
|  |  | 
|  | Py_INCREF (self->frame_unwinders); | 
|  | return self->frame_unwinders; | 
|  | } | 
|  |  | 
|  | /* Set this program space's list of the unwinders to UNWINDERS.  */ | 
|  |  | 
|  | static int | 
|  | pspy_set_frame_unwinders (PyObject *o, PyObject *unwinders, void *ignore) | 
|  | { | 
|  | pspace_object *self = (pspace_object *) o; | 
|  |  | 
|  | if (!unwinders) | 
|  | { | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | "cannot delete the frame unwinders list"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (!PyList_Check (unwinders)) | 
|  | { | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | "the frame unwinders attribute must be a list"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Take care in case the LHS and RHS are related somehow.  */ | 
|  | gdbpy_ref<> tmp (self->frame_unwinders); | 
|  | Py_INCREF (unwinders); | 
|  | self->frame_unwinders = unwinders; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Get the 'type_printers' attribute.  */ | 
|  |  | 
|  | static PyObject * | 
|  | pspy_get_type_printers (PyObject *o, void *ignore) | 
|  | { | 
|  | pspace_object *self = (pspace_object *) o; | 
|  |  | 
|  | Py_INCREF (self->type_printers); | 
|  | return self->type_printers; | 
|  | } | 
|  |  | 
|  | /* Get the 'xmethods' attribute.  */ | 
|  |  | 
|  | PyObject * | 
|  | pspy_get_xmethods (PyObject *o, void *ignore) | 
|  | { | 
|  | pspace_object *self = (pspace_object *) o; | 
|  |  | 
|  | Py_INCREF (self->xmethods); | 
|  | return self->xmethods; | 
|  | } | 
|  |  | 
|  | /* Return the list of missing debug handlers for this program space.  */ | 
|  |  | 
|  | static PyObject * | 
|  | pspy_get_missing_debug_handlers (PyObject *o, void *ignore) | 
|  | { | 
|  | pspace_object *self = (pspace_object *) o; | 
|  |  | 
|  | Py_INCREF (self->missing_debug_handlers); | 
|  | return self->missing_debug_handlers; | 
|  | } | 
|  |  | 
|  | /* Set this program space's list of missing debug handlers to HANDLERS.  */ | 
|  |  | 
|  | static int | 
|  | pspy_set_missing_debug_handlers (PyObject *o, PyObject *handlers, | 
|  | void *ignore) | 
|  | { | 
|  | pspace_object *self = (pspace_object *) o; | 
|  |  | 
|  | if (handlers == nullptr) | 
|  | { | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | "cannot delete the missing debug handlers list"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (!PyList_Check (handlers)) | 
|  | { | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | "the missing debug handlers attribute must be a list"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Take care in case the LHS and RHS are related somehow.  */ | 
|  | gdbpy_ref<> tmp (self->missing_debug_handlers); | 
|  | Py_INCREF (handlers); | 
|  | self->missing_debug_handlers = handlers; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Set the 'type_printers' attribute.  */ | 
|  |  | 
|  | static int | 
|  | pspy_set_type_printers (PyObject *o, PyObject *value, void *ignore) | 
|  | { | 
|  | pspace_object *self = (pspace_object *) o; | 
|  |  | 
|  | if (! value) | 
|  | { | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | "cannot delete the type_printers attribute"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (! PyList_Check (value)) | 
|  | { | 
|  | PyErr_SetString (PyExc_TypeError, | 
|  | "the type_printers attribute must be a list"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Take care in case the LHS and RHS are related somehow.  */ | 
|  | gdbpy_ref<> tmp (self->type_printers); | 
|  | Py_INCREF (value); | 
|  | self->type_printers = value; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Implement the objfiles method.  */ | 
|  |  | 
|  | static PyObject * | 
|  | pspy_get_objfiles (PyObject *self_, PyObject *args) | 
|  | { | 
|  | pspace_object *self = (pspace_object *) self_; | 
|  |  | 
|  | PSPY_REQUIRE_VALID (self); | 
|  |  | 
|  | gdbpy_ref<> list (PyList_New (0)); | 
|  | if (list == NULL) | 
|  | return NULL; | 
|  |  | 
|  | if (self->pspace != NULL) | 
|  | { | 
|  | for (objfile *objf : self->pspace->objfiles ()) | 
|  | { | 
|  | gdbpy_ref<> item = objfile_to_objfile_object (objf); | 
|  |  | 
|  | if (item == nullptr | 
|  | || PyList_Append (list.get (), item.get ()) == -1) | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | return list.release (); | 
|  | } | 
|  |  | 
|  | /* Implementation of solib_name (Long) -> String. | 
|  | Returns the name of the shared library holding a given address, or None.  */ | 
|  |  | 
|  | static PyObject * | 
|  | pspy_solib_name (PyObject *o, PyObject *args) | 
|  | { | 
|  | CORE_ADDR pc; | 
|  | PyObject *pc_obj; | 
|  |  | 
|  | pspace_object *self = (pspace_object *) o; | 
|  |  | 
|  | PSPY_REQUIRE_VALID (self); | 
|  |  | 
|  | if (!PyArg_ParseTuple (args, "O", &pc_obj)) | 
|  | return NULL; | 
|  | if (get_addr_from_python (pc_obj, &pc) < 0) | 
|  | return nullptr; | 
|  |  | 
|  | const char *soname = solib_name_from_address (self->pspace, pc); | 
|  | if (soname == nullptr) | 
|  | Py_RETURN_NONE; | 
|  | return host_string_to_python_string (soname).release (); | 
|  | } | 
|  |  | 
|  | /* Implement objfile_for_address.  */ | 
|  |  | 
|  | static PyObject * | 
|  | pspy_objfile_for_address (PyObject *o, PyObject *args) | 
|  | { | 
|  | CORE_ADDR addr; | 
|  | PyObject *addr_obj; | 
|  |  | 
|  | pspace_object *self = (pspace_object *) o; | 
|  |  | 
|  | PSPY_REQUIRE_VALID (self); | 
|  |  | 
|  | if (!PyArg_ParseTuple (args, "O", &addr_obj)) | 
|  | return nullptr; | 
|  | if (get_addr_from_python (addr_obj, &addr) < 0) | 
|  | return nullptr; | 
|  |  | 
|  | struct objfile *objf = self->pspace->objfile_for_address (addr); | 
|  | if (objf == nullptr) | 
|  | Py_RETURN_NONE; | 
|  |  | 
|  | return objfile_to_objfile_object (objf).release (); | 
|  | } | 
|  |  | 
|  | /* Return the innermost lexical block containing the specified pc value, | 
|  | or 0 if there is none.  */ | 
|  | static PyObject * | 
|  | pspy_block_for_pc (PyObject *o, PyObject *args) | 
|  | { | 
|  | pspace_object *self = (pspace_object *) o; | 
|  | CORE_ADDR pc; | 
|  | PyObject *pc_obj; | 
|  | const struct block *block = NULL; | 
|  | struct compunit_symtab *cust = NULL; | 
|  |  | 
|  | PSPY_REQUIRE_VALID (self); | 
|  |  | 
|  | if (!PyArg_ParseTuple (args, "O", &pc_obj)) | 
|  | return NULL; | 
|  | if (get_addr_from_python (pc_obj, &pc) < 0) | 
|  | return nullptr; | 
|  |  | 
|  | try | 
|  | { | 
|  | scoped_restore_current_program_space saver; | 
|  |  | 
|  | set_current_program_space (self->pspace); | 
|  | cust = find_pc_compunit_symtab (pc); | 
|  |  | 
|  | if (cust != NULL && cust->objfile () != NULL) | 
|  | block = block_for_pc (pc); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | if (cust == NULL || cust->objfile () == NULL) | 
|  | Py_RETURN_NONE; | 
|  |  | 
|  | if (block) | 
|  | return block_to_block_object (block, cust->objfile ()); | 
|  |  | 
|  | Py_RETURN_NONE; | 
|  | } | 
|  |  | 
|  | /* Implementation of the find_pc_line function. | 
|  | Returns the gdb.Symtab_and_line object corresponding to a PC value.  */ | 
|  |  | 
|  | static PyObject * | 
|  | pspy_find_pc_line (PyObject *o, PyObject *args) | 
|  | { | 
|  | CORE_ADDR pc; | 
|  | PyObject *result = NULL; /* init for gcc -Wall */ | 
|  | PyObject *pc_obj; | 
|  | pspace_object *self = (pspace_object *) o; | 
|  |  | 
|  | PSPY_REQUIRE_VALID (self); | 
|  |  | 
|  | if (!PyArg_ParseTuple (args, "O", &pc_obj)) | 
|  | return NULL; | 
|  | if (get_addr_from_python (pc_obj, &pc) < 0) | 
|  | return nullptr; | 
|  |  | 
|  | try | 
|  | { | 
|  | struct symtab_and_line sal; | 
|  | scoped_restore_current_program_space saver; | 
|  |  | 
|  | set_current_program_space (self->pspace); | 
|  |  | 
|  | sal = find_pc_line (pc, 0); | 
|  | result = symtab_and_line_to_sal_object (sal); | 
|  | } | 
|  | catch (const gdb_exception &except) | 
|  | { | 
|  | GDB_PY_HANDLE_EXCEPTION (except); | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* Implementation of is_valid (self) -> Boolean. | 
|  | Returns True if this program space still exists in GDB.  */ | 
|  |  | 
|  | static PyObject * | 
|  | pspy_is_valid (PyObject *o, PyObject *args) | 
|  | { | 
|  | pspace_object *self = (pspace_object *) o; | 
|  |  | 
|  | if (self->pspace == NULL) | 
|  | Py_RETURN_FALSE; | 
|  |  | 
|  | Py_RETURN_TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /* Return a new reference to the Python object of type Pspace | 
|  | representing PSPACE.  If the object has already been created, | 
|  | return it.  Otherwise, create it.  Return NULL and set the Python | 
|  | error on failure.  */ | 
|  |  | 
|  | gdbpy_ref<> | 
|  | pspace_to_pspace_object (struct program_space *pspace) | 
|  | { | 
|  | PyObject *result = (PyObject *) pspy_pspace_data_key.get (pspace); | 
|  | if (result == NULL) | 
|  | { | 
|  | gdbpy_ref<pspace_object> object | 
|  | ((pspace_object *) PyObject_New (pspace_object, &pspace_object_type)); | 
|  | if (object == NULL) | 
|  | return NULL; | 
|  | if (!pspy_initialize (object.get ())) | 
|  | return NULL; | 
|  |  | 
|  | object->pspace = pspace; | 
|  | pspy_pspace_data_key.set (pspace, object.get ()); | 
|  | result = (PyObject *) object.release (); | 
|  | } | 
|  |  | 
|  | return gdbpy_ref<>::new_reference (result); | 
|  | } | 
|  |  | 
|  | /* See python-internal.h.  */ | 
|  |  | 
|  | struct program_space * | 
|  | progspace_object_to_program_space (PyObject *obj) | 
|  | { | 
|  | gdb_assert (gdbpy_is_progspace (obj)); | 
|  | return ((pspace_object *) obj)->pspace; | 
|  | } | 
|  |  | 
|  | /* See python-internal.h.  */ | 
|  |  | 
|  | bool | 
|  | gdbpy_is_progspace (PyObject *obj) | 
|  | { | 
|  | return PyObject_TypeCheck (obj, &pspace_object_type); | 
|  | } | 
|  |  | 
|  | /* Emit an ExecutableChangedEvent event to REGISTRY.  Return 0 on success, | 
|  | or a negative value on error.  PSPACE is the program_space in which the | 
|  | current executable has changed, and RELOAD_P is true if the executable | 
|  | path stayed the same, but the file on disk changed, or false if the | 
|  | executable path actually changed.  */ | 
|  |  | 
|  | static int | 
|  | emit_executable_changed_event (eventregistry_object *registry, | 
|  | struct program_space *pspace, bool reload_p) | 
|  | { | 
|  | gdbpy_ref<> event_obj | 
|  | = create_event_object (&executable_changed_event_object_type); | 
|  | if (event_obj == nullptr) | 
|  | return -1; | 
|  |  | 
|  | gdbpy_ref<> py_pspace = pspace_to_pspace_object (pspace); | 
|  | if (py_pspace == nullptr | 
|  | || evpy_add_attribute (event_obj.get (), "progspace", | 
|  | py_pspace.get ()) < 0) | 
|  | return -1; | 
|  |  | 
|  | gdbpy_ref<> py_reload_p (PyBool_FromLong (reload_p ? 1 : 0)); | 
|  | if (py_reload_p == nullptr | 
|  | || evpy_add_attribute (event_obj.get (), "reload", | 
|  | py_reload_p.get ()) < 0) | 
|  | return -1; | 
|  |  | 
|  | return evpy_emit_event (event_obj.get (), registry); | 
|  | } | 
|  |  | 
|  | /* Listener for the executable_changed observable, this is called when the | 
|  | current executable within PSPACE changes.  RELOAD_P is true if the | 
|  | executable path stayed the same but the file changed on disk.  RELOAD_P | 
|  | is false if the executable path was changed.  */ | 
|  |  | 
|  | static void | 
|  | gdbpy_executable_changed (struct program_space *pspace, bool reload_p) | 
|  | { | 
|  | if (!gdb_python_initialized) | 
|  | return; | 
|  |  | 
|  | gdbpy_enter enter_py; | 
|  |  | 
|  | if (!evregpy_no_listeners_p (gdb_py_events.executable_changed)) | 
|  | if (emit_executable_changed_event (gdb_py_events.executable_changed, | 
|  | pspace, reload_p) < 0) | 
|  | gdbpy_print_stack (); | 
|  | } | 
|  |  | 
|  | /* Helper function to emit NewProgspaceEvent (when ADDING_P is true) or | 
|  | FreeProgspaceEvent events (when ADDING_P is false).  */ | 
|  |  | 
|  | static void | 
|  | gdbpy_program_space_event (program_space *pspace, bool adding_p) | 
|  | { | 
|  | if (!gdb_python_initialized) | 
|  | return; | 
|  |  | 
|  | gdbpy_enter enter_py; | 
|  |  | 
|  | eventregistry_object *registry; | 
|  | PyTypeObject *event_type; | 
|  | if (adding_p) | 
|  | { | 
|  | registry = gdb_py_events.new_progspace; | 
|  | event_type = &new_progspace_event_object_type; | 
|  | } | 
|  | else | 
|  | { | 
|  | registry = gdb_py_events.free_progspace; | 
|  | event_type = &free_progspace_event_object_type; | 
|  | } | 
|  |  | 
|  | if (evregpy_no_listeners_p (registry)) | 
|  | return; | 
|  |  | 
|  | gdbpy_ref<> pspace_obj = pspace_to_pspace_object (pspace); | 
|  | if (pspace_obj == nullptr) | 
|  | { | 
|  | gdbpy_print_stack (); | 
|  | return; | 
|  | } | 
|  |  | 
|  | gdbpy_ref<> event = create_event_object (event_type); | 
|  | if (event == nullptr | 
|  | || evpy_add_attribute (event.get (), "progspace", | 
|  | pspace_obj.get ()) < 0 | 
|  | || evpy_emit_event (event.get (), registry) < 0) | 
|  | gdbpy_print_stack (); | 
|  | } | 
|  |  | 
|  | /* Emit a NewProgspaceEvent to indicate PSPACE has been created.  */ | 
|  |  | 
|  | static void | 
|  | gdbpy_new_program_space_event (program_space *pspace) | 
|  | { | 
|  | gdbpy_program_space_event (pspace, true); | 
|  | } | 
|  |  | 
|  | /* Emit a FreeProgspaceEvent to indicate PSPACE is just about to be removed | 
|  | from GDB.  */ | 
|  |  | 
|  | static void | 
|  | gdbpy_free_program_space_event (program_space *pspace) | 
|  | { | 
|  | gdbpy_program_space_event (pspace, false); | 
|  | } | 
|  |  | 
|  | static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION | 
|  | gdbpy_initialize_pspace (void) | 
|  | { | 
|  | gdb::observers::executable_changed.attach (gdbpy_executable_changed, | 
|  | "py-progspace"); | 
|  | gdb::observers::new_program_space.attach (gdbpy_new_program_space_event, | 
|  | "py-progspace"); | 
|  | gdb::observers::free_program_space.attach (gdbpy_free_program_space_event, | 
|  | "py-progspace"); | 
|  |  | 
|  | if (PyType_Ready (&pspace_object_type) < 0) | 
|  | return -1; | 
|  |  | 
|  | return gdb_pymodule_addobject (gdb_module, "Progspace", | 
|  | (PyObject *) &pspace_object_type); | 
|  | } | 
|  |  | 
|  | GDBPY_INITIALIZE_FILE (gdbpy_initialize_pspace); | 
|  |  | 
|  |  | 
|  |  | 
|  | static gdb_PyGetSetDef pspace_getset[] = | 
|  | { | 
|  | { "__dict__", gdb_py_generic_dict, NULL, | 
|  | "The __dict__ for this progspace.", &pspace_object_type }, | 
|  | { "filename", pspy_get_filename, NULL, | 
|  | "The filename of the progspace's main symbol file, or None.", nullptr }, | 
|  | { "symbol_file", pspy_get_symbol_file, nullptr, | 
|  | "The gdb.Objfile for the progspace's main symbol file, or None.", | 
|  | nullptr}, | 
|  | { "executable_filename", pspy_get_exec_file, nullptr, | 
|  | "The filename for the progspace's executable, or None.", nullptr}, | 
|  | { "pretty_printers", pspy_get_printers, pspy_set_printers, | 
|  | "Pretty printers.", NULL }, | 
|  | { "frame_filters", pspy_get_frame_filters, pspy_set_frame_filters, | 
|  | "Frame filters.", NULL }, | 
|  | { "frame_unwinders", pspy_get_frame_unwinders, pspy_set_frame_unwinders, | 
|  | "Frame unwinders.", NULL }, | 
|  | { "type_printers", pspy_get_type_printers, pspy_set_type_printers, | 
|  | "Type printers.", NULL }, | 
|  | { "xmethods", pspy_get_xmethods, NULL, | 
|  | "Debug methods.", NULL }, | 
|  | { "missing_debug_handlers", pspy_get_missing_debug_handlers, | 
|  | pspy_set_missing_debug_handlers, "Missing debug handlers.", NULL }, | 
|  | { NULL } | 
|  | }; | 
|  |  | 
|  | static PyMethodDef progspace_object_methods[] = | 
|  | { | 
|  | { "objfiles", pspy_get_objfiles, METH_NOARGS, | 
|  | "Return a sequence of objfiles associated to this program space." }, | 
|  | { "solib_name", pspy_solib_name, METH_VARARGS, | 
|  | "solib_name (Long) -> String.\n\ | 
|  | Return the name of the shared library holding a given address, or None." }, | 
|  | { "objfile_for_address", pspy_objfile_for_address, METH_VARARGS, | 
|  | "objfile_for_address (int) -> gdb.Objfile\n\ | 
|  | Return the objfile containing the given address, or None." }, | 
|  | { "block_for_pc", pspy_block_for_pc, METH_VARARGS, | 
|  | "Return the block containing the given pc value, or None." }, | 
|  | { "find_pc_line", pspy_find_pc_line, METH_VARARGS, | 
|  | "find_pc_line (pc) -> Symtab_and_line.\n\ | 
|  | Return the gdb.Symtab_and_line object corresponding to the pc value." }, | 
|  | { "is_valid", pspy_is_valid, METH_NOARGS, | 
|  | "is_valid () -> Boolean.\n\ | 
|  | Return true if this program space is valid, false if not." }, | 
|  | { NULL } | 
|  | }; | 
|  |  | 
|  | PyTypeObject pspace_object_type = | 
|  | { | 
|  | PyVarObject_HEAD_INIT (NULL, 0) | 
|  | "gdb.Progspace",		  /*tp_name*/ | 
|  | sizeof (pspace_object),	  /*tp_basicsize*/ | 
|  | 0,				  /*tp_itemsize*/ | 
|  | pspy_dealloc,			  /*tp_dealloc*/ | 
|  | 0,				  /*tp_print*/ | 
|  | 0,				  /*tp_getattr*/ | 
|  | 0,				  /*tp_setattr*/ | 
|  | 0,				  /*tp_compare*/ | 
|  | 0,				  /*tp_repr*/ | 
|  | 0,				  /*tp_as_number*/ | 
|  | 0,				  /*tp_as_sequence*/ | 
|  | 0,				  /*tp_as_mapping*/ | 
|  | 0,				  /*tp_hash */ | 
|  | 0,				  /*tp_call*/ | 
|  | 0,				  /*tp_str*/ | 
|  | 0,				  /*tp_getattro*/ | 
|  | 0,				  /*tp_setattro*/ | 
|  | 0,				  /*tp_as_buffer*/ | 
|  | Py_TPFLAGS_DEFAULT,		  /*tp_flags*/ | 
|  | "GDB progspace object",	  /* tp_doc */ | 
|  | 0,				  /* tp_traverse */ | 
|  | 0,				  /* tp_clear */ | 
|  | 0,				  /* tp_richcompare */ | 
|  | 0,				  /* tp_weaklistoffset */ | 
|  | 0,				  /* tp_iter */ | 
|  | 0,				  /* tp_iternext */ | 
|  | progspace_object_methods,	  /* tp_methods */ | 
|  | 0,				  /* tp_members */ | 
|  | pspace_getset,		  /* tp_getset */ | 
|  | 0,				  /* tp_base */ | 
|  | 0,				  /* tp_dict */ | 
|  | 0,				  /* tp_descr_get */ | 
|  | 0,				  /* tp_descr_set */ | 
|  | offsetof (pspace_object, dict), /* tp_dictoffset */ | 
|  | 0,				  /* tp_init */ | 
|  | 0,				  /* tp_alloc */ | 
|  | 0,				  /* tp_new */ | 
|  | }; |