
This commit adds a new method gdb.Architecture.registers that returns an object of the new type gdb.RegisterDescriptorIterator. This iterator returns objects of the new type gdb.RegisterDescriptor. A RegisterDescriptor is not a way to read the value of a register, this is already covered by Frame.read_register, a RegisterDescriptor is simply a way to discover from Python, which registers are available for a given architecture. I did consider just returning a string, the name of each register, instead of a RegisterDescriptor, however, I'm aware that it we don't want to break the existing Python API in any way, so if I return just a string now, but in the future we want more information about a register then we would have to add a second API to get that information. By going straight to a descriptor object now, it is easy to add additional properties in the future should we wish to. Right now the only property of a register that a user can access is the name of the register. In future we might want to be able to ask the register about is register groups, or its type. gdb/ChangeLog: * Makefile.in (SUBDIR_PYTHON_SRCS): Add py-registers.c * python/py-arch.c (archpy_registers): New function. (arch_object_methods): Add 'registers' method. * python/py-registers.c: New file. * python/python-internal.h (gdbpy_new_register_descriptor_iterator): Declare. (gdbpy_initialize_registers): Declare. * python/python.c (do_start_initialization): Call gdbpy_initialize_registers. * NEWS: Mention additions to the Python API. gdb/testsuite/ChangeLog: * gdb.python/py-arch-reg-names.exp: New file. gdb/doc/ChangeLog: * python.texi (Python API): Add new section the menu. (Frames In Python): Add new @anchor. (Architectures In Python): Document new registers method. (Registers In Python): New section.
269 lines
7.9 KiB
C
269 lines
7.9 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"
|
|
|
|
/* 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");
|
|
|
|
/* Create an return a new gdb.RegisterDescriptor object. */
|
|
static PyObject *
|
|
gdbpy_new_register_descriptor (struct gdbarch *gdbarch,
|
|
int regnum)
|
|
{
|
|
/* Create a new object and fill in its details. */
|
|
register_descriptor_object *reg
|
|
= PyObject_New (register_descriptor_object,
|
|
®ister_descriptor_object_type);
|
|
if (reg == NULL)
|
|
return NULL;
|
|
reg->regnum = regnum;
|
|
reg->gdbarch = gdbarch;
|
|
return (PyObject *) reg;
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
/* 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_new_register_descriptor (gdbarch, regnum);
|
|
}
|
|
while (true);
|
|
}
|
|
|
|
/* Initializes the new Python classes from this file in the gdb module. */
|
|
|
|
int
|
|
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;
|
|
|
|
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));
|
|
}
|
|
|
|
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 */
|
|
0 /*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 */
|
|
};
|