Mirror of the gdb mailing list
 help / color / mirror / Atom feed
From: "Alex Bennée via Gdb" <gdb@sourceware.org>
To: Luis Machado <luis.machado@arm.com>
Cc: "Nicholas Piggin" <npiggin@gmail.com>,
	qemu-devel@nongnu.org, "Akihiko Odaki" <akihiko.odaki@daynix.com>,
	"Luis Machado" <luis.machado@linaro.org>,
	"Ilya Leoshkevich" <iii@linux.ibm.com>,
	qemu-s390x@nongnu.org,
	"Daniel Henrique Barboza" <danielhb413@gmail.com>,
	qemu-ppc@nongnu.org, "Philippe Mathieu-Daudé" <philmd@linaro.org>,
	"Cédric Le Goater" <clg@kaod.org>,
	"Richard Henderson" <richard.henderson@linaro.org>,
	"David Hildenbrand" <david@redhat.com>,
	"gdb@gnu.org" <gdb@gnu.org>
Subject: Re: [PULL 06/23] tests/tcg: add an explicit gdbstub register tester
Date: Thu, 16 Nov 2023 14:59:07 +0000	[thread overview]
Message-ID: <87y1exu4lg.fsf@draig.linaro.org> (raw)
In-Reply-To: <37df0557-faf0-4667-925f-fcc7deac4f52@arm.com> (Luis Machado's message of "Thu, 16 Nov 2023 09:56:40 +0000")

Luis Machado <luis.machado@arm.com> writes:

> On 11/15/23 20:56, Alex Bennée via Gdb wrote:
>> "Nicholas Piggin" <npiggin@gmail.com> writes:
>>
>>> On Wed Nov 8, 2023 at 12:23 AM AEST, Alex Bennée wrote:
>>>> We already do a couple of "info registers" for specific tests but this
>>>> is a more comprehensive multiarch test. It also has some output
>>>> helpful for debugging the gdbstub by showing which XML features are
>>>> advertised and what the underlying register numbers are.
>>>>
>>>> My initial motivation was to see if there are any duplicate register
>>>> names exposed via the gdbstub while I was reviewing the proposed
>>>> register interface for TCG plugins.
>>>>
>>>> Mismatches between the xml and remote-desc are reported for debugging
>>>> but do not fail the test.
>>>>
>>>> We also skip the tests for the following arches for now until we can
>>>> investigate and fix any issues:
>>>>
>>>>   - s390x (fails to read v0l->v15l, not seen in remote-registers)
>>>>   - ppc64 (fails to read vs0h->vs31h, not seen in remote-registers)
>>>
>>> binutils-gdb.git/gdb/rs6000-tdep.c has:
>>>
>>> static const char *
>>> rs6000_register_name (struct gdbarch *gdbarch, int regno)
>>> {
>>>   ppc_gdbarch_tdep *tdep = (ppc_gdbarch_tdep *) gdbarch_tdep (gdbarch);
>>>
>>>   /* The upper half "registers" have names in the XML description,
>>>      but we present only the low GPRs and the full 64-bit registers
>>>      to the user.  */
>>>   if (tdep->ppc_ev0_upper_regnum >= 0
>>>       && tdep->ppc_ev0_upper_regnum <= regno
>>>       && regno < tdep->ppc_ev0_upper_regnum + ppc_num_gprs)
>>>     return "";
>>>
>>>   /* Hide the upper halves of the vs0~vs31 registers.  */
>>>   if (tdep->ppc_vsr0_regnum >= 0
>>>       && tdep->ppc_vsr0_upper_regnum <= regno
>>>       && regno < tdep->ppc_vsr0_upper_regnum + ppc_num_gprs)
>>>     return "";
>>>
>>> (s390 looks similar for V0-V15 lower).
>>>
>>> I guess it is because the upper half is not a real register but an
>>> extension of an existing FP register to make a vector register. I
>>> just don't know how that should be resolved with QEMU.
>>>
>>> Should we put an exception in the test case for these? Or is there
>>> something we should be doing differently with the XML regs?
>>
>> Yeah I suspect this is just inconsistency between targets on gdb. My
>> naive assumption was XML should match the displayed registers but it
>> seems there is additional filtering going on.
>>
>> It seems in this case the registers are still there and have regnums (so
>> I assume the stub could be asked for them) but the names have been
>> squashed. I guess we could detect that and accept it?
>>
>>>
>>> i386 gdb does similar:
>>>
>>> static const char *
>>> i386_register_name (struct gdbarch *gdbarch, int regnum)
>>> {
>>>   /* Hide the upper YMM registers.  */
>>>   if (i386_ymmh_regnum_p (gdbarch, regnum))
>>>     return "";
>>>
>>>   /* Hide the upper YMM16-31 registers.  */
>>>   if (i386_ymmh_avx512_regnum_p (gdbarch, regnum))
>>>     return "";
>>>
>>>   /* Hide the upper ZMM registers.  */
>>>   if (i386_zmmh_regnum_p (gdbarch, regnum))
>>>     return "";
>>>
>>>   return tdesc_register_name (gdbarch, regnum);
>>> }
>>>
>>> So, I'm not sure how they don't fail this test. Does QEMU just
>>> not have YMM/ZMM in XML regmap?
>>
>> No I think we only send the core one with XMM regs and there are no
>> additional registers sent via gdb_register_coprocessor.
>>
>>>
>>> Thanks,
>>> Nick
>
> FTR, luis.machado@linaro.org doesn't exist anymore.
>
> As for the XML, it serves as an architecture hint/description of what features and registers
> are available.
>
> GDB will process that and will potentially include additional pseudo-registers (so QEMU doesn't
> need to do so, unless it is some pseudo-register not accounted by gdb).
>
> The rest of the features/registers gdb doesn't care about, it will just add them to the end of the
> list, and will assign whatever number is next. GDB will be able to read/write them, but nothing more
> than that.

So with a bit of fiddling I can do:

modified   tests/tcg/multiarch/gdbstub/registers.py
@@ -44,7 +44,6 @@ def fetch_xml_regmap():
 
     total_regs = 0
     reg_map = {}
-    frame = gdb.selected_frame()
 
     tree = ET.fromstring(xml)
     for f in tree.findall("feature"):
@@ -61,12 +60,8 @@ def fetch_xml_regmap():
         for r in regs:
             name = r.attrib["name"]
             regnum = int(r.attrib["regnum"])
-            try:
-                value = frame.read_register(name)
-            except ValueError:
-                report(False, f"failed to read reg: {name}")
 
-            entry = { "name": name, "initial": value, "regnum": regnum }
+            entry = { "name": name, "regnum": regnum }
 
             if name in reg_map:
                 report(False, f"duplicate register {entry} vs {reg_map[name]}")
@@ -80,6 +75,15 @@ def fetch_xml_regmap():
 
     return reg_map
 
+def get_register_by_regnum(reg_map, regnum):
+    """
+    Helper to find a register from the map via its XML regnum
+    """
+    for regname, entry in reg_map.items():
+        if entry['regnum'] == regnum:
+            return entry
+    return None
+
 def crosscheck_remote_xml(reg_map):
     """
     Cross-check the list of remote-registers with the XML info.
@@ -90,6 +94,7 @@ def crosscheck_remote_xml(reg_map):
 
     total_regs = len(reg_map.keys())
     total_r_regs = 0
+    total_r_elided_regs = 0
 
     for r in r_regs:
         fields = r.split()
@@ -100,6 +105,15 @@ def crosscheck_remote_xml(reg_map):
             r_name = fields[0]
             r_regnum = int(fields[6])
 
+            # Some registers are "hidden" so don't have a name
+            # although they still should have a register number
+            if r_name == "''":
+                total_r_elided_regs += 1
+                x_reg = get_register_by_regnum(reg_map, r_regnum)
+                if x_reg is not None:
+                    x_reg["hidden"] = True
+                continue
+
             # check in the XML
             try:
                 x_reg = reg_map[r_name]
@@ -118,13 +132,38 @@ def crosscheck_remote_xml(reg_map):
     # registers on a 32 bit machine. Also print what is missing to
     # help with debug.
     if total_regs != total_r_regs:
-        print(f"xml-tdesc has ({total_regs}) registers")
-        print(f"remote-registers has ({total_r_regs}) registers")
+        print(f"xml-tdesc has {total_regs} registers")
+        print(f"remote-registers has {total_r_regs} registers")
+        print(f"of which {total_r_elided_regs} are hidden")
 
         for x_key in reg_map.keys():
             x_reg = reg_map[x_key]
-            if "seen" not in x_reg:
-                print(f"{x_reg} wasn't seen in remote-registers")
+            if "hidden" in x_reg:
+                print(f"{x_reg} elided by gdb")
+            elif "seen" not in x_reg:
+                report(False, f"{x_reg} wasn't seen in remote-registers")
+
+def initial_register_read(reg_map):
+    """
+    Do an initial read of all registers that we know gdb cares about
+    (so ignore the elided ones).
+    """
+    frame = gdb.selected_frame()
+
+    for e in reg_map.values():
+        name = e["name"]
+        regnum = e["regnum"]
+
+        try:
+            if "hidden" in e:
+                value = frame.read_register(regnum)
+            else:
+                value = frame.read_register(name)
+
+            e["initial"] = value
+        except ValueError:
+                report(False, f"failed to read reg: {name}")
+
 
 def complete_and_diff(reg_map):
     """
@@ -144,18 +183,19 @@ def complete_and_diff(reg_map):
     changed = 0
 
     for e in reg_map.values():
-        name = e["name"]
-        old_val = e["initial"]
+        if "hidden" not in e:
+            name = e["name"]
+            old_val = e["initial"]
 
-        try:
-            new_val = frame.read_register(name)
-        except:
-            report(False, f"failed to read {name} at end of run")
-            continue
+            try:
+                new_val = frame.read_register(name)
+            except ValueError:
+                report(False, f"failed to read {name} at end of run")
+                continue
 
-        if new_val != old_val:
-            print(f"{name} changes from {old_val} to {new_val}")
-            changed += 1
+            if new_val != old_val:
+                print(f"{name} changes from {old_val} to {new_val}")
+                changed += 1
 
     # as long as something changed we can be confident its working
     report(changed > 0, f"{changed} registers were changed")
@@ -168,6 +208,7 @@ def run_test():
 
     if reg_map is not None:
         crosscheck_remote_xml(reg_map)
+        initial_register_read(reg_map)
         complete_and_diff(reg_map)

I'll wrap that into my next set of patches.

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro

      reply	other threads:[~2023-11-16 14:59 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20231107142354.3151266-1-alex.bennee@linaro.org>
     [not found] ` <20231107142354.3151266-7-alex.bennee@linaro.org>
     [not found]   ` <CWXN9HF4AXGM.19H4A5BU366S1@wheely>
2023-11-15 20:56     ` Alex Bennée via Gdb
2023-11-16  9:56       ` Luis Machado via Gdb
2023-11-16 14:59         ` Alex Bennée via Gdb [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87y1exu4lg.fsf@draig.linaro.org \
    --to=gdb@sourceware.org \
    --cc=akihiko.odaki@daynix.com \
    --cc=alex.bennee@linaro.org \
    --cc=clg@kaod.org \
    --cc=danielhb413@gmail.com \
    --cc=david@redhat.com \
    --cc=gdb@gnu.org \
    --cc=iii@linux.ibm.com \
    --cc=luis.machado@arm.com \
    --cc=luis.machado@linaro.org \
    --cc=npiggin@gmail.com \
    --cc=philmd@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-ppc@nongnu.org \
    --cc=qemu-s390x@nongnu.org \
    --cc=richard.henderson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox