mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-04-18 14:41:04 +08:00
gdb/python: New method to access list of register groups
Add a new method gdb.Architecture.register_groups which returns a new object of type gdb.RegisterGroupsIterator. This new iterator then returns objects of type gdb.RegisterGroup. Each gdb.RegisterGroup object just wraps a single reggroup pointer, and (currently) has just one read-only property 'name' that is a string, the name of the register group. As with the previous commit (adding gdb.RegisterDescriptor) I made gdb.RegisterGroup an object rather than just a string in case we want to add additional properties in the future. gdb/ChangeLog: * NEWS: Mention additions to Python API. * python/py-arch.c (archpy_register_groups): New function. (arch_object_methods): Add 'register_groups' method. * python/py-registers.c (reggroup_iterator_object): New struct. (reggroup_object): New struct. (gdbpy_new_reggroup): New function. (gdbpy_reggroup_to_string): New function. (gdbpy_reggroup_name): New function. (gdbpy_reggroup_iter): New function. (gdbpy_reggroup_iter_next): New function. (gdbpy_new_reggroup_iterator): New function (gdbpy_initialize_registers): Register new types. (reggroup_iterator_object_type): Define new Python type. (gdbpy_reggroup_getset): New static global. (reggroup_object_type): Define new Python type. * python/python-internal.h gdb/testsuite/ChangeLog: * gdb.python/py-arch-reg-groups.exp: New file. gdb/doc/ChangeLog: * gdb.texi (Registers): Add @anchor for 'info registers <reggroup>' command. * python.texi (Architectures In Python): Document new register_groups method. (Registers In Python): Document two new object types related to register groups.
This commit is contained in:
parent
0f767f942b
commit
64cb3757a9
@ -1,3 +1,22 @@
|
||||
2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* NEWS: Mention additions to Python API.
|
||||
* python/py-arch.c (archpy_register_groups): New function.
|
||||
(arch_object_methods): Add 'register_groups' method.
|
||||
* python/py-registers.c (reggroup_iterator_object): New struct.
|
||||
(reggroup_object): New struct.
|
||||
(gdbpy_new_reggroup): New function.
|
||||
(gdbpy_reggroup_to_string): New function.
|
||||
(gdbpy_reggroup_name): New function.
|
||||
(gdbpy_reggroup_iter): New function.
|
||||
(gdbpy_reggroup_iter_next): New function.
|
||||
(gdbpy_new_reggroup_iterator): New function
|
||||
(gdbpy_initialize_registers): Register new types.
|
||||
(reggroup_iterator_object_type): Define new Python type.
|
||||
(gdbpy_reggroup_getset): New static global.
|
||||
(reggroup_object_type): Define new Python type.
|
||||
* python/python-internal.h
|
||||
|
||||
2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* Makefile.in (SUBDIR_PYTHON_SRCS): Add py-registers.c
|
||||
|
5
gdb/NEWS
5
gdb/NEWS
@ -125,6 +125,11 @@ GNU/Linux/RISC-V (gdbserver) riscv*-*-linux*
|
||||
gdb.RegisterDescriptor objects. The new RegisterDescriptor is a
|
||||
way to query the registers available for an architecture.
|
||||
|
||||
** New gdb.Architecture.register_groups method that returns a
|
||||
gdb.RegisterGroupIterator object, an iterator that returns
|
||||
gdb.RegisterGroup objects. The new RegisterGroup is a way to
|
||||
discover the available register groups.
|
||||
|
||||
*** Changes in GDB 9
|
||||
|
||||
* 'thread-exited' event is now available in the annotations interface.
|
||||
|
@ -1,3 +1,12 @@
|
||||
2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* gdb.texi (Registers): Add @anchor for 'info registers
|
||||
<reggroup>' command.
|
||||
* python.texi (Architectures In Python): Document new
|
||||
register_groups method.
|
||||
(Registers In Python): Document two new object types related to
|
||||
register groups.
|
||||
|
||||
2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* python.texi (Python API): Add new section to the menu.
|
||||
|
@ -12435,6 +12435,7 @@ and vector registers (in the selected stack frame).
|
||||
Print the names and values of all registers, including floating-point
|
||||
and vector registers (in the selected stack frame).
|
||||
|
||||
@anchor{info_registers_reggroup}
|
||||
@item info registers @var{reggroup} @dots{}
|
||||
Print the name and value of the registers in each of the specified
|
||||
@var{reggroup}s. The @var{reggroup} can be any of those returned by
|
||||
|
@ -5725,6 +5725,13 @@ the name of a register group. If @var{reggroup} is omitted, or is the
|
||||
empty string, then the register group @samp{all} is assumed.
|
||||
@end defun
|
||||
|
||||
@anchor{gdbpy_architecture_reggroups}
|
||||
@defun Architecture.register_groups ()
|
||||
Return a @code{gdb.RegisterGroupsIterator} (@pxref{Registers In
|
||||
Python}) for all of the register groups available for the
|
||||
@code{gdb.Architecture}.
|
||||
@end defun
|
||||
|
||||
@node Registers In Python
|
||||
@subsubsection Registers In Python
|
||||
@cindex Registers In Python
|
||||
@ -5748,6 +5755,31 @@ A @code{gdb.RegisterDescriptor} has the following read-only properties:
|
||||
The name of this register.
|
||||
@end defvar
|
||||
|
||||
Python code can also request from a @code{gdb.Architecture}
|
||||
information about the set of register groups available on a given
|
||||
architecture
|
||||
(@pxref{gdbpy_architecture_reggroups,,@code{Architecture.register_groups}}).
|
||||
|
||||
Every register can be a member of zero or more register groups. Some
|
||||
register groups are used internally within @value{GDBN} to control
|
||||
things like which registers must be saved when calling into the
|
||||
program being debugged (@pxref{Calling,,Calling Program Functions}).
|
||||
Other register groups exist to allow users to easily see related sets
|
||||
of registers in commands like @code{info registers}
|
||||
(@pxref{info_registers_reggroup,,@code{info registers
|
||||
@var{reggroup}}}).
|
||||
|
||||
The register groups information is returned as a
|
||||
@code{gdb.RegisterGroupsIterator}, which is an iterator that in turn
|
||||
returns @code{gdb.RegisterGroup} objects.
|
||||
|
||||
A @code{gdb.RegisterGroup} object has the following read-only
|
||||
properties:
|
||||
|
||||
@defvar RegisterGroup.name
|
||||
A string that is the name of this register group.
|
||||
@end defvar
|
||||
|
||||
@node TUI Windows In Python
|
||||
@subsubsection Implementing new TUI windows
|
||||
@cindex Python TUI Windows
|
||||
|
@ -248,6 +248,20 @@ archpy_registers (PyObject *self, PyObject *args, PyObject *kw)
|
||||
return gdbpy_new_register_descriptor_iterator (gdbarch, group_name);
|
||||
}
|
||||
|
||||
/* Implementation of gdb.Architecture.register_groups (self) -> Iterator.
|
||||
Returns an iterator that will give up all valid register groups in the
|
||||
architecture SELF. */
|
||||
|
||||
static PyObject *
|
||||
archpy_register_groups (PyObject *self, PyObject *args)
|
||||
{
|
||||
struct gdbarch *gdbarch = NULL;
|
||||
|
||||
/* Extract the gdbarch from the self object. */
|
||||
ARCHPY_REQUIRE_VALID (self, gdbarch);
|
||||
return gdbpy_new_reggroup_iterator (gdbarch);
|
||||
}
|
||||
|
||||
/* Initializes the Architecture class in the gdb module. */
|
||||
|
||||
int
|
||||
@ -276,6 +290,10 @@ END_PC." },
|
||||
"registers ([ group-name ]) -> Iterator.\n\
|
||||
Return an iterator of register descriptors for the registers in register\n\
|
||||
group GROUP-NAME." },
|
||||
{ "register_groups", archpy_register_groups,
|
||||
METH_NOARGS,
|
||||
"register_groups () -> Iterator.\n\
|
||||
Return an iterator over all of the register groups in this architecture." },
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
@ -56,6 +56,67 @@ typedef struct {
|
||||
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");
|
||||
|
||||
/* Create a new gdb.RegisterGroup object wrapping REGGROUP. */
|
||||
|
||||
static PyObject *
|
||||
gdbpy_new_reggroup (struct reggroup *reggroup)
|
||||
{
|
||||
/* Create a new object and fill in its details. */
|
||||
reggroup_object *group
|
||||
= PyObject_New (reggroup_object, ®group_object_type);
|
||||
if (group == NULL)
|
||||
return NULL;
|
||||
group->reggroup = reggroup;
|
||||
return (PyObject *) group;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Create an return a new gdb.RegisterDescriptor object. */
|
||||
static PyObject *
|
||||
gdbpy_new_register_descriptor (struct gdbarch *gdbarch,
|
||||
@ -96,6 +157,54 @@ 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_new_reggroup (iter_obj->reggroup);
|
||||
}
|
||||
|
||||
/* 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
|
||||
@ -190,6 +299,22 @@ gdbpy_initialize_registers ()
|
||||
(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;
|
||||
@ -267,3 +392,73 @@ PyTypeObject register_descriptor_object_type = {
|
||||
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 */
|
||||
};
|
||||
|
@ -475,6 +475,7 @@ PyObject *gdbarch_to_arch_object (struct gdbarch *gdbarch);
|
||||
|
||||
PyObject *gdbpy_new_register_descriptor_iterator (struct gdbarch *gdbarch,
|
||||
const char *group_name);
|
||||
PyObject *gdbpy_new_reggroup_iterator (struct gdbarch *gdbarch);
|
||||
|
||||
gdbpy_ref<thread_object> create_thread_object (struct thread_info *tp);
|
||||
gdbpy_ref<> thread_to_thread_object (thread_info *thr);;
|
||||
|
@ -1,3 +1,7 @@
|
||||
2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* gdb.python/py-arch-reg-groups.exp: New file.
|
||||
|
||||
2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* gdb.python/py-arch-reg-names.exp: New file.
|
||||
|
87
gdb/testsuite/gdb.python/py-arch-reg-groups.exp
Normal file
87
gdb/testsuite/gdb.python/py-arch-reg-groups.exp
Normal file
@ -0,0 +1,87 @@
|
||||
# Copyright 2020 Free Software Foundation, Inc.
|
||||
|
||||
# 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/>.
|
||||
|
||||
# Check the gdb.Architecture.register_groups functionality.
|
||||
|
||||
load_lib gdb-python.exp
|
||||
standard_testfile py-arch.c
|
||||
|
||||
if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
|
||||
return -1
|
||||
}
|
||||
|
||||
# Skip all tests if Python scripting is not enabled.
|
||||
if { [skip_python_tests] } { continue }
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
# First, use 'maint print reggroups' to get a list of all register
|
||||
# groups.
|
||||
set groups {}
|
||||
set test "maint print reggroups"
|
||||
gdb_test_multiple $test $test {
|
||||
-re ".*Group\[ \t\]+Type\[ \t\]+\r\n" {
|
||||
exp_continue
|
||||
}
|
||||
-re "^ (\[^ \t\]+)\[ \t\]+\[^\r\n\]+\r\n" {
|
||||
lappend groups $expect_out(1,string)
|
||||
exp_continue
|
||||
}
|
||||
-re "^$gdb_prompt " {
|
||||
}
|
||||
}
|
||||
gdb_assert {[llength $groups] > 0} \
|
||||
"Found at least one register group"
|
||||
|
||||
# Now get the same register names using Python API.
|
||||
gdb_py_test_silent_cmd \
|
||||
"python frame = gdb.selected_frame()" "get frame" 0
|
||||
gdb_py_test_silent_cmd \
|
||||
"python arch = frame.architecture()" "get arch" 0
|
||||
gdb_py_test_silent_cmd \
|
||||
"python groups = list (arch.register_groups ())" \
|
||||
"get register groups" 0
|
||||
gdb_py_test_silent_cmd \
|
||||
"python groups = map (lambda obj: obj.name, groups)" \
|
||||
"convert groups to names" 0
|
||||
|
||||
set py_groups {}
|
||||
gdb_test_multiple "python print (\"\\n\".join (groups))" \
|
||||
"register groups from python" {
|
||||
-re "^python print \[^\r\n\]+\r\n" {
|
||||
exp_continue
|
||||
}
|
||||
-re "^(\[^\r\n\]+)\r\n" {
|
||||
lappend py_groups $expect_out(1,string)
|
||||
exp_continue
|
||||
}
|
||||
-re "^$gdb_prompt " {
|
||||
}
|
||||
}
|
||||
|
||||
gdb_assert {[llength $py_groups] > 0} \
|
||||
"Found at least one register group from python"
|
||||
gdb_assert {[llength $py_groups] == [llength $groups]} \
|
||||
"Same numnber of registers groups found"
|
||||
|
||||
set found_non_match 0
|
||||
for { set i 0 } { $i < [llength $groups] } { incr i } {
|
||||
if {[lindex $groups $i] != [lindex $py_groups $i]} {
|
||||
set found_non_match 1
|
||||
}
|
||||
}
|
||||
gdb_assert { $found_non_match == 0 } "all register groups match"
|
Loading…
x
Reference in New Issue
Block a user