diff options
author | Alex Bennée <alex.bennee@linaro.org> | 2021-01-08 22:42:41 +0000 |
---|---|---|
committer | Alex Bennée <alex.bennee@linaro.org> | 2021-01-18 10:04:31 +0000 |
commit | c00506aa26e975918483d0d1fe17a2192d19098a (patch) | |
tree | 761a7ab40fab085ac63390e29168b2bee1112ec3 /tests/tcg/multiarch | |
parent | 9559150e86518d0c7f4eb864e525b6e385fa8a4d (diff) | |
download | qemu-c00506aa26e975918483d0d1fe17a2192d19098a.zip qemu-c00506aa26e975918483d0d1fe17a2192d19098a.tar.gz qemu-c00506aa26e975918483d0d1fe17a2192d19098a.tar.bz2 |
gdbstub: implement a softmmu based test
This adds a new tests that allows us to test softmmu only features
including watchpoints. To do achieve this we need to:
- add _exit: labels to the boot codes
- write a memory.py test case
- plumb the test case into the build system
- tweak the run_test script to:
- re-direct output when asked
- use socket based connection for all tests
- add a small pause before connection
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Message-Id: <20210108224256.2321-6-alex.bennee@linaro.org>
Diffstat (limited to 'tests/tcg/multiarch')
-rw-r--r-- | tests/tcg/multiarch/gdbstub/memory.py | 130 | ||||
-rw-r--r-- | tests/tcg/multiarch/system/Makefile.softmmu-target | 19 |
2 files changed, 148 insertions, 1 deletions
diff --git a/tests/tcg/multiarch/gdbstub/memory.py b/tests/tcg/multiarch/gdbstub/memory.py new file mode 100644 index 0000000..67864ad --- /dev/null +++ b/tests/tcg/multiarch/gdbstub/memory.py @@ -0,0 +1,130 @@ +from __future__ import print_function +# +# Test some of the softmmu debug features with the multiarch memory +# test. It is a port of the original vmlinux focused test case but +# using the "memory" test instead. +# +# This is launched via tests/guest-debug/run-test.py +# + +import gdb +import sys + +failcount = 0 + + +def report(cond, msg): + "Report success/fail of test" + if cond: + print("PASS: %s" % (msg)) + else: + print("FAIL: %s" % (msg)) + global failcount + failcount += 1 + + +def check_step(): + "Step an instruction, check it moved." + start_pc = gdb.parse_and_eval('$pc') + gdb.execute("si") + end_pc = gdb.parse_and_eval('$pc') + + return not (start_pc == end_pc) + + +# +# Currently it's hard to create a hbreak with the pure python API and +# manually matching PC to symbol address is a bit flaky thanks to +# function prologues. However internally QEMU's gdbstub treats them +# the same as normal breakpoints so it will do for now. +# +def check_break(sym_name): + "Setup breakpoint, continue and check we stopped." + sym, ok = gdb.lookup_symbol(sym_name) + bp = gdb.Breakpoint(sym_name, gdb.BP_BREAKPOINT) + + gdb.execute("c") + + # hopefully we came back + end_pc = gdb.parse_and_eval('$pc') + report(bp.hit_count == 1, + "break @ %s (%s %d hits)" % (end_pc, sym.value(), bp.hit_count)) + + bp.delete() + + +def do_one_watch(sym, wtype, text): + + wp = gdb.Breakpoint(sym, gdb.BP_WATCHPOINT, wtype) + gdb.execute("c") + report_str = "%s for %s" % (text, sym) + + if wp.hit_count > 0: + report(True, report_str) + wp.delete() + else: + report(False, report_str) + + +def check_watches(sym_name): + "Watch a symbol for any access." + + # Should hit for any read + do_one_watch(sym_name, gdb.WP_ACCESS, "awatch") + + # Again should hit for reads + do_one_watch(sym_name, gdb.WP_READ, "rwatch") + + # Finally when it is written + do_one_watch(sym_name, gdb.WP_WRITE, "watch") + + +def run_test(): + "Run through the tests one by one" + + print("Checking we can step the first few instructions") + step_ok = 0 + for i in range(3): + if check_step(): + step_ok += 1 + + report(step_ok == 3, "single step in boot code") + + # If we get here we have missed some of the other breakpoints. + print("Setup catch-all for _exit") + cbp = gdb.Breakpoint("_exit", gdb.BP_BREAKPOINT) + + check_break("main") + check_watches("test_data[128]") + + report(cbp.hit_count == 0, "didn't reach backstop") + +# +# This runs as the script it sourced (via -x, via run-test.py) +# +try: + inferior = gdb.selected_inferior() + arch = inferior.architecture() + print("ATTACHED: %s" % arch.name()) +except (gdb.error, AttributeError): + print("SKIPPING (not connected)", file=sys.stderr) + exit(0) + +if gdb.parse_and_eval('$pc') == 0: + print("SKIP: PC not set") + exit(0) + +try: + # These are not very useful in scripts + gdb.execute("set pagination off") + + # Run the actual tests + run_test() +except (gdb.error): + print("GDB Exception: %s" % (sys.exc_info()[0])) + failcount += 1 + pass + +# Finally kill the inferior and exit gdb with a count of failures +gdb.execute("kill") +exit(failcount) diff --git a/tests/tcg/multiarch/system/Makefile.softmmu-target b/tests/tcg/multiarch/system/Makefile.softmmu-target index db4bbed..4657f6e 100644 --- a/tests/tcg/multiarch/system/Makefile.softmmu-target +++ b/tests/tcg/multiarch/system/Makefile.softmmu-target @@ -7,8 +7,25 @@ # complications of building. # -MULTIARCH_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/multiarch/system +MULTIARCH_SRC=$(SRC_PATH)/tests/tcg/multiarch +MULTIARCH_SYSTEM_SRC=$(MULTIARCH_SRC)/system VPATH+=$(MULTIARCH_SYSTEM_SRC) MULTIARCH_TEST_SRCS=$(wildcard $(MULTIARCH_SYSTEM_SRC)/*.c) MULTIARCH_TESTS = $(patsubst $(MULTIARCH_SYSTEM_SRC)/%.c, %, $(MULTIARCH_TEST_SRCS)) + +ifneq ($(HAVE_GDB_BIN),) +GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py + +run-gdbstub-memory: memory + $(call run-test, $@, $(GDB_SCRIPT) \ + --gdb $(HAVE_GDB_BIN) \ + --qemu $(QEMU) \ + --output $<.gdb.out \ + --qargs \ + "-monitor none -display none -chardev file$(COMMA)path=$<.out$(COMMA)id=output $(QEMU_OPTS)" \ + --bin $< --test $(MULTIARCH_SRC)/gdbstub/memory.py, \ + "softmmu gdbstub support") + +MULTIARCH_RUNS += run-gdbstub-memory +endif |