From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-x441.google.com (mail-wr1-x441.google.com [IPv6:2a00:1450:4864:20::441]) by sourceware.org (Postfix) with ESMTPS id A82113939C29 for ; Wed, 17 Jun 2020 17:38:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org A82113939C29 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=andrew.burgess@embecosm.com Received: by mail-wr1-x441.google.com with SMTP id t13so819514wrs.2 for ; Wed, 17 Jun 2020 10:38:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ECIf2lMU5I27hVY2S1TNozAIhuT3kajY6jaA5cepaLA=; b=Gr8khgU+AbNr5WcmYVRWukp4La1HxbQcA/LmcRO1+x7O0ZvDuBDZi760NfljqRCK5k Ro8bN+3eGQHLEQzfajnY4XMG2w5+sie+/O6Hi1JjSuRW39hH2lYGVmlUp5FC962P2ih+ wwaacmT6B6z2kDltOaelXVOgh4t8zGO1A04+rZ6B7+kZPLgEMuNc4J+j5d+iJphj7QCL E6ax9HD4OZmV5xLo1cPjux9q0vBqX/kDCWRyZUbCYWi5bKGgAxRAMUMzzICLan1n65Xw KBlp2Ya1uAtVQyvv9HsBFKwxYy6d/chBaR5dPXfFBzNnvcGvOr0U1qS6/a6S9BnUCdrl z28A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ECIf2lMU5I27hVY2S1TNozAIhuT3kajY6jaA5cepaLA=; b=gP1Oyq5B5NDiaTi8so68DqNwZCOKBcyn15lNxGr1DJjCZMNvwvaDKGJPnsIRonYbpD 989xbECmRR+iYVvMaNkyWS4RHE6OrqDP/hpVNTEIFdBTFX0MRCjzeLCbL/S+h6lmD8lk cA5DHEgcSJjA8cieBgscAs2SqljOMVlP/ME7P629R7Uu+3Yg4Hlnn9tzQUROKBf21N61 Uv4+JSembJazh701igfLh7CrTx7VoxsWjdORXDvpdcyTmCp8D62QYkwrrNbRe83vErux ISwuoiGLlT/XndoVhMcWqsUo/8g0N4/CVfpQuwjSw+UtRcGXKGGOC3wl16DHMRdYjysI iAxQ== X-Gm-Message-State: AOAM530hU/+sKzXEnJrZaUtIaxChXbnfsgAOxopMaahD25O9aRuEn/XG LREgSFWf0c7vrrPmSD+6O6qV1QLrnuI= X-Google-Smtp-Source: ABdhPJxdEThU/SPh591ne//Z3IqWWgMrQT2CdB6fDn9Tyh/tOBBu0mOlaYx5EDf3ECiRAAbmu0Wsgw== X-Received: by 2002:a5d:6109:: with SMTP id v9mr404028wrt.26.1592415500173; Wed, 17 Jun 2020 10:38:20 -0700 (PDT) Received: from localhost (host86-128-12-16.range86-128.btcentralplus.com. [86.128.12.16]) by smtp.gmail.com with ESMTPSA id a3sm291265wrp.91.2020.06.17.10.38.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 17 Jun 2020 10:38:19 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Subject: [PATCH 4/5] gdb/python: New method to access list of register groups Date: Wed, 17 Jun 2020 18:38:08 +0100 Message-Id: <360af15dc7ea2e2e20f2b9ff6529467b7e0a0614.1592415322.git.andrew.burgess@embecosm.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-9.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 17 Jun 2020 17:38:24 -0000 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 ' command. * python.texi (Architectures In Python): Document new register_groups method. (Registers In Python): Document two new object types related to register groups. --- gdb/ChangeLog | 19 ++ gdb/NEWS | 5 + gdb/doc/ChangeLog | 9 + gdb/doc/gdb.texinfo | 1 + gdb/doc/python.texi | 32 +++ gdb/python/py-arch.c | 18 ++ gdb/python/py-registers.c | 195 ++++++++++++++++++ gdb/python/python-internal.h | 1 + gdb/testsuite/ChangeLog | 4 + .../gdb.python/py-arch-reg-groups.exp | 87 ++++++++ 10 files changed, 371 insertions(+) create mode 100644 gdb/testsuite/gdb.python/py-arch-reg-groups.exp diff --git a/gdb/NEWS b/gdb/NEWS index 0dc467dc95e..1c684427b1d 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -101,6 +101,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. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 59e3e75d18a..56cd10ec2e2 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -12344,6 +12344,7 @@ 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 diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index 7503063af61..6ecc3ea63f0 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -5725,6 +5725,13 @@ empty string, then the register group @dfn{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 @@ -5747,6 +5754,31 @@ 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 diff --git a/gdb/python/py-arch.c b/gdb/python/py-arch.c index 15f9f50d7d7..d9eaf81a30a 100644 --- a/gdb/python/py-arch.c +++ b/gdb/python/py-arch.c @@ -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 */ }; diff --git a/gdb/python/py-registers.c b/gdb/python/py-registers.c index b78e7426c98..3a6bc276d5b 100644 --- a/gdb/python/py-registers.c +++ b/gdb/python/py-registers.c @@ -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 (void) (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 */ +}; diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 91cac319059..3f4fd2a886d 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -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 create_thread_object (struct thread_info *tp); gdbpy_ref<> thread_to_thread_object (thread_info *thr);; diff --git a/gdb/testsuite/gdb.python/py-arch-reg-groups.exp b/gdb/testsuite/gdb.python/py-arch-reg-groups.exp new file mode 100644 index 00000000000..ea9aa77b0fa --- /dev/null +++ b/gdb/testsuite/gdb.python/py-arch-reg-groups.exp @@ -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 . + +# 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" -- 2.25.4