diff --git a/gdb/ChangeLog b/gdb/ChangeLog index b15a3a4e25f..e2d2e15b653 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,14 @@ +2020-07-21 Andrew Burgess + + * python/py-registers.c (gdbpy_register_object_data): New static + global. + (gdbpy_register_object_data_init): New function. + (gdbpy_new_register_descriptor): Renamed to... + (gdbpy_get_register_descriptor): ...this, and update to reuse + existing register descriptors where possible. + (gdbpy_register_descriptor_iter_next): Update. + (gdbpy_initialize_registers): Register new gdbarch data. + 2020-07-21 Simon Marchi * linux-nat.c (stopped_pids): Make static. diff --git a/gdb/python/py-registers.c b/gdb/python/py-registers.c index db0fe37eecb..8e22a919d87 100644 --- a/gdb/python/py-registers.c +++ b/gdb/python/py-registers.c @@ -24,6 +24,9 @@ #include "reggroups.h" #include "python-internal.h" +/* 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 @@ -81,6 +84,17 @@ typedef struct { 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) +{ + std::vector> *vec = new (std::vector>); + return (void *) vec; +} + /* Create a new gdb.RegisterGroup object wrapping REGGROUP. */ static PyObject * @@ -117,20 +131,38 @@ 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, +/* 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) { - /* 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; + auto vec = (std::vector> *) 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->at (regnum) == nullptr) + { + gdbpy_ref reg + (PyObject_New (register_descriptor_object, + ®ister_descriptor_object_type)); + if (reg == NULL) + return NULL; + reg->regnum = regnum; + reg->gdbarch = gdbarch; + vec->at (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->at (regnum); } /* Convert the register descriptor to a string. */ @@ -281,7 +313,7 @@ gdbpy_register_descriptor_iter_next (PyObject *self) iter_obj->regnum++; if (name != nullptr && *name != '\0') - return gdbpy_new_register_descriptor (gdbarch, regnum); + return gdbpy_get_register_descriptor (gdbarch, regnum).release (); } while (true); } @@ -291,6 +323,9 @@ gdbpy_register_descriptor_iter_next (PyObject *self) 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; diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 804df0264b5..6b13e928497 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2020-07-21 Andrew Burgess + + * gdb.python/py-arch-reg-names.exp: Additional tests. + 2020-07-21 Tom de Vries * gdb.reverse/solib-precsave.exp: Handle additional "recommended diff --git a/gdb/testsuite/gdb.python/py-arch-reg-names.exp b/gdb/testsuite/gdb.python/py-arch-reg-names.exp index 14bc0a822a4..8dd34ef5fd2 100644 --- a/gdb/testsuite/gdb.python/py-arch-reg-names.exp +++ b/gdb/testsuite/gdb.python/py-arch-reg-names.exp @@ -85,3 +85,22 @@ for { set i 0 } { $i < [llength $regs] } { incr i } { } } gdb_assert { $found_non_match == 0 } "all registers match" + +# Check that we get the same register descriptors from two different +# iterators. +gdb_py_test_silent_cmd \ + "python iter1 = arch.registers ()" \ + "get first all register iterator" 0 +gdb_py_test_silent_cmd \ + "python iter2 = arch.registers ()" \ + "get second all register iterator" 0 +gdb_py_test_silent_cmd \ + [multi_line_input \ + "python" \ + "for r1, r2 in zip(iter1, iter2):" \ + " if (r1.name != r2.name):"\ + " raise gdb.GdbError (\"miss-matched names\")" \ + " if (r1 != r2):" \ + " raise gdb.GdbError (\"miss-matched objects\")" \ + "\004" ] \ + "check names and objects match" 1