Pārlūkot izejas kodu

tests/tcg: finesse the registers check for "hidden" regs

The reason the ppc64 and s390x test where failing was because gdb
hides them although they are still accessible via regnum. We can
re-arrange the test a little bit and include these two arches in our
test.

We also need to be a bit more careful handling remote-registers as the
format isn't easily parsed with pure white space separation. Once we
fold types like "long long" and "long double" into a single word we
can now assert all registers are either listed or elided.

Cc: Ilya Leoshkevich <iii@linux.ibm.com>
Cc:  <qemu-s390x@nongnu.org>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Daniel Henrique Barboza <danielhb413@gmail.com>
Cc:  <qemu-ppc@nongnu.org>
Cc: Luis Machado <luis.machado@arm.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20231121153606.542101-1-alex.bennee@linaro.org>
Alex Bennée 1 gadu atpakaļ
vecāks
revīzija
6ef164188d

+ 69 - 26
tests/tcg/multiarch/gdbstub/registers.py

@@ -44,7 +44,6 @@ def fetch_xml_regmap():
 
 
     total_regs = 0
     total_regs = 0
     reg_map = {}
     reg_map = {}
-    frame = gdb.selected_frame()
 
 
     tree = ET.fromstring(xml)
     tree = ET.fromstring(xml)
     for f in tree.findall("feature"):
     for f in tree.findall("feature"):
@@ -61,12 +60,8 @@ def fetch_xml_regmap():
         for r in regs:
         for r in regs:
             name = r.attrib["name"]
             name = r.attrib["name"]
             regnum = int(r.attrib["regnum"])
             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:
             if name in reg_map:
                 report(False, f"duplicate register {entry} vs {reg_map[name]}")
                 report(False, f"duplicate register {entry} vs {reg_map[name]}")
@@ -80,6 +75,15 @@ def fetch_xml_regmap():
 
 
     return reg_map
     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):
 def crosscheck_remote_xml(reg_map):
     """
     """
     Cross-check the list of remote-registers with the XML info.
     Cross-check the list of remote-registers with the XML info.
@@ -90,8 +94,11 @@ def crosscheck_remote_xml(reg_map):
 
 
     total_regs = len(reg_map.keys())
     total_regs = len(reg_map.keys())
     total_r_regs = 0
     total_r_regs = 0
+    total_r_elided_regs = 0
 
 
     for r in r_regs:
     for r in r_regs:
+        r = r.replace("long long", "long_long")
+        r = r.replace("long double", "long_double")
         fields = r.split()
         fields = r.split()
         # Some of the registers reported here are "pseudo" registers that
         # Some of the registers reported here are "pseudo" registers that
         # gdb invents based on actual registers so we need to filter them
         # gdb invents based on actual registers so we need to filter them
@@ -100,6 +107,15 @@ def crosscheck_remote_xml(reg_map):
             r_name = fields[0]
             r_name = fields[0]
             r_regnum = int(fields[6])
             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
             # check in the XML
             try:
             try:
                 x_reg = reg_map[r_name]
                 x_reg = reg_map[r_name]
@@ -114,17 +130,42 @@ def crosscheck_remote_xml(reg_map):
             else:
             else:
                 total_r_regs += 1
                 total_r_regs += 1
 
 
-    # Just print a mismatch in totals as gdb will filter out 64 bit
-    # 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")
+    report(total_regs == total_r_regs + total_r_elided_regs,
+           "All XML Registers accounted for")
+
+    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 "hidden" in x_reg:
+            print(f"{x_reg} elided by gdb")
+        elif "seen" not in x_reg:
+            print(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)
+                e["initial"] = value
+            elif "seen" in e:
+                value = frame.read_register(name)
+                e["initial"] = value
+
+        except ValueError:
+                report(False, f"failed to read reg: {name}")
 
 
-        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")
 
 
 def complete_and_diff(reg_map):
 def complete_and_diff(reg_map):
     """
     """
@@ -144,18 +185,19 @@ def complete_and_diff(reg_map):
     changed = 0
     changed = 0
 
 
     for e in reg_map.values():
     for e in reg_map.values():
-        name = e["name"]
-        old_val = e["initial"]
+        if "initial" in e and "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
     # as long as something changed we can be confident its working
     report(changed > 0, f"{changed} registers were changed")
     report(changed > 0, f"{changed} registers were changed")
@@ -168,6 +210,7 @@ def run_test():
 
 
     if reg_map is not None:
     if reg_map is not None:
         crosscheck_remote_xml(reg_map)
         crosscheck_remote_xml(reg_map)
+        initial_register_read(reg_map)
         complete_and_diff(reg_map)
         complete_and_diff(reg_map)
 
 
 
 

+ 0 - 7
tests/tcg/ppc64/Makefile.target

@@ -43,11 +43,4 @@ PPC64_TESTS += signal_save_restore_xer
 PPC64_TESTS += xxspltw
 PPC64_TESTS += xxspltw
 PPC64_TESTS += test-aes
 PPC64_TESTS += test-aes
 
 
-ifneq ($(GDB),)
-# Skip for now until vsx registers sorted out
-run-gdbstub-registers:
-	$(call skip-test, $<, "BROKEN reading VSX registers")
-endif
-
-
 TESTS += $(PPC64_TESTS)
 TESTS += $(PPC64_TESTS)

+ 0 - 4
tests/tcg/s390x/Makefile.target

@@ -103,10 +103,6 @@ run-gdbstub-svc: hello-s390x-asm
 		--bin $< --test $(S390X_SRC)/gdbstub/test-svc.py, \
 		--bin $< --test $(S390X_SRC)/gdbstub/test-svc.py, \
 	single-stepping svc)
 	single-stepping svc)
 
 
-# Skip for now until vx registers sorted out
-run-gdbstub-registers:
-	$(call skip-test, $<, "BROKEN reading VX registers")
-
 EXTRA_RUNS += run-gdbstub-signals-s390x run-gdbstub-svc
 EXTRA_RUNS += run-gdbstub-signals-s390x run-gdbstub-svc
 endif
 endif