/* Python interface to program spaces.
- Copyright (C) 2010-2012 Free Software Foundation, Inc.
+ Copyright (C) 2010-2018 Free Software Foundation, Inc.
This file is part of GDB.
#include "objfiles.h"
#include "language.h"
#include "arch-utils.h"
+#include "py-ref.h"
+#include "solib.h"
+#include "block.h"
typedef struct
{
/* 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;
} pspace_object;
-static PyTypeObject pspace_object_type;
+extern PyTypeObject pspace_object_type
+ CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("pspace_object");
static const struct program_space_data *pspy_pspace_data_key;
-\f
+/* 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. */
struct objfile *objfile = obj->pspace->symfile_object_file;
if (objfile)
- return PyString_Decode (objfile->name, strlen (objfile->name),
- host_charset (), NULL);
+ return host_string_to_python_string (objfile_name (objfile));
}
Py_RETURN_NONE;
}
{
pspace_object *ps_self = (pspace_object *) self;
+ Py_XDECREF (ps_self->dict);
Py_XDECREF (ps_self->printers);
- self->ob_type->tp_free (self);
+ Py_XDECREF (ps_self->frame_filters);
+ Py_XDECREF (ps_self->frame_unwinders);
+ Py_XDECREF (ps_self->type_printers);
+ Py_XDECREF (ps_self->xmethods);
+ 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;
+
+ return 1;
}
static PyObject *
pspy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
{
- pspace_object *self = (pspace_object *) type->tp_alloc (type, 0);
+ gdbpy_ref<pspace_object> self ((pspace_object *) type->tp_alloc (type, 0));
- if (self)
+ if (self != NULL)
{
- self->pspace = NULL;
-
- self->printers = PyList_New (0);
- if (!self->printers)
- {
- Py_DECREF (self);
- return NULL;
- }
+ if (!pspy_initialize (self.get ()))
+ return NULL;
}
- return (PyObject *) self;
+
+ return (PyObject *) self.release ();
}
PyObject *
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)
+{
+ PyObject *tmp;
+ 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. */
+ tmp = self->frame_filters;
+ Py_INCREF (frame);
+ self->frame_filters = frame;
+ Py_XDECREF (tmp);
+
+ 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)
+{
+ PyObject *tmp;
+ 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. */
+ tmp = self->frame_unwinders;
+ Py_INCREF (unwinders);
+ self->frame_unwinders = unwinders;
+ Py_XDECREF (tmp);
+
+ 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;
+}
+
+/* Set the 'type_printers' attribute. */
+
+static int
+pspy_set_type_printers (PyObject *o, PyObject *value, void *ignore)
+{
+ PyObject *tmp;
+ 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. */
+ tmp = self->type_printers;
+ Py_INCREF (value);
+ self->type_printers = value;
+ Py_XDECREF (tmp);
+
+ 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)
+ {
+ struct objfile *objf;
+
+ ALL_PSPACE_OBJFILES (self->pspace, objf)
+ {
+ PyObject *item = objfile_to_objfile_object (objf);
+
+ if (!item || PyList_Append (list.get (), item) == -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)
+{
+ char *soname;
+ gdb_py_longest pc;
+ pspace_object *self = (pspace_object *) o;
+
+ PSPY_REQUIRE_VALID (self);
+
+ if (!PyArg_ParseTuple (args, GDB_PY_LLU_ARG, &pc))
+ return NULL;
+
+ soname = solib_name_from_address (self->pspace, pc);
+ if (soname == nullptr)
+ Py_RETURN_NONE;
+ return host_string_to_python_string (soname);
+}
+
+/* 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;
+ gdb_py_ulongest pc;
+ const struct block *block = NULL;
+ struct compunit_symtab *cust = NULL;
+
+ PSPY_REQUIRE_VALID (self);
+
+ if (!PyArg_ParseTuple (args, GDB_PY_LLU_ARG, &pc))
+ return NULL;
+
+ TRY
+ {
+ scoped_restore_current_program_space saver;
+
+ set_current_program_space (self->pspace);
+ cust = find_pc_compunit_symtab (pc);
+
+ if (cust != NULL && COMPUNIT_OBJFILE (cust) != NULL)
+ block = block_for_pc (pc);
+ }
+ CATCH (except, RETURN_MASK_ALL)
+ {
+ GDB_PY_HANDLE_EXCEPTION (except);
+ }
+ END_CATCH
+
+ if (cust == NULL || COMPUNIT_OBJFILE (cust) == NULL)
+ {
+ PyErr_SetString (PyExc_RuntimeError,
+ _("Cannot locate object file for block."));
+ return NULL;
+ }
+
+ if (block)
+ return block_to_block_object (block, COMPUNIT_OBJFILE (cust));
+
+ 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)
+{
+ gdb_py_ulongest pc_llu;
+ PyObject *result = NULL; /* init for gcc -Wall */
+ pspace_object *self = (pspace_object *) o;
+
+ PSPY_REQUIRE_VALID (self);
+
+ if (!PyArg_ParseTuple (args, GDB_PY_LLU_ARG, &pc_llu))
+ return NULL;
+
+ TRY
+ {
+ struct symtab_and_line sal;
+ CORE_ADDR pc;
+ scoped_restore_current_program_space saver;
+
+ set_current_program_space (self->pspace);
+
+ pc = (CORE_ADDR) pc_llu;
+ sal = find_pc_line (pc, 0);
+ result = symtab_and_line_to_sal_object (sal);
+ }
+ CATCH (except, RETURN_MASK_ALL)
+ {
+ GDB_PY_HANDLE_EXCEPTION (except);
+ }
+ END_CATCH
+
+ 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;
+}
+
\f
/* Clear the PSPACE pointer in a Pspace object and remove the reference. */
static void
py_free_pspace (struct program_space *pspace, void *datum)
{
- struct cleanup *cleanup;
- pspace_object *object = datum;
- struct gdbarch *arch = get_current_arch ();
-
- cleanup = ensure_python_env (arch, current_language);
+ /* 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 target_gdbarch 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. */
+ struct gdbarch *arch = target_gdbarch ();
+
+ gdbpy_enter enter_py (arch, current_language);
+ gdbpy_ref<pspace_object> object ((pspace_object *) datum);
object->pspace = NULL;
- Py_DECREF ((PyObject *) object);
- do_cleanups (cleanup);
}
/* Return a borrowed reference to the Python object of type Pspace
PyObject *
pspace_to_pspace_object (struct program_space *pspace)
{
- pspace_object *object;
-
- object = program_space_data (pspace, pspy_pspace_data_key);
- if (!object)
+ gdbpy_ref<pspace_object> object
+ ((pspace_object *) program_space_data (pspace, pspy_pspace_data_key));
+ if (object == NULL)
{
- object = PyObject_New (pspace_object, &pspace_object_type);
- if (object)
+ object.reset (PyObject_New (pspace_object, &pspace_object_type));
+ if (object != NULL)
{
- object->pspace = pspace;
+ if (!pspy_initialize (object.get ()))
+ return NULL;
- object->printers = PyList_New (0);
- if (!object->printers)
- {
- Py_DECREF (object);
- return NULL;
- }
-
- set_program_space_data (pspace, pspy_pspace_data_key, object);
+ object->pspace = pspace;
+ set_program_space_data (pspace, pspy_pspace_data_key, object.get ());
}
}
- return (PyObject *) object;
+ return (PyObject *) object.release ();
}
-void
+int
gdbpy_initialize_pspace (void)
{
pspy_pspace_data_key
- = register_program_space_data_with_cleanup (py_free_pspace);
+ = register_program_space_data_with_cleanup (NULL, py_free_pspace);
if (PyType_Ready (&pspace_object_type) < 0)
- return;
+ return -1;
- Py_INCREF (&pspace_object_type);
- PyModule_AddObject (gdb_module, "Progspace",
- (PyObject *) &pspace_object_type);
+ return gdb_pymodule_addobject (gdb_module, "Progspace",
+ (PyObject *) &pspace_object_type);
}
\f
-static PyGetSetDef pspace_getset[] =
+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 progspace's main filename, or None.", NULL },
{ "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 },
+ { 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." },
+ { "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 }
};
-static PyTypeObject pspace_object_type =
+PyTypeObject pspace_object_type =
{
- PyObject_HEAD_INIT (NULL)
- 0, /*ob_size*/
+ PyVarObject_HEAD_INIT (NULL, 0)
"gdb.Progspace", /*tp_name*/
sizeof (pspace_object), /*tp_basicsize*/
0, /*tp_itemsize*/
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
- 0, /* tp_methods */
+ 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 */
- 0, /* tp_dictoffset */
+ offsetof (pspace_object, dict), /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
pspy_new, /* tp_new */