Message ID | 20210804225146.154513-1-iii@linux.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v8] tests/tcg/s390x: Test SIGILL and SIGSEGV handling | expand |
On 05.08.21 00:51, Ilya Leoshkevich wrote: > Verify that s390x-specific uc_mcontext.psw.addr is reported correctly > and that signal handling interacts properly with debugging. > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> > --- > > v7: https://lists.nongnu.org/archive/html/qemu-devel/2021-08/msg00463.html > v7 -> v8: Another rebase needed due to the conflict with Jonathan's > 50e36dd61652. > > tests/tcg/s390x/Makefile.target | 17 +- > tests/tcg/s390x/gdbstub/test-signals-s390x.py | 76 ++++++++ > tests/tcg/s390x/signals-s390x.c | 165 ++++++++++++++++++ > 3 files changed, 257 insertions(+), 1 deletion(-) > create mode 100644 tests/tcg/s390x/gdbstub/test-signals-s390x.py > create mode 100644 tests/tcg/s390x/signals-s390x.c > > diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target > index bd084c7840..cc64dd32d2 100644 > --- a/tests/tcg/s390x/Makefile.target > +++ b/tests/tcg/s390x/Makefile.target > @@ -1,4 +1,5 @@ > -VPATH+=$(SRC_PATH)/tests/tcg/s390x > +S390X_SRC=$(SRC_PATH)/tests/tcg/s390x > +VPATH+=$(S390X_SRC) > CFLAGS+=-march=zEC12 -m64 > TESTS+=hello-s390x > TESTS+=csst > @@ -9,3 +10,17 @@ TESTS+=pack > TESTS+=mvo > TESTS+=mvc > TESTS+=trap > +TESTS+=signals-s390x > + > +ifneq ($(HAVE_GDB_BIN),) > +GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py > + > +run-gdbstub-signals-s390x: signals-s390x > + $(call run-test, $@, $(GDB_SCRIPT) \ > + --gdb $(HAVE_GDB_BIN) \ > + --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ > + --bin $< --test $(S390X_SRC)/gdbstub/test-signals-s390x.py, \ > + "mixing signals and debugging on s390x") > + > +EXTRA_RUNS += run-gdbstub-signals-s390x > +endif > diff --git a/tests/tcg/s390x/gdbstub/test-signals-s390x.py b/tests/tcg/s390x/gdbstub/test-signals-s390x.py > new file mode 100644 > index 0000000000..80a284b475 > --- /dev/null > +++ b/tests/tcg/s390x/gdbstub/test-signals-s390x.py > @@ -0,0 +1,76 @@ > +from __future__ import print_function > + > +# > +# Test that signals and debugging mix well together on s390x. > +# > +# 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 run_test(): > + """Run through the tests one by one""" > + illegal_op = gdb.Breakpoint("illegal_op") > + stg = gdb.Breakpoint("stg") > + mvc_8 = gdb.Breakpoint("mvc_8") > + > + # Expect the following events: > + # 1x illegal_op breakpoint > + # 2x stg breakpoint, segv, breakpoint > + # 2x mvc_8 breakpoint, segv, breakpoint > + for _ in range(14): How do we come up with the value 14? > + gdb.execute("c") > + report(illegal_op.hit_count == 1, "illegal_op.hit_count == 1") > + report(stg.hit_count == 4, "stg.hit_count == 4") The doc above says we should see this twice, why do we see it 4 times? > + report(mvc_8.hit_count == 4, "mvc_8.hit_count == 4") > + Dito [...] > diff --git a/tests/tcg/s390x/signals-s390x.c b/tests/tcg/s390x/signals-s390x.c > new file mode 100644 > index 0000000000..dc2f8ee59a > --- /dev/null > +++ b/tests/tcg/s390x/signals-s390x.c > @@ -0,0 +1,165 @@ > +#include <assert.h> > +#include <signal.h> > +#include <string.h> > +#include <sys/mman.h> > +#include <ucontext.h> > +#include <unistd.h> > + > +/* > + * Various instructions that generate SIGILL and SIGSEGV. They could have been > + * defined in a separate .s file, but this would complicate the build, so the > + * inline asm is used instead. > + */ > + > +void illegal_op(void); > +void after_illegal_op(void); > +asm(".globl\tillegal_op\n" > + "illegal_op:\t.byte\t0x00,0x00\n" > + "\t.globl\tafter_illegal_op\n" > + "after_illegal_op:\tbr\t%r14"); > + > +void stg(void *dst, unsigned long src); > +asm(".globl\tstg\n" > + "stg:\tstg\t%r3,0(%r2)\n" > + "\tbr\t%r14"); > + > +void mvc_8(void *dst, void *src); > +asm(".globl\tmvc_8\n" > + "mvc_8:\tmvc\t0(8,%r2),0(%r3)\n" > + "\tbr\t%r14"); I was wondering if there would be any nicer way to write this, like (very prototype and wrong) static void stg(void *dst, unsigned long src) { asm volatile("stg %r3,0(%r2)\n"); } static void mvc_8(void *dst, void *src) { asm volatile("mvc 0(8,%r2),0(%r3)\n"); } Please ignore if that just doesn't make any sense. Nothing else jumped at me :)
On Thu, 2021-08-05 at 11:37 +0200, David Hildenbrand wrote: > On 05.08.21 00:51, Ilya Leoshkevich wrote: > > Verify that s390x-specific uc_mcontext.psw.addr is reported > > correctly > > and that signal handling interacts properly with debugging. > > > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> > > --- > > > > v7: > > https://lists.nongnu.org/archive/html/qemu-devel/2021-08/msg00463.html > > v7 -> v8: Another rebase needed due to the conflict with Jonathan's > > 50e36dd61652. > > > > tests/tcg/s390x/Makefile.target | 17 +- > > tests/tcg/s390x/gdbstub/test-signals-s390x.py | 76 ++++++++ > > tests/tcg/s390x/signals-s390x.c | 165 > > ++++++++++++++++++ > > 3 files changed, 257 insertions(+), 1 deletion(-) > > create mode 100644 tests/tcg/s390x/gdbstub/test-signals-s390x.py > > create mode 100644 tests/tcg/s390x/signals-s390x.c > > > > diff --git a/tests/tcg/s390x/Makefile.target > > b/tests/tcg/s390x/Makefile.target > > index bd084c7840..cc64dd32d2 100644 > > --- a/tests/tcg/s390x/Makefile.target > > +++ b/tests/tcg/s390x/Makefile.target > > @@ -1,4 +1,5 @@ > > -VPATH+=$(SRC_PATH)/tests/tcg/s390x > > +S390X_SRC=$(SRC_PATH)/tests/tcg/s390x > > +VPATH+=$(S390X_SRC) > > CFLAGS+=-march=zEC12 -m64 > > TESTS+=hello-s390x > > TESTS+=csst > > @@ -9,3 +10,17 @@ TESTS+=pack > > TESTS+=mvo > > TESTS+=mvc > > TESTS+=trap > > +TESTS+=signals-s390x > > + > > +ifneq ($(HAVE_GDB_BIN),) > > +GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py > > + > > +run-gdbstub-signals-s390x: signals-s390x > > + $(call run-test, $@, $(GDB_SCRIPT) \ > > + --gdb $(HAVE_GDB_BIN) \ > > + --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ > > + --bin $< --test $(S390X_SRC)/gdbstub/test-signals- > > s390x.py, \ > > + "mixing signals and debugging on s390x") > > + > > +EXTRA_RUNS += run-gdbstub-signals-s390x > > +endif > > diff --git a/tests/tcg/s390x/gdbstub/test-signals-s390x.py > > b/tests/tcg/s390x/gdbstub/test-signals-s390x.py > > new file mode 100644 > > index 0000000000..80a284b475 > > --- /dev/null > > +++ b/tests/tcg/s390x/gdbstub/test-signals-s390x.py > > @@ -0,0 +1,76 @@ > > +from __future__ import print_function > > + > > +# > > +# Test that signals and debugging mix well together on s390x. > > +# > > +# 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 run_test(): > > + """Run through the tests one by one""" > > + illegal_op = gdb.Breakpoint("illegal_op") > > + stg = gdb.Breakpoint("stg") > > + mvc_8 = gdb.Breakpoint("mvc_8") > > + > > + # Expect the following events: > > + # 1x illegal_op breakpoint > > + # 2x stg breakpoint, segv, breakpoint > > + # 2x mvc_8 breakpoint, segv, breakpoint > > + for _ in range(14): > > How do we come up with the value 14? 1 (initial) + 1 (illegal op) + 2 * 3 (stg) + 2 * 3 (mvc_8). > > > + gdb.execute("c") > > + report(illegal_op.hit_count == 1, "illegal_op.hit_count == 1") > > + report(stg.hit_count == 4, "stg.hit_count == 4") > > The doc above says we should see this twice, why do we see it 4 > times? With "2x stg breakpoint, segv, breakpoint" I meant: stg break, stg segv, stg break, stg break, stg segv, stg break. > > + report(mvc_8.hit_count == 4, "mvc_8.hit_count == 4") > > + > > Dito > > [...] > > > diff --git a/tests/tcg/s390x/signals-s390x.c > > b/tests/tcg/s390x/signals-s390x.c > > new file mode 100644 > > index 0000000000..dc2f8ee59a > > --- /dev/null > > +++ b/tests/tcg/s390x/signals-s390x.c > > @@ -0,0 +1,165 @@ > > +#include <assert.h> > > +#include <signal.h> > > +#include <string.h> > > +#include <sys/mman.h> > > +#include <ucontext.h> > > +#include <unistd.h> > > + > > +/* > > + * Various instructions that generate SIGILL and SIGSEGV. They > > could have been > > + * defined in a separate .s file, but this would complicate the > > build, so the > > + * inline asm is used instead. > > + */ > > + > > +void illegal_op(void); > > +void after_illegal_op(void); > > +asm(".globl\tillegal_op\n" > > + "illegal_op:\t.byte\t0x00,0x00\n" > > + "\t.globl\tafter_illegal_op\n" > > + "after_illegal_op:\tbr\t%r14"); > > + > > +void stg(void *dst, unsigned long src); > > +asm(".globl\tstg\n" > > + "stg:\tstg\t%r3,0(%r2)\n" > > + "\tbr\t%r14"); > > + > > +void mvc_8(void *dst, void *src); > > +asm(".globl\tmvc_8\n" > > + "mvc_8:\tmvc\t0(8,%r2),0(%r3)\n" > > + "\tbr\t%r14"); > > I was wondering if there would be any nicer way to write this, > like (very prototype and wrong) > > > static void stg(void *dst, unsigned long src) > { > asm volatile("stg %r3,0(%r2)\n"); > } > > static void mvc_8(void *dst, void *src) > { > asm volatile("mvc 0(8,%r2),0(%r3)\n"); > } The prologue would get in the way, and I don't think gcc has __attribute__((naked)) for s390. > Please ignore if that just doesn't make any sense. > > Nothing else jumped at me :)
On 05.08.21 11:57, Ilya Leoshkevich wrote: > On Thu, 2021-08-05 at 11:37 +0200, David Hildenbrand wrote: >> On 05.08.21 00:51, Ilya Leoshkevich wrote: >>> Verify that s390x-specific uc_mcontext.psw.addr is reported >>> correctly >>> and that signal handling interacts properly with debugging. >>> >>> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> >>> --- >>> >>> v7: >>> https://lists.nongnu.org/archive/html/qemu-devel/2021-08/msg00463.html >>> v7 -> v8: Another rebase needed due to the conflict with Jonathan's >>> 50e36dd61652. >>> >>> tests/tcg/s390x/Makefile.target | 17 +- >>> tests/tcg/s390x/gdbstub/test-signals-s390x.py | 76 ++++++++ >>> tests/tcg/s390x/signals-s390x.c | 165 >>> ++++++++++++++++++ >>> 3 files changed, 257 insertions(+), 1 deletion(-) >>> create mode 100644 tests/tcg/s390x/gdbstub/test-signals-s390x.py >>> create mode 100644 tests/tcg/s390x/signals-s390x.c >>> >>> diff --git a/tests/tcg/s390x/Makefile.target >>> b/tests/tcg/s390x/Makefile.target >>> index bd084c7840..cc64dd32d2 100644 >>> --- a/tests/tcg/s390x/Makefile.target >>> +++ b/tests/tcg/s390x/Makefile.target >>> @@ -1,4 +1,5 @@ >>> -VPATH+=$(SRC_PATH)/tests/tcg/s390x >>> +S390X_SRC=$(SRC_PATH)/tests/tcg/s390x >>> +VPATH+=$(S390X_SRC) >>> CFLAGS+=-march=zEC12 -m64 >>> TESTS+=hello-s390x >>> TESTS+=csst >>> @@ -9,3 +10,17 @@ TESTS+=pack >>> TESTS+=mvo >>> TESTS+=mvc >>> TESTS+=trap >>> +TESTS+=signals-s390x >>> + >>> +ifneq ($(HAVE_GDB_BIN),) >>> +GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py >>> + >>> +run-gdbstub-signals-s390x: signals-s390x >>> + $(call run-test, $@, $(GDB_SCRIPT) \ >>> + --gdb $(HAVE_GDB_BIN) \ >>> + --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ >>> + --bin $< --test $(S390X_SRC)/gdbstub/test-signals- >>> s390x.py, \ >>> + "mixing signals and debugging on s390x") >>> + >>> +EXTRA_RUNS += run-gdbstub-signals-s390x >>> +endif >>> diff --git a/tests/tcg/s390x/gdbstub/test-signals-s390x.py >>> b/tests/tcg/s390x/gdbstub/test-signals-s390x.py >>> new file mode 100644 >>> index 0000000000..80a284b475 >>> --- /dev/null >>> +++ b/tests/tcg/s390x/gdbstub/test-signals-s390x.py >>> @@ -0,0 +1,76 @@ >>> +from __future__ import print_function >>> + >>> +# >>> +# Test that signals and debugging mix well together on s390x. >>> +# >>> +# 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 run_test(): >>> + """Run through the tests one by one""" >>> + illegal_op = gdb.Breakpoint("illegal_op") >>> + stg = gdb.Breakpoint("stg") >>> + mvc_8 = gdb.Breakpoint("mvc_8") >>> + >>> + # Expect the following events: >>> + # 1x illegal_op breakpoint >>> + # 2x stg breakpoint, segv, breakpoint >>> + # 2x mvc_8 breakpoint, segv, breakpoint >>> + for _ in range(14): >> >> How do we come up with the value 14? > > 1 (initial) + 1 (illegal op) + 2 * 3 (stg) + 2 * 3 (mvc_8). > Oh, that makes sense. >> >>> + gdb.execute("c") >>> + report(illegal_op.hit_count == 1, "illegal_op.hit_count == 1") >>> + report(stg.hit_count == 4, "stg.hit_count == 4") >> >> The doc above says we should see this twice, why do we see it 4 >> times? > > With "2x stg breakpoint, segv, breakpoint" I meant: stg break, stg > segv, stg break, stg break, stg segv, stg break. Understand it now, wasn't paying attention to the details :) Thanks! Acked-by: David Hildenbrand <david@redhat.com>
On 05/08/2021 00.51, Ilya Leoshkevich wrote: > Verify that s390x-specific uc_mcontext.psw.addr is reported correctly > and that signal handling interacts properly with debugging. > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> > --- > > v7: https://lists.nongnu.org/archive/html/qemu-devel/2021-08/msg00463.html > v7 -> v8: Another rebase needed due to the conflict with Jonathan's > 50e36dd61652. Thanks for respinning this patch! I now gave it a try, and it seems to work, but the output looks a little funny: SKIPPED signals on s390x because BROKEN awaiting sigframe clean-ups and vdso support TEST test-mmap (default) on s390x TEST testthread on s390x TEST threadcount on s390x TEST hello-s390x on s390x TEST csst on s390x TEST ipm on s390x TEST exrl-trt on s390x TEST exrl-trtr on s390x TEST pack on s390x TEST mvo on s390x TEST mvc on s390x TEST trap on s390x TEST signals-s390x on s390x i.e. it first says "SKIPPED signals", but later still executes the test. Could that be fixed somehow? Thomas
On Fri, 2021-08-06 at 07:25 +0200, Thomas Huth wrote: > On 05/08/2021 00.51, Ilya Leoshkevich wrote: > > Verify that s390x-specific uc_mcontext.psw.addr is reported > > correctly > > and that signal handling interacts properly with debugging. > > > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> > > --- > > > > v7: > > https://lists.nongnu.org/archive/html/qemu-devel/2021-08/msg00463.html > > v7 -> v8: Another rebase needed due to the conflict with Jonathan's > > 50e36dd61652. > > Thanks for respinning this patch! I now gave it a try, and it seems > to work, > but the output looks a little funny: > > SKIPPED signals on s390x because BROKEN awaiting sigframe clean- > ups and > vdso support > TEST test-mmap (default) on s390x > TEST testthread on s390x > TEST threadcount on s390x > TEST hello-s390x on s390x > TEST csst on s390x > TEST ipm on s390x > TEST exrl-trt on s390x > TEST exrl-trtr on s390x > TEST pack on s390x > TEST mvo on s390x > TEST mvc on s390x > TEST trap on s390x > TEST signals-s390x on s390x > > i.e. it first says "SKIPPED signals", but later still executes the > test. > Could that be fixed somehow? These are two different tests actually. signals is a multiarch test that is valid on other machines as well. The new signals-s390x tests only s390x-specific aspects of signal handling. Best regards, Ilya
Ilya Leoshkevich <iii@linux.ibm.com> writes: > Verify that s390x-specific uc_mcontext.psw.addr is reported correctly > and that signal handling interacts properly with debugging. > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Acked-by: Alex Bennée <alex.bennee@linaro.org> > --- > > v7: https://lists.nongnu.org/archive/html/qemu-devel/2021-08/msg00463.html > v7 -> v8: Another rebase needed due to the conflict with Jonathan's > 50e36dd61652. > > tests/tcg/s390x/Makefile.target | 17 +- > tests/tcg/s390x/gdbstub/test-signals-s390x.py | 76 ++++++++ > tests/tcg/s390x/signals-s390x.c | 165 ++++++++++++++++++ > 3 files changed, 257 insertions(+), 1 deletion(-) > create mode 100644 tests/tcg/s390x/gdbstub/test-signals-s390x.py > create mode 100644 tests/tcg/s390x/signals-s390x.c > > diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target > index bd084c7840..cc64dd32d2 100644 > --- a/tests/tcg/s390x/Makefile.target > +++ b/tests/tcg/s390x/Makefile.target > @@ -1,4 +1,5 @@ > -VPATH+=$(SRC_PATH)/tests/tcg/s390x > +S390X_SRC=$(SRC_PATH)/tests/tcg/s390x > +VPATH+=$(S390X_SRC) > CFLAGS+=-march=zEC12 -m64 > TESTS+=hello-s390x > TESTS+=csst > @@ -9,3 +10,17 @@ TESTS+=pack > TESTS+=mvo > TESTS+=mvc > TESTS+=trap > +TESTS+=signals-s390x > + > +ifneq ($(HAVE_GDB_BIN),) > +GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py > + > +run-gdbstub-signals-s390x: signals-s390x > + $(call run-test, $@, $(GDB_SCRIPT) \ > + --gdb $(HAVE_GDB_BIN) \ > + --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ > + --bin $< --test $(S390X_SRC)/gdbstub/test-signals-s390x.py, \ > + "mixing signals and debugging on s390x") > + > +EXTRA_RUNS += run-gdbstub-signals-s390x > +endif > diff --git a/tests/tcg/s390x/gdbstub/test-signals-s390x.py b/tests/tcg/s390x/gdbstub/test-signals-s390x.py > new file mode 100644 > index 0000000000..80a284b475 > --- /dev/null > +++ b/tests/tcg/s390x/gdbstub/test-signals-s390x.py > @@ -0,0 +1,76 @@ > +from __future__ import print_function > + > +# > +# Test that signals and debugging mix well together on s390x. > +# > +# 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 run_test(): > + """Run through the tests one by one""" > + illegal_op = gdb.Breakpoint("illegal_op") > + stg = gdb.Breakpoint("stg") > + mvc_8 = gdb.Breakpoint("mvc_8") > + > + # Expect the following events: > + # 1x illegal_op breakpoint > + # 2x stg breakpoint, segv, breakpoint > + # 2x mvc_8 breakpoint, segv, breakpoint > + for _ in range(14): > + gdb.execute("c") > + report(illegal_op.hit_count == 1, "illegal_op.hit_count == 1") > + report(stg.hit_count == 4, "stg.hit_count == 4") > + report(mvc_8.hit_count == 4, "mvc_8.hit_count == 4") > + > + # The test must succeed. > + gdb.Breakpoint("_exit") > + gdb.execute("c") > + status = int(gdb.parse_and_eval("$r2")) > + report(status == 0, "status == 0"); > + > + > +# > +# 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") > + gdb.execute("set confirm off") > + > + # Run the actual tests > + run_test() > +except (gdb.error): > + print("GDB Exception: %s" % (sys.exc_info()[0])) > + failcount += 1 > + pass > + > +print("All tests complete: %d failures" % failcount) > +exit(failcount) > diff --git a/tests/tcg/s390x/signals-s390x.c b/tests/tcg/s390x/signals-s390x.c > new file mode 100644 > index 0000000000..dc2f8ee59a > --- /dev/null > +++ b/tests/tcg/s390x/signals-s390x.c > @@ -0,0 +1,165 @@ > +#include <assert.h> > +#include <signal.h> > +#include <string.h> > +#include <sys/mman.h> > +#include <ucontext.h> > +#include <unistd.h> > + > +/* > + * Various instructions that generate SIGILL and SIGSEGV. They could have been > + * defined in a separate .s file, but this would complicate the build, so the > + * inline asm is used instead. > + */ > + > +void illegal_op(void); > +void after_illegal_op(void); > +asm(".globl\tillegal_op\n" > + "illegal_op:\t.byte\t0x00,0x00\n" > + "\t.globl\tafter_illegal_op\n" > + "after_illegal_op:\tbr\t%r14"); > + > +void stg(void *dst, unsigned long src); > +asm(".globl\tstg\n" > + "stg:\tstg\t%r3,0(%r2)\n" > + "\tbr\t%r14"); > + > +void mvc_8(void *dst, void *src); > +asm(".globl\tmvc_8\n" > + "mvc_8:\tmvc\t0(8,%r2),0(%r3)\n" > + "\tbr\t%r14"); > + > +static void safe_puts(const char *s) > +{ > + write(0, s, strlen(s)); > + write(0, "\n", 1); > +} > + > +enum exception { > + exception_operation, > + exception_translation, > + exception_protection, > +}; > + > +static struct { > + int sig; > + void *addr; > + unsigned long psw_addr; > + enum exception exception; > +} expected; > + > +static void handle_signal(int sig, siginfo_t *info, void *ucontext) > +{ > + void *page; > + int err; > + > + if (sig != expected.sig) { > + safe_puts("[ FAILED ] wrong signal"); > + _exit(1); > + } > + > + if (info->si_addr != expected.addr) { > + safe_puts("[ FAILED ] wrong si_addr"); > + _exit(1); > + } > + > + if (((ucontext_t *)ucontext)->uc_mcontext.psw.addr != expected.psw_addr) { > + safe_puts("[ FAILED ] wrong psw.addr"); > + _exit(1); > + } > + > + switch (expected.exception) { > + case exception_translation: > + page = mmap(expected.addr, 4096, PROT_READ | PROT_WRITE, > + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); > + if (page != expected.addr) { > + safe_puts("[ FAILED ] mmap() failed"); > + _exit(1); > + } > + break; > + case exception_protection: > + err = mprotect(expected.addr, 4096, PROT_READ | PROT_WRITE); > + if (err != 0) { > + safe_puts("[ FAILED ] mprotect() failed"); > + _exit(1); > + } > + break; > + default: > + break; > + } > +} > + > +static void check_sigsegv(void *func, enum exception exception, > + unsigned long val) > +{ > + int prot; > + unsigned long *page; > + unsigned long *addr; > + int err; > + > + prot = exception == exception_translation ? PROT_NONE : PROT_READ; > + page = mmap(NULL, 4096, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); > + assert(page != MAP_FAILED); > + if (exception == exception_translation) { > + /* Hopefully nothing will be mapped at this address. */ > + err = munmap(page, 4096); > + assert(err == 0); > + } > + addr = page + (val & 0x1ff); > + > + expected.sig = SIGSEGV; > + expected.addr = page; > + expected.psw_addr = (unsigned long)func; > + expected.exception = exception; > + if (func == stg) { > + stg(addr, val); > + } else { > + assert(func == mvc_8); > + mvc_8(addr, &val); > + } > + assert(*addr == val); > + > + err = munmap(page, 4096); > + assert(err == 0); > +} > + > +int main(void) > +{ > + struct sigaction act; > + int err; > + > + memset(&act, 0, sizeof(act)); > + act.sa_sigaction = handle_signal; > + act.sa_flags = SA_SIGINFO; > + err = sigaction(SIGILL, &act, NULL); > + assert(err == 0); > + err = sigaction(SIGSEGV, &act, NULL); > + assert(err == 0); > + > + safe_puts("[ RUN ] Operation exception"); > + expected.sig = SIGILL; > + expected.addr = illegal_op; > + expected.psw_addr = (unsigned long)after_illegal_op; > + expected.exception = exception_operation; > + illegal_op(); > + safe_puts("[ OK ]"); > + > + safe_puts("[ RUN ] Translation exception from stg"); > + check_sigsegv(stg, exception_translation, 42); > + safe_puts("[ OK ]"); > + > + safe_puts("[ RUN ] Translation exception from mvc"); > + check_sigsegv(mvc_8, exception_translation, 4242); > + safe_puts("[ OK ]"); > + > + safe_puts("[ RUN ] Protection exception from stg"); > + check_sigsegv(stg, exception_protection, 424242); > + safe_puts("[ OK ]"); > + > + safe_puts("[ RUN ] Protection exception from mvc"); > + check_sigsegv(mvc_8, exception_protection, 42424242); > + safe_puts("[ OK ]"); > + > + safe_puts("[ PASSED ]"); > + > + _exit(0); > +}
On Thu, Aug 05 2021, Ilya Leoshkevich <iii@linux.ibm.com> wrote: > Verify that s390x-specific uc_mcontext.psw.addr is reported correctly > and that signal handling interacts properly with debugging. > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> > --- > > v7: https://lists.nongnu.org/archive/html/qemu-devel/2021-08/msg00463.html > v7 -> v8: Another rebase needed due to the conflict with Jonathan's > 50e36dd61652. > > tests/tcg/s390x/Makefile.target | 17 +- > tests/tcg/s390x/gdbstub/test-signals-s390x.py | 76 ++++++++ > tests/tcg/s390x/signals-s390x.c | 165 ++++++++++++++++++ > 3 files changed, 257 insertions(+), 1 deletion(-) > create mode 100644 tests/tcg/s390x/gdbstub/test-signals-s390x.py > create mode 100644 tests/tcg/s390x/signals-s390x.c Thanks, applied.
diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target index bd084c7840..cc64dd32d2 100644 --- a/tests/tcg/s390x/Makefile.target +++ b/tests/tcg/s390x/Makefile.target @@ -1,4 +1,5 @@ -VPATH+=$(SRC_PATH)/tests/tcg/s390x +S390X_SRC=$(SRC_PATH)/tests/tcg/s390x +VPATH+=$(S390X_SRC) CFLAGS+=-march=zEC12 -m64 TESTS+=hello-s390x TESTS+=csst @@ -9,3 +10,17 @@ TESTS+=pack TESTS+=mvo TESTS+=mvc TESTS+=trap +TESTS+=signals-s390x + +ifneq ($(HAVE_GDB_BIN),) +GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py + +run-gdbstub-signals-s390x: signals-s390x + $(call run-test, $@, $(GDB_SCRIPT) \ + --gdb $(HAVE_GDB_BIN) \ + --qemu $(QEMU) --qargs "$(QEMU_OPTS)" \ + --bin $< --test $(S390X_SRC)/gdbstub/test-signals-s390x.py, \ + "mixing signals and debugging on s390x") + +EXTRA_RUNS += run-gdbstub-signals-s390x +endif diff --git a/tests/tcg/s390x/gdbstub/test-signals-s390x.py b/tests/tcg/s390x/gdbstub/test-signals-s390x.py new file mode 100644 index 0000000000..80a284b475 --- /dev/null +++ b/tests/tcg/s390x/gdbstub/test-signals-s390x.py @@ -0,0 +1,76 @@ +from __future__ import print_function + +# +# Test that signals and debugging mix well together on s390x. +# +# 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 run_test(): + """Run through the tests one by one""" + illegal_op = gdb.Breakpoint("illegal_op") + stg = gdb.Breakpoint("stg") + mvc_8 = gdb.Breakpoint("mvc_8") + + # Expect the following events: + # 1x illegal_op breakpoint + # 2x stg breakpoint, segv, breakpoint + # 2x mvc_8 breakpoint, segv, breakpoint + for _ in range(14): + gdb.execute("c") + report(illegal_op.hit_count == 1, "illegal_op.hit_count == 1") + report(stg.hit_count == 4, "stg.hit_count == 4") + report(mvc_8.hit_count == 4, "mvc_8.hit_count == 4") + + # The test must succeed. + gdb.Breakpoint("_exit") + gdb.execute("c") + status = int(gdb.parse_and_eval("$r2")) + report(status == 0, "status == 0"); + + +# +# 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") + gdb.execute("set confirm off") + + # Run the actual tests + run_test() +except (gdb.error): + print("GDB Exception: %s" % (sys.exc_info()[0])) + failcount += 1 + pass + +print("All tests complete: %d failures" % failcount) +exit(failcount) diff --git a/tests/tcg/s390x/signals-s390x.c b/tests/tcg/s390x/signals-s390x.c new file mode 100644 index 0000000000..dc2f8ee59a --- /dev/null +++ b/tests/tcg/s390x/signals-s390x.c @@ -0,0 +1,165 @@ +#include <assert.h> +#include <signal.h> +#include <string.h> +#include <sys/mman.h> +#include <ucontext.h> +#include <unistd.h> + +/* + * Various instructions that generate SIGILL and SIGSEGV. They could have been + * defined in a separate .s file, but this would complicate the build, so the + * inline asm is used instead. + */ + +void illegal_op(void); +void after_illegal_op(void); +asm(".globl\tillegal_op\n" + "illegal_op:\t.byte\t0x00,0x00\n" + "\t.globl\tafter_illegal_op\n" + "after_illegal_op:\tbr\t%r14"); + +void stg(void *dst, unsigned long src); +asm(".globl\tstg\n" + "stg:\tstg\t%r3,0(%r2)\n" + "\tbr\t%r14"); + +void mvc_8(void *dst, void *src); +asm(".globl\tmvc_8\n" + "mvc_8:\tmvc\t0(8,%r2),0(%r3)\n" + "\tbr\t%r14"); + +static void safe_puts(const char *s) +{ + write(0, s, strlen(s)); + write(0, "\n", 1); +} + +enum exception { + exception_operation, + exception_translation, + exception_protection, +}; + +static struct { + int sig; + void *addr; + unsigned long psw_addr; + enum exception exception; +} expected; + +static void handle_signal(int sig, siginfo_t *info, void *ucontext) +{ + void *page; + int err; + + if (sig != expected.sig) { + safe_puts("[ FAILED ] wrong signal"); + _exit(1); + } + + if (info->si_addr != expected.addr) { + safe_puts("[ FAILED ] wrong si_addr"); + _exit(1); + } + + if (((ucontext_t *)ucontext)->uc_mcontext.psw.addr != expected.psw_addr) { + safe_puts("[ FAILED ] wrong psw.addr"); + _exit(1); + } + + switch (expected.exception) { + case exception_translation: + page = mmap(expected.addr, 4096, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + if (page != expected.addr) { + safe_puts("[ FAILED ] mmap() failed"); + _exit(1); + } + break; + case exception_protection: + err = mprotect(expected.addr, 4096, PROT_READ | PROT_WRITE); + if (err != 0) { + safe_puts("[ FAILED ] mprotect() failed"); + _exit(1); + } + break; + default: + break; + } +} + +static void check_sigsegv(void *func, enum exception exception, + unsigned long val) +{ + int prot; + unsigned long *page; + unsigned long *addr; + int err; + + prot = exception == exception_translation ? PROT_NONE : PROT_READ; + page = mmap(NULL, 4096, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(page != MAP_FAILED); + if (exception == exception_translation) { + /* Hopefully nothing will be mapped at this address. */ + err = munmap(page, 4096); + assert(err == 0); + } + addr = page + (val & 0x1ff); + + expected.sig = SIGSEGV; + expected.addr = page; + expected.psw_addr = (unsigned long)func; + expected.exception = exception; + if (func == stg) { + stg(addr, val); + } else { + assert(func == mvc_8); + mvc_8(addr, &val); + } + assert(*addr == val); + + err = munmap(page, 4096); + assert(err == 0); +} + +int main(void) +{ + struct sigaction act; + int err; + + memset(&act, 0, sizeof(act)); + act.sa_sigaction = handle_signal; + act.sa_flags = SA_SIGINFO; + err = sigaction(SIGILL, &act, NULL); + assert(err == 0); + err = sigaction(SIGSEGV, &act, NULL); + assert(err == 0); + + safe_puts("[ RUN ] Operation exception"); + expected.sig = SIGILL; + expected.addr = illegal_op; + expected.psw_addr = (unsigned long)after_illegal_op; + expected.exception = exception_operation; + illegal_op(); + safe_puts("[ OK ]"); + + safe_puts("[ RUN ] Translation exception from stg"); + check_sigsegv(stg, exception_translation, 42); + safe_puts("[ OK ]"); + + safe_puts("[ RUN ] Translation exception from mvc"); + check_sigsegv(mvc_8, exception_translation, 4242); + safe_puts("[ OK ]"); + + safe_puts("[ RUN ] Protection exception from stg"); + check_sigsegv(stg, exception_protection, 424242); + safe_puts("[ OK ]"); + + safe_puts("[ RUN ] Protection exception from mvc"); + check_sigsegv(mvc_8, exception_protection, 42424242); + safe_puts("[ OK ]"); + + safe_puts("[ PASSED ]"); + + _exit(0); +}
Verify that s390x-specific uc_mcontext.psw.addr is reported correctly and that signal handling interacts properly with debugging. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> --- v7: https://lists.nongnu.org/archive/html/qemu-devel/2021-08/msg00463.html v7 -> v8: Another rebase needed due to the conflict with Jonathan's 50e36dd61652. tests/tcg/s390x/Makefile.target | 17 +- tests/tcg/s390x/gdbstub/test-signals-s390x.py | 76 ++++++++ tests/tcg/s390x/signals-s390x.c | 165 ++++++++++++++++++ 3 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 tests/tcg/s390x/gdbstub/test-signals-s390x.py create mode 100644 tests/tcg/s390x/signals-s390x.c