gdb/python: Add gdb.Architecture.registers method
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.
This commit is contained in:
parent
87dbc77459
commit
0f767f942b
11 changed files with 452 additions and 0 deletions
|
@ -1,3 +1,16 @@
|
|||
2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* 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.
|
||||
|
||||
2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* NEWS: Mention new Python API method.
|
||||
|
|
|
@ -401,6 +401,7 @@ SUBDIR_PYTHON_SRCS = \
|
|||
python/py-record.c \
|
||||
python/py-record-btrace.c \
|
||||
python/py-record-full.c \
|
||||
python/py-registers.c \
|
||||
python/py-signalevent.c \
|
||||
python/py-stopevent.c \
|
||||
python/py-symbol.c \
|
||||
|
|
5
gdb/NEWS
5
gdb/NEWS
|
@ -120,6 +120,11 @@ GNU/Linux/RISC-V (gdbserver) riscv*-*-linux*
|
|||
** New method gdb.PendingFrame.architecture () to retrieve the
|
||||
architecture of the pending frame.
|
||||
|
||||
** New gdb.Architecture.registers method that returns a
|
||||
gdb.RegisterDescriptorIterator object, an iterator that returns
|
||||
gdb.RegisterDescriptor objects. The new RegisterDescriptor is a
|
||||
way to query the registers available for an architecture.
|
||||
|
||||
*** Changes in GDB 9
|
||||
|
||||
* 'thread-exited' event is now available in the annotations interface.
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* python.texi (Python API): Add new section to the menu.
|
||||
(Frames In Python): Add new @anchor.
|
||||
(Architectures In Python): Document new registers method.
|
||||
(Registers In Python): New section.
|
||||
|
||||
2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* python.texi (Unwinding Frames in Python): Document
|
||||
|
|
|
@ -163,6 +163,7 @@ optional arguments while skipping others. Example:
|
|||
using Python.
|
||||
* Lazy Strings In Python:: Python representation of lazy strings.
|
||||
* Architectures In Python:: Python representation of architectures.
|
||||
* Registers In Python:: Python representation of registers.
|
||||
* TUI Windows In Python:: Implementing new TUI windows.
|
||||
@end menu
|
||||
|
||||
|
@ -4684,6 +4685,7 @@ Return the frame's symtab and line object.
|
|||
@xref{Symbol Tables In Python}.
|
||||
@end defun
|
||||
|
||||
@anchor{gdbpy_frame_read_register}
|
||||
@defun Frame.read_register (register)
|
||||
Return the value of @var{register} in this frame. The @var{register}
|
||||
argument must be a string (e.g., @code{'sp'} or @code{'rax'}).
|
||||
|
@ -5715,6 +5717,37 @@ instruction in bytes.
|
|||
@end table
|
||||
@end defun
|
||||
|
||||
@anchor{gdbpy_architecture_registers}
|
||||
@defun Architecture.registers (@r{[} @var{reggroup} @r{]})
|
||||
Return a @code{gdb.RegisterDescriptorIterator} (@pxref{Registers In
|
||||
Python}) for all of the registers in @var{reggroup}, a string that is
|
||||
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
|
||||
|
||||
@node Registers In Python
|
||||
@subsubsection Registers In Python
|
||||
@cindex Registers In Python
|
||||
|
||||
Python code can request from a @code{gdb.Architecture} information
|
||||
about the set of registers available
|
||||
(@pxref{gdbpy_architecture_registers,,@code{Architecture.registers}}).
|
||||
The register information is returned as a
|
||||
@code{gdb.RegisterDescriptorIterator}, which is an iterator that in
|
||||
turn returns @code{gdb.RegisterDescriptor} objects.
|
||||
|
||||
A @code{gdb.RegisterDescriptor} does not provide the value of a
|
||||
register (@pxref{gdbpy_frame_read_register,,@code{Frame.read_register}}
|
||||
for reading a register's value), instead the @code{RegisterDescriptor}
|
||||
is a way to discover which registers are available for a particular
|
||||
architecture.
|
||||
|
||||
A @code{gdb.RegisterDescriptor} has the following read-only properties:
|
||||
|
||||
@defvar RegisterDescriptor.name
|
||||
The name of this register.
|
||||
@end defvar
|
||||
|
||||
@node TUI Windows In Python
|
||||
@subsubsection Implementing new TUI windows
|
||||
@cindex Python TUI Windows
|
||||
|
|
|
@ -226,6 +226,28 @@ archpy_disassemble (PyObject *self, PyObject *args, PyObject *kw)
|
|||
return result_list.release ();
|
||||
}
|
||||
|
||||
/* Implementation of gdb.Architecture.registers (self, reggroup) -> Iterator.
|
||||
Returns an iterator over register descriptors for registers in GROUP
|
||||
within the architecture SELF. */
|
||||
|
||||
static PyObject *
|
||||
archpy_registers (PyObject *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
static const char *keywords[] = { "reggroup", NULL };
|
||||
struct gdbarch *gdbarch = NULL;
|
||||
const char *group_name = NULL;
|
||||
|
||||
/* Parse method arguments. */
|
||||
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "|s", keywords,
|
||||
&group_name))
|
||||
return NULL;
|
||||
|
||||
/* Extract the gdbarch from the self object. */
|
||||
ARCHPY_REQUIRE_VALID (self, gdbarch);
|
||||
|
||||
return gdbpy_new_register_descriptor_iterator (gdbarch, group_name);
|
||||
}
|
||||
|
||||
/* Initializes the Architecture class in the gdb module. */
|
||||
|
||||
int
|
||||
|
@ -249,6 +271,11 @@ Return the name of the architecture as a string value." },
|
|||
"disassemble (start_pc [, end_pc [, count]]) -> List.\n\
|
||||
Return a list of at most COUNT disassembled instructions from START_PC to\n\
|
||||
END_PC." },
|
||||
{ "registers", (PyCFunction) archpy_registers,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
"registers ([ group-name ]) -> Iterator.\n\
|
||||
Return an iterator of register descriptors for the registers in register\n\
|
||||
group GROUP-NAME." },
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
|
269
gdb/python/py-registers.c
Normal file
269
gdb/python/py-registers.c
Normal file
|
@ -0,0 +1,269 @@
|
|||
/* 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 */
|
||||
};
|
|
@ -473,6 +473,9 @@ PyObject *gdbpy_lookup_objfile (PyObject *self, PyObject *args, PyObject *kw);
|
|||
|
||||
PyObject *gdbarch_to_arch_object (struct gdbarch *gdbarch);
|
||||
|
||||
PyObject *gdbpy_new_register_descriptor_iterator (struct gdbarch *gdbarch,
|
||||
const char *group_name);
|
||||
|
||||
gdbpy_ref<thread_object> create_thread_object (struct thread_info *tp);
|
||||
gdbpy_ref<> thread_to_thread_object (thread_info *thr);;
|
||||
gdbpy_ref<inferior_object> inferior_to_inferior_object (inferior *inf);
|
||||
|
@ -540,6 +543,8 @@ int gdbpy_initialize_py_events (void)
|
|||
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
|
||||
int gdbpy_initialize_arch (void)
|
||||
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
|
||||
int gdbpy_initialize_registers ()
|
||||
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
|
||||
int gdbpy_initialize_xmethods (void)
|
||||
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
|
||||
int gdbpy_initialize_unwind (void)
|
||||
|
|
|
@ -1759,6 +1759,7 @@ do_start_initialization ()
|
|||
|| gdbpy_initialize_py_events () < 0
|
||||
|| gdbpy_initialize_event () < 0
|
||||
|| gdbpy_initialize_arch () < 0
|
||||
|| gdbpy_initialize_registers () < 0
|
||||
|| gdbpy_initialize_xmethods () < 0
|
||||
|| gdbpy_initialize_unwind () < 0
|
||||
|| gdbpy_initialize_tui () < 0)
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* gdb.python/py-arch-reg-names.exp: New file.
|
||||
|
||||
2020-07-06 Andrew Burgess <andrew.burgess@embecosm.com>
|
||||
|
||||
* gdb.python/py-unwind.py (TestUnwinder::__call__): Add test for
|
||||
|
|
87
gdb/testsuite/gdb.python/py-arch-reg-names.exp
Normal file
87
gdb/testsuite/gdb.python/py-arch-reg-names.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.registers 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 'info registers' to get a list of register names.
|
||||
set regs {}
|
||||
gdb_test_multiple "info registers general" "info registers general" {
|
||||
-re "^info registers general\r\n" {
|
||||
exp_continue
|
||||
}
|
||||
-re "^(\[^ \t\]+)\[ \t\]+\[^\r\n\]+\r\n" {
|
||||
set reg $expect_out(1,string)
|
||||
lappend regs $reg
|
||||
exp_continue
|
||||
}
|
||||
-re "^$gdb_prompt " {
|
||||
}
|
||||
}
|
||||
gdb_assert {[llength $regs] > 0} \
|
||||
"Found at least one register"
|
||||
|
||||
# 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 regs = list (arch.registers (\"general\"))" \
|
||||
"get general registers" 0
|
||||
gdb_py_test_silent_cmd \
|
||||
"python regs = map (lambda r : r.name, regs)" \
|
||||
"get names of general registers" 0
|
||||
|
||||
set py_regs {}
|
||||
gdb_test_multiple "python print (\"\\n\".join (regs))" \
|
||||
"general register from python" {
|
||||
-re "^python print \[^\r\n\]+\r\n" {
|
||||
exp_continue
|
||||
}
|
||||
-re "^(\[^\r\n\]+)\r\n" {
|
||||
set reg $expect_out(1,string)
|
||||
lappend py_regs $reg
|
||||
exp_continue
|
||||
}
|
||||
-re "^$gdb_prompt " {
|
||||
}
|
||||
}
|
||||
|
||||
gdb_assert {[llength $py_regs] > 0} \
|
||||
"Found at least one register from python"
|
||||
gdb_assert {[llength $py_regs] == [llength $regs]} \
|
||||
"Same numnber of registers found"
|
||||
|
||||
set found_non_match 0
|
||||
for { set i 0 } { $i < [llength $regs] } { incr i } {
|
||||
if {[lindex $regs $i] != [lindex $py_regs $i]} {
|
||||
set found_non_match 1
|
||||
}
|
||||
}
|
||||
gdb_assert { $found_non_match == 0 } "all registers match"
|
Loading…
Add table
Add a link
Reference in a new issue