aboutsummaryrefslogtreecommitdiff
path: root/gdb/python
diff options
context:
space:
mode:
authorAndrew Burgess <andrew.burgess@embecosm.com>2020-07-22 12:13:11 +0100
committerAndrew Burgess <andrew.burgess@embecosm.com>2020-07-28 10:27:54 +0100
commit43d5901dedc7d0eefd7b677f555a4cbf470ee455 (patch)
tree3de8979071da95938c825d591c4ced4ca321cccc /gdb/python
parent14fa8fb3073dfdb8736ccf6bde6572d8b226c4cf (diff)
downloadfsf-binutils-gdb-43d5901dedc7d0eefd7b677f555a4cbf470ee455.zip
fsf-binutils-gdb-43d5901dedc7d0eefd7b677f555a4cbf470ee455.tar.gz
fsf-binutils-gdb-43d5901dedc7d0eefd7b677f555a4cbf470ee455.tar.bz2
gdb/python: make more use of RegisterDescriptors
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.
Diffstat (limited to 'gdb/python')
-rw-r--r--gdb/python/py-frame.c22
-rw-r--r--gdb/python/py-registers.c53
-rw-r--r--gdb/python/py-unwind.c36
-rw-r--r--gdb/python/python-internal.h19
4 files changed, 86 insertions, 44 deletions
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index 3fd1e7f..e121afb 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -27,7 +27,6 @@
#include "python-internal.h"
#include "symfile.h"
#include "objfiles.h"
-#include "user-regs.h"
typedef struct {
PyObject_HEAD
@@ -242,12 +241,11 @@ frapy_pc (PyObject *self, PyObject *args)
static PyObject *
frapy_read_register (PyObject *self, PyObject *args)
{
- const char *regnum_str;
+ PyObject *pyo_reg_id;
struct value *val = NULL;
- if (!PyArg_ParseTuple (args, "s", &regnum_str))
+ if (!PyArg_UnpackTuple (args, "read_register", 1, 1, &pyo_reg_id))
return NULL;
-
try
{
struct frame_info *frame;
@@ -255,14 +253,18 @@ frapy_read_register (PyObject *self, PyObject *args)
FRAPY_REQUIRE_VALID (self, frame);
- regnum = user_reg_map_name_to_regnum (get_frame_arch (frame),
- regnum_str,
- strlen (regnum_str));
- if (regnum >= 0)
- val = value_of_register (regnum, frame);
+ if (!gdbpy_parse_register_id (get_frame_arch (frame), pyo_reg_id,
+ &regnum))
+ {
+ PyErr_SetString (PyExc_ValueError, "Bad register");
+ return NULL;
+ }
+
+ gdb_assert (regnum >= 0);
+ val = value_of_register (regnum, frame);
if (val == NULL)
- PyErr_SetString (PyExc_ValueError, _("Unknown register."));
+ PyErr_SetString (PyExc_ValueError, _("Can't read register."));
}
catch (const gdb_exception &except)
{
diff --git a/gdb/python/py-registers.c b/gdb/python/py-registers.c
index fffe3ec..516d43d 100644
--- a/gdb/python/py-registers.c
+++ b/gdb/python/py-registers.c
@@ -370,6 +370,59 @@ register_descriptor_iter_find (PyObject *self, PyObject *args, PyObject *kw)
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 *) &register_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
diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c
index 1cef491..55d6a31 100644
--- a/gdb/python/py-unwind.c
+++ b/gdb/python/py-unwind.c
@@ -27,7 +27,6 @@
#include "python-internal.h"
#include "regcache.h"
#include "valprint.h"
-#include "user-regs.h"
#define TRACE_PY_UNWIND(level, args...) if (pyuw_debug >= level) \
{ fprintf_unfiltered (gdb_stdlog, args); }
@@ -101,37 +100,6 @@ static unsigned int pyuw_debug = 0;
static struct gdbarch_data *pyuw_gdbarch_data;
-/* Parses register id, which can be either a number or a name.
- Returns 1 on success, 0 otherwise. */
-
-static int
-pyuw_parse_register_id (struct gdbarch *gdbarch, PyObject *pyo_reg_id,
- int *reg_num)
-{
- if (pyo_reg_id == NULL)
- return 0;
- 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)
- return 0;
- *reg_num = user_reg_map_name_to_regnum (gdbarch, reg_name.get (),
- strlen (reg_name.get ()));
- return *reg_num >= 0;
- }
- else if (PyInt_Check (pyo_reg_id))
- {
- long value;
- if (gdb_py_int_as_long (pyo_reg_id, &value) && (int) value == value)
- {
- *reg_num = (int) value;
- return user_reg_map_regnum_to_name (gdbarch, *reg_num) != NULL;
- }
- }
- return 0;
-}
-
/* Convert gdb.Value instance to inferior's pointer. Return 1 on success,
0 on failure. */
@@ -275,7 +243,7 @@ unwind_infopy_add_saved_register (PyObject *self, PyObject *args)
if (!PyArg_UnpackTuple (args, "previous_frame_register", 2, 2,
&pyo_reg_id, &pyo_reg_value))
return NULL;
- if (!pyuw_parse_register_id (pending_frame->gdbarch, pyo_reg_id, &regnum))
+ if (!gdbpy_parse_register_id (pending_frame->gdbarch, pyo_reg_id, &regnum))
{
PyErr_SetString (PyExc_ValueError, "Bad register");
return NULL;
@@ -376,7 +344,7 @@ pending_framepy_read_register (PyObject *self, PyObject *args)
}
if (!PyArg_UnpackTuple (args, "read_register", 1, 1, &pyo_reg_id))
return NULL;
- if (!pyuw_parse_register_id (pending_frame->gdbarch, pyo_reg_id, &regnum))
+ if (!gdbpy_parse_register_id (pending_frame->gdbarch, pyo_reg_id, &regnum))
{
PyErr_SetString (PyExc_ValueError, "Bad register");
return NULL;
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 1e6dcf3..6874543 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -776,4 +776,23 @@ struct Py_buffer_deleter
/* A unique_ptr specialization for Py_buffer. */
typedef std::unique_ptr<Py_buffer, Py_buffer_deleter> Py_buffer_up;
+/* Parse a register number from PYO_REG_ID and place the register number
+ into *REG_NUM. The register is a register for GDBARCH.
+
+ If a register is parsed successfully then *REG_NUM will have been
+ updated, and true is returned. Otherwise the contents of *REG_NUM are
+ undefined, and false is returned.
+
+ The PYO_REG_ID object can be a string, the name of the register. This
+ is the slowest approach as GDB has to map the name to a number for each
+ call. Alternatively PYO_REG_ID can be an internal GDB register
+ number. This is quick but should not be encouraged as this means
+ Python scripts are now dependent on GDB's internal register numbering.
+ Final PYO_REG_ID can be a gdb.RegisterDescriptor object, these objects
+ can be looked up by name once, and then cache the register number so
+ should be as quick as using a register number. */
+
+extern bool gdbpy_parse_register_id (struct gdbarch *gdbarch,
+ PyObject *pyo_reg_id, int *reg_num);
+
#endif /* PYTHON_PYTHON_INTERNAL_H */