/* Python interface to register, and register group information. Copyright (C) 2020-2023 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 . */ #include "defs.h" #include "gdbarch.h" #include "arch-utils.h" #include "reggroups.h" #include "python-internal.h" #include "user-regs.h" #include /* Per-gdbarch data type. */ typedef std::vector> gdbpy_register_type; /* Token to access per-gdbarch data related to register descriptors. */ static const registry::key gdbpy_register_object_data; /* Structure for iterator over register descriptors. */ struct register_descriptor_iterator_object { PyObject_HEAD /* The register group that the user is iterating over. This will never be NULL. */ const struct reggroup *reggroup; /* The next register number to lookup. Starts at 0 and counts up. */ int regnum; /* Pointer back to the architecture we're finding registers for. */ struct gdbarch *gdbarch; }; extern PyTypeObject register_descriptor_iterator_object_type CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("register_descriptor_iterator_object"); /* A register descriptor. */ struct register_descriptor_object { PyObject_HEAD /* The register this is a descriptor for. */ int regnum; /* The architecture this is a register for. */ struct gdbarch *gdbarch; }; extern PyTypeObject register_descriptor_object_type CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("register_descriptor_object"); /* Structure for iterator over register groups. */ struct reggroup_iterator_object { PyObject_HEAD /* The index into GROUPS for the next group to return. */ std::vector::size_type index; /* Pointer back to the architecture we're finding registers for. */ struct gdbarch *gdbarch; }; extern PyTypeObject reggroup_iterator_object_type CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("reggroup_iterator_object"); /* A register group object. */ struct reggroup_object { PyObject_HEAD /* The register group being described. */ const struct reggroup *reggroup; }; extern PyTypeObject reggroup_object_type CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("reggroup_object"); /* Return a gdb.RegisterGroup object wrapping REGGROUP. The register group objects are cached, and the same Python object will always be returned for the same REGGROUP pointer. */ static gdbpy_ref<> gdbpy_get_reggroup (const reggroup *reggroup) { /* Map from GDB's internal reggroup objects to the Python representation. GDB's reggroups are global, and are never deleted, so using a map like this is safe. */ static std::unordered_map> gdbpy_reggroup_object_map; /* If there is not already a suitable Python object in the map then create a new one, and add it to the map. */ if (gdbpy_reggroup_object_map[reggroup] == nullptr) { /* Create a new object and fill in its details. */ gdbpy_ref group (PyObject_New (reggroup_object, ®group_object_type)); if (group == NULL) return NULL; group->reggroup = reggroup; gdbpy_reggroup_object_map[reggroup] = gdbpy_ref<> ((PyObject *) group.release ()); } /* Fetch the Python object wrapping REGGROUP from the map, increasing the reference count is handled by the gdbpy_ref class. */ return gdbpy_reggroup_object_map[reggroup]; } /* Convert a gdb.RegisterGroup to a string, it just returns the name of the register group. */ static PyObject * gdbpy_reggroup_to_string (PyObject *self) { reggroup_object *group = (reggroup_object *) self; const reggroup *reggroup = group->reggroup; return PyUnicode_FromString (reggroup->name ()); } /* Implement gdb.RegisterGroup.name (self) -> String. Return a string that is the name of this register group. */ static PyObject * gdbpy_reggroup_name (PyObject *self, void *closure) { return gdbpy_reggroup_to_string (self); } /* Return a gdb.RegisterDescriptor object for REGNUM from GDBARCH. For each REGNUM (in GDBARCH) only one descriptor is ever created, which is then cached on the GDBARCH. */ static gdbpy_ref<> gdbpy_get_register_descriptor (struct gdbarch *gdbarch, int regnum) { gdbpy_register_type *vecp = gdbpy_register_object_data.get (gdbarch); if (vecp == nullptr) vecp = gdbpy_register_object_data.emplace (gdbarch); gdbpy_register_type &vec = *vecp; /* Ensure that we have enough entries in the vector. */ if (vec.size () <= regnum) vec.resize ((regnum + 1), nullptr); /* If we don't already have a descriptor for REGNUM in GDBARCH then create one now. */ if (vec[regnum] == nullptr) { gdbpy_ref reg (PyObject_New (register_descriptor_object, ®ister_descriptor_object_type)); if (reg == NULL) return NULL; reg->regnum = regnum; reg->gdbarch = gdbarch; vec[regnum] = gdbpy_ref<> ((PyObject *) reg.release ()); } /* Grab the register descriptor from the vector, the reference count is automatically incremented thanks to gdbpy_ref. */ return vec[regnum]; } /* Convert the register descriptor to a string. */ static PyObject * gdbpy_register_descriptor_to_string (PyObject *self) { register_descriptor_object *reg = (register_descriptor_object *) self; struct gdbarch *gdbarch = reg->gdbarch; int regnum = reg->regnum; const char *name = gdbarch_register_name (gdbarch, regnum); return PyUnicode_FromString (name); } /* Implement gdb.RegisterDescriptor.name attribute get function. Return a string that is the name of this register. Due to checking when register descriptors are created the name will never by the empty string. */ static PyObject * gdbpy_register_descriptor_name (PyObject *self, void *closure) { return gdbpy_register_descriptor_to_string (self); } /* Return a reference to the gdb.RegisterGroupsIterator object. */ static PyObject * gdbpy_reggroup_iter (PyObject *self) { Py_INCREF (self); return self; } /* Return the next gdb.RegisterGroup object from the iterator. */ static PyObject * gdbpy_reggroup_iter_next (PyObject *self) { reggroup_iterator_object *iter_obj = (reggroup_iterator_object *) self; const std::vector &groups = gdbarch_reggroups (iter_obj->gdbarch); if (iter_obj->index >= groups.size ()) { PyErr_SetString (PyExc_StopIteration, _("No more groups")); return NULL; } const reggroup *group = groups[iter_obj->index]; iter_obj->index++; return gdbpy_get_reggroup (group).release (); } /* Return a new gdb.RegisterGroupsIterator over all the register groups in GDBARCH. */ PyObject * gdbpy_new_reggroup_iterator (struct gdbarch *gdbarch) { gdb_assert (gdbarch != nullptr); /* Create a new object and fill in its internal state. */ reggroup_iterator_object *iter = PyObject_New (reggroup_iterator_object, ®group_iterator_object_type); if (iter == NULL) return NULL; iter->index = 0; iter->gdbarch = gdbarch; return (PyObject *) iter; } /* Create and return a new gdb.RegisterDescriptorIterator object which will iterate over all registers in GROUP_NAME for GDBARCH. If GROUP_NAME is either NULL or the empty string then the ALL_REGGROUP is used, otherwise lookup the register group matching GROUP_NAME and use that. This function can return NULL if GROUP_NAME isn't found. */ PyObject * gdbpy_new_register_descriptor_iterator (struct gdbarch *gdbarch, const char *group_name) { const reggroup *grp = NULL; /* Lookup the requested register group, or find the default. */ if (group_name == NULL || *group_name == '\0') grp = all_reggroup; else { grp = reggroup_find (gdbarch, group_name); if (grp == NULL) { PyErr_SetString (PyExc_ValueError, _("Unknown register group name.")); return NULL; } } /* Create a new iterator object initialised for this architecture and fill in all of the details. */ register_descriptor_iterator_object *iter = PyObject_New (register_descriptor_iterator_object, ®ister_descriptor_iterator_object_type); if (iter == NULL) return NULL; iter->regnum = 0; iter->gdbarch = gdbarch; gdb_assert (grp != NULL); iter->reggroup = grp; return (PyObject *) iter; } /* Return a reference to the gdb.RegisterDescriptorIterator object. */ static PyObject * gdbpy_register_descriptor_iter (PyObject *self) { Py_INCREF (self); return self; } /* Return the next register name. */ static PyObject * gdbpy_register_descriptor_iter_next (PyObject *self) { register_descriptor_iterator_object *iter_obj = (register_descriptor_iterator_object *) self; struct gdbarch *gdbarch = iter_obj->gdbarch; do { if (iter_obj->regnum >= gdbarch_num_cooked_regs (gdbarch)) { PyErr_SetString (PyExc_StopIteration, _("No more registers")); return NULL; } const char *name = nullptr; int regnum = iter_obj->regnum; if (gdbarch_register_reggroup_p (gdbarch, regnum, iter_obj->reggroup)) name = gdbarch_register_name (gdbarch, regnum); iter_obj->regnum++; if (name != nullptr && *name != '\0') return gdbpy_get_register_descriptor (gdbarch, regnum).release (); } while (true); } /* Implement: gdb.RegisterDescriptorIterator.find (self, name) -> gdb.RegisterDescriptor Look up a descriptor for register with NAME. If no matching register is found then return None. */ static PyObject * register_descriptor_iter_find (PyObject *self, PyObject *args, PyObject *kw) { static const char *keywords[] = { "name", NULL }; const char *register_name = NULL; register_descriptor_iterator_object *iter_obj = (register_descriptor_iterator_object *) self; struct gdbarch *gdbarch = iter_obj->gdbarch; if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s", keywords, ®ister_name)) return NULL; if (register_name != NULL && *register_name != '\0') { int regnum = user_reg_map_name_to_regnum (gdbarch, register_name, strlen (register_name)); if (regnum >= 0) return gdbpy_get_register_descriptor (gdbarch, regnum).release (); } Py_RETURN_NONE; } /* See python-internal.h. */ bool gdbpy_parse_register_id (struct gdbarch *gdbarch, PyObject *pyo_reg_id, int *reg_num) { gdb_assert (pyo_reg_id != NULL); /* The register could be a string, its name. */ if (gdbpy_is_string (pyo_reg_id)) { gdb::unique_xmalloc_ptr reg_name (gdbpy_obj_to_string (pyo_reg_id)); if (reg_name != NULL) { *reg_num = user_reg_map_name_to_regnum (gdbarch, reg_name.get (), strlen (reg_name.get ())); if (*reg_num >= 0) return true; PyErr_SetString (PyExc_ValueError, "Bad register"); } } /* The register could be its internal GDB register number. */ else if (PyLong_Check (pyo_reg_id)) { long value; if (gdb_py_int_as_long (pyo_reg_id, &value) == 0) { /* Nothing -- error. */ } else if ((int) value == value && user_reg_map_regnum_to_name (gdbarch, value) != NULL) { *reg_num = (int) value; return true; } else PyErr_SetString (PyExc_ValueError, "Bad register"); } /* The register could be a gdb.RegisterDescriptor object. */ else if (PyObject_IsInstance (pyo_reg_id, (PyObject *) ®ister_descriptor_object_type)) { register_descriptor_object *reg = (register_descriptor_object *) pyo_reg_id; if (reg->gdbarch == gdbarch) { *reg_num = reg->regnum; return true; } else PyErr_SetString (PyExc_ValueError, _("Invalid Architecture in RegisterDescriptor")); } else PyErr_SetString (PyExc_TypeError, _("Invalid type for register")); gdb_assert (PyErr_Occurred ()); return false; } /* Initializes the new Python classes from this file in the gdb module. */ static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION gdbpy_initialize_registers () { register_descriptor_object_type.tp_new = PyType_GenericNew; if (PyType_Ready (®ister_descriptor_object_type) < 0) return -1; if (gdb_pymodule_addobject (gdb_module, "RegisterDescriptor", (PyObject *) ®ister_descriptor_object_type) < 0) return -1; reggroup_iterator_object_type.tp_new = PyType_GenericNew; if (PyType_Ready (®group_iterator_object_type) < 0) return -1; if (gdb_pymodule_addobject (gdb_module, "RegisterGroupsIterator", (PyObject *) ®group_iterator_object_type) < 0) return -1; reggroup_object_type.tp_new = PyType_GenericNew; if (PyType_Ready (®group_object_type) < 0) return -1; if (gdb_pymodule_addobject (gdb_module, "RegisterGroup", (PyObject *) ®group_object_type) < 0) return -1; register_descriptor_iterator_object_type.tp_new = PyType_GenericNew; if (PyType_Ready (®ister_descriptor_iterator_object_type) < 0) return -1; return (gdb_pymodule_addobject (gdb_module, "RegisterDescriptorIterator", (PyObject *) ®ister_descriptor_iterator_object_type)); } GDBPY_INITIALIZE_FILE (gdbpy_initialize_registers); static PyMethodDef register_descriptor_iterator_object_methods [] = { { "find", (PyCFunction) register_descriptor_iter_find, METH_VARARGS | METH_KEYWORDS, "registers (name) -> gdb.RegisterDescriptor.\n\ Return a register descriptor for the register NAME, or None if no register\n\ with that name exists in this iterator." }, {NULL} /* Sentinel */ }; PyTypeObject register_descriptor_iterator_object_type = { PyVarObject_HEAD_INIT (NULL, 0) "gdb.RegisterDescriptorIterator", /*tp_name*/ sizeof (register_descriptor_iterator_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ 0, /*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 architecture register descriptor iterator object", /*tp_doc */ 0, /*tp_traverse */ 0, /*tp_clear */ 0, /*tp_richcompare */ 0, /*tp_weaklistoffset */ gdbpy_register_descriptor_iter, /*tp_iter */ gdbpy_register_descriptor_iter_next, /*tp_iternext */ register_descriptor_iterator_object_methods /*tp_methods */ }; static gdb_PyGetSetDef gdbpy_register_descriptor_getset[] = { { "name", gdbpy_register_descriptor_name, NULL, "The name of this register.", NULL }, { NULL } /* Sentinel */ }; PyTypeObject register_descriptor_object_type = { PyVarObject_HEAD_INIT (NULL, 0) "gdb.RegisterDescriptor", /*tp_name*/ sizeof (register_descriptor_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ 0, /*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*/ gdbpy_register_descriptor_to_string, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "GDB architecture register descriptor object", /*tp_doc */ 0, /*tp_traverse */ 0, /*tp_clear */ 0, /*tp_richcompare */ 0, /*tp_weaklistoffset */ 0, /*tp_iter */ 0, /*tp_iternext */ 0, /*tp_methods */ 0, /*tp_members */ gdbpy_register_descriptor_getset /*tp_getset */ }; PyTypeObject reggroup_iterator_object_type = { PyVarObject_HEAD_INIT (NULL, 0) "gdb.RegisterGroupsIterator", /*tp_name*/ sizeof (reggroup_iterator_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ 0, /*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 register groups iterator object", /*tp_doc */ 0, /*tp_traverse */ 0, /*tp_clear */ 0, /*tp_richcompare */ 0, /*tp_weaklistoffset */ gdbpy_reggroup_iter, /*tp_iter */ gdbpy_reggroup_iter_next, /*tp_iternext */ 0 /*tp_methods */ }; static gdb_PyGetSetDef gdbpy_reggroup_getset[] = { { "name", gdbpy_reggroup_name, NULL, "The name of this register group.", NULL }, { NULL } /* Sentinel */ }; PyTypeObject reggroup_object_type = { PyVarObject_HEAD_INIT (NULL, 0) "gdb.RegisterGroup", /*tp_name*/ sizeof (reggroup_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ 0, /*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*/ gdbpy_reggroup_to_string, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "GDB register group object", /*tp_doc */ 0, /*tp_traverse */ 0, /*tp_clear */ 0, /*tp_richcompare */ 0, /*tp_weaklistoffset */ 0, /*tp_iter */ 0, /*tp_iternext */ 0, /*tp_methods */ 0, /*tp_members */ gdbpy_reggroup_getset /*tp_getset */ };