mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-09 02:24:58 -06:00

Both the report() function as well as the initial gdbstub test sequence are copy-pasted into ~10 files with slight modifications. This indicates that they are indeed generic, so factor them out. While at it, add a few newlines to make the formatting closer to PEP-8. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20240129093410.3151-3-iii@linux.ibm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
211 lines
5.9 KiB
Python
211 lines
5.9 KiB
Python
# Exercise the register functionality by exhaustively iterating
|
|
# through all supported registers on the system.
|
|
#
|
|
# This is launched via tests/guest-debug/run-test.py but you can also
|
|
# call it directly if using it for debugging/introspection:
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
import gdb
|
|
import xml.etree.ElementTree as ET
|
|
from test_gdbstub import main, report
|
|
|
|
|
|
initial_vlen = 0
|
|
|
|
|
|
def fetch_xml_regmap():
|
|
"""
|
|
Iterate through the XML descriptions and validate.
|
|
|
|
We check for any duplicate registers and report them. Return a
|
|
reg_map hash containing the names, regnums and initial values of
|
|
all registers.
|
|
"""
|
|
|
|
# First check the XML descriptions we have sent. Most arches
|
|
# support XML but a few of the ancient ones don't in which case we
|
|
# need to gracefully fail.
|
|
|
|
try:
|
|
xml = gdb.execute("maint print xml-tdesc", False, True)
|
|
except (gdb.error):
|
|
print("SKIP: target does not support XML")
|
|
return None
|
|
|
|
total_regs = 0
|
|
reg_map = {}
|
|
|
|
tree = ET.fromstring(xml)
|
|
for f in tree.findall("feature"):
|
|
name = f.attrib["name"]
|
|
regs = f.findall("reg")
|
|
|
|
total = len(regs)
|
|
total_regs += total
|
|
base = int(regs[0].attrib["regnum"])
|
|
top = int(regs[-1].attrib["regnum"])
|
|
|
|
print(f"feature: {name} has {total} registers from {base} to {top}")
|
|
|
|
for r in regs:
|
|
name = r.attrib["name"]
|
|
regnum = int(r.attrib["regnum"])
|
|
|
|
entry = { "name": name, "regnum": regnum }
|
|
|
|
if name in reg_map:
|
|
report(False, f"duplicate register {entry} vs {reg_map[name]}")
|
|
continue
|
|
|
|
reg_map[name] = entry
|
|
|
|
# Validate we match
|
|
report(total_regs == len(reg_map.keys()),
|
|
f"counted all {total_regs} registers in XML")
|
|
|
|
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.
|
|
"""
|
|
|
|
remote = gdb.execute("maint print remote-registers", False, True)
|
|
r_regs = remote.split("\n")
|
|
|
|
total_regs = len(reg_map.keys())
|
|
total_r_regs = 0
|
|
total_r_elided_regs = 0
|
|
|
|
for r in r_regs:
|
|
r = r.replace("long long", "long_long")
|
|
r = r.replace("long double", "long_double")
|
|
fields = r.split()
|
|
# Some of the registers reported here are "pseudo" registers that
|
|
# gdb invents based on actual registers so we need to filter them
|
|
# out.
|
|
if len(fields) == 8:
|
|
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]
|
|
except KeyError:
|
|
report(False, f"{r_name} not in XML description")
|
|
continue
|
|
|
|
x_reg["seen"] = True
|
|
x_regnum = x_reg["regnum"]
|
|
if r_regnum != x_regnum:
|
|
report(False, f"{r_name} {r_regnum} == {x_regnum} (xml)")
|
|
else:
|
|
total_r_regs += 1
|
|
|
|
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}")
|
|
|
|
|
|
def complete_and_diff(reg_map):
|
|
"""
|
|
Let the program run to (almost) completion and then iterate
|
|
through all the registers we know about and report which ones have
|
|
changed.
|
|
"""
|
|
# Let the program get to the end and we can check what changed
|
|
b = gdb.Breakpoint("_exit")
|
|
if b.pending: # workaround Microblaze weirdness
|
|
b.delete()
|
|
gdb.Breakpoint("_Exit")
|
|
|
|
gdb.execute("continue")
|
|
|
|
frame = gdb.selected_frame()
|
|
changed = 0
|
|
|
|
for e in reg_map.values():
|
|
if "initial" in e and "hidden" not in e:
|
|
name = e["name"]
|
|
old_val = e["initial"]
|
|
|
|
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
|
|
|
|
# as long as something changed we can be confident its working
|
|
report(changed > 0, f"{changed} registers were changed")
|
|
|
|
|
|
def run_test():
|
|
"Run through the tests"
|
|
|
|
reg_map = fetch_xml_regmap()
|
|
|
|
if reg_map is not None:
|
|
crosscheck_remote_xml(reg_map)
|
|
initial_register_read(reg_map)
|
|
complete_and_diff(reg_map)
|
|
|
|
|
|
main(run_test)
|