mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-13 03:48:49 +08:00

This commit unifies all of the Python register lookup code (used by Frame.read_register, PendingFrame.read_register, and gdb.UnwindInfo.add_saved_register), and adds support for using a gdb.RegisterDescriptor for register lookup. Currently the register unwind code (PendingFrame and UnwindInfo) allow registers to be looked up either by name, or by GDB's internal number. I suspect the number was added for performance reasons, when unwinding we don't want to repeatedly map from name to number for every unwind. However, this kind-of sucks, it means Python scripts could include GDB's internal register numbers, and if we ever change this numbering in the future users scripts will break in unexpected ways. Meanwhile, the Frame.read_register method only supports accessing registers using a string, the register name. This commit unifies all of the register to register-number lookup code in our Python bindings, and adds a third choice into the mix, the use of gdb.RegisterDescriptor. The register descriptors can be looked up by name, but once looked up, they contain GDB's register number, and so provide all of the performance benefits of using a register number directly. However, as they are looked up by name we are no longer tightly binding the Python API to GDB's internal numbering scheme. As we may already have scripts in the wild that are using the register numbers directly I have kept support for this in the API, but I have listed this method last in the manual, and I have tried to stress that this is NOT a good method to use and that users should use either a string or register descriptor approach. After this commit all existing Python code should function as before, but users now have new options for how to identify registers. gdb/ChangeLog: * python/py-frame.c: Remove 'user-regs.h' include. (frapy_read_register): Rewrite to make use of gdbpy_parse_register_id. * python/py-registers.c (gdbpy_parse_register_id): New function, moved here from python/py-unwind.c. Updated the return type, and also accepts register descriptor objects. * python/py-unwind.c: Remove 'user-regs.h' include. (pyuw_parse_register_id): Moved to python/py-registers.c. (unwind_infopy_add_saved_register): Update to use gdbpy_parse_register_id. (pending_framepy_read_register): Likewise. * python/python-internal.h (gdbpy_parse_register_id): Declare. gdb/testsuite/ChangeLog: * gdb.python/py-unwind.py: Update to make use of a register descriptor. gdb/doc/ChangeLog: * python.texi (Unwinding Frames in Python): Update descriptions for PendingFrame.read_register and gdb.UnwindInfo.add_saved_register. (Frames In Python): Update description of Frame.read_register.
614 lines
18 KiB
C
614 lines
18 KiB
C
/* Python interface to register, and register group information.
|
|
|
|
Copyright (C) 2020 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 "defs.h"
|
|
#include "gdbarch.h"
|
|
#include "arch-utils.h"
|
|
#include "disasm.h"
|
|
#include "reggroups.h"
|
|
#include "python-internal.h"
|
|
#include "user-regs.h"
|
|
#include <unordered_map>
|
|
|
|
/* Token to access per-gdbarch data related to register descriptors. */
|
|
static struct gdbarch_data *gdbpy_register_object_data = NULL;
|
|
|
|
/* Structure for iterator over register descriptors. */
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
|
|
/* The register group that the user is iterating over. This will never
|
|
be NULL. */
|
|
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;
|
|
} register_descriptor_iterator_object;
|
|
|
|
extern PyTypeObject register_descriptor_iterator_object_type
|
|
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("register_descriptor_iterator_object");
|
|
|
|
/* A register descriptor. */
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
|
|
/* The register this is a descriptor for. */
|
|
int regnum;
|
|
|
|
/* The architecture this is a register for. */
|
|
struct gdbarch *gdbarch;
|
|
} register_descriptor_object;
|
|
|
|
extern PyTypeObject register_descriptor_object_type
|
|
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("register_descriptor_object");
|
|
|
|
/* Structure for iterator over register groups. */
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
|
|
/* The last register group returned. Initially this will be NULL. */
|
|
struct reggroup *reggroup;
|
|
|
|
/* Pointer back to the architecture we're finding registers for. */
|
|
struct gdbarch *gdbarch;
|
|
} reggroup_iterator_object;
|
|
|
|
extern PyTypeObject reggroup_iterator_object_type
|
|
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("reggroup_iterator_object");
|
|
|
|
/* A register group object. */
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
|
|
/* The register group being described. */
|
|
struct reggroup *reggroup;
|
|
} reggroup_object;
|
|
|
|
extern PyTypeObject reggroup_object_type
|
|
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("reggroup_object");
|
|
|
|
/* Associates a vector of gdb.RegisterDescriptor objects with GDBARCH as
|
|
gdbarch_data via the gdbarch post init registration mechanism
|
|
(gdbarch_data_register_post_init). */
|
|
|
|
static void *
|
|
gdbpy_register_object_data_init (struct gdbarch *gdbarch)
|
|
{
|
|
return new std::vector<gdbpy_ref<>>;
|
|
}
|
|
|
|
/* 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 (struct 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<struct reggroup *,gdbpy_ref<>>
|
|
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<reggroup_object> 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;
|
|
struct reggroup *reggroup = group->reggroup;
|
|
|
|
const char *name = reggroup_name (reggroup);
|
|
return PyString_FromString (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)
|
|
{
|
|
auto &vec
|
|
= *(std::vector<gdbpy_ref<>> *) gdbarch_data (gdbarch,
|
|
gdbpy_register_object_data);
|
|
|
|
/* 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 <register_descriptor_object> 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 PyString_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;
|
|
struct gdbarch *gdbarch = iter_obj->gdbarch;
|
|
|
|
struct reggroup *next_group = reggroup_next (gdbarch, iter_obj->reggroup);
|
|
if (next_group == NULL)
|
|
{
|
|
PyErr_SetString (PyExc_StopIteration, _("No more groups"));
|
|
return NULL;
|
|
}
|
|
|
|
iter_obj->reggroup = next_group;
|
|
return gdbpy_get_reggroup (iter_obj->reggroup).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->reggroup = NULL;
|
|
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)
|
|
{
|
|
struct 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<char> 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 ()));
|
|
return *reg_num >= 0;
|
|
}
|
|
}
|
|
/* The register could be its internal GDB register number. */
|
|
else if (PyInt_Check (pyo_reg_id))
|
|
{
|
|
long value;
|
|
if (gdb_py_int_as_long (pyo_reg_id, &value) && (int) value == value)
|
|
{
|
|
if (user_reg_map_regnum_to_name (gdbarch, value) != NULL)
|
|
{
|
|
*reg_num = (int) value;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
/* 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"));
|
|
}
|
|
|
|
gdb_assert (PyErr_Occurred ());
|
|
return false;
|
|
}
|
|
|
|
/* Initializes the new Python classes from this file in the gdb module. */
|
|
|
|
int
|
|
gdbpy_initialize_registers ()
|
|
{
|
|
gdbpy_register_object_data
|
|
= gdbarch_data_register_post_init (gdbpy_register_object_data_init);
|
|
|
|
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));
|
|
}
|
|
|
|
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 | Py_TPFLAGS_HAVE_ITER, /*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 | Py_TPFLAGS_HAVE_ITER, /*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 */
|
|
};
|