Verify that s390x-specific uc_mcontext.psw.addr is reported correctly.
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
tests/tcg/s390x/Makefile.target | 1 +
tests/tcg/s390x/signal.c | 163 ++++++++++++++++++++++++++++++++
2 files changed, 164 insertions(+)
create mode 100644 tests/tcg/s390x/signal.c
diff --git a/tests/tcg/s390x/Makefile.target b/tests/tcg/s390x/Makefile.target
index 241ef28f61..cdb7d85316 100644
--- a/tests/tcg/s390x/Makefile.target
+++ b/tests/tcg/s390x/Makefile.target
@@ -8,3 +8,4 @@ TESTS+=exrl-trtr
TESTS+=pack
TESTS+=mvo
TESTS+=mvc
+TESTS+=signal
diff --git a/tests/tcg/s390x/signal.c b/tests/tcg/s390x/signal.c
new file mode 100644
index 0000000000..c25d7dd019
--- /dev/null
+++ b/tests/tcg/s390x/signal.c
@@ -0,0 +1,163 @@
+#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;
+ }
+}
+
+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 ]");
+
+ return 0;
+}
--
2.31.1
On 2021-06-01 8:22 pm, Ilya Leoshkevich wrote:
> Verify that s390x-specific uc_mcontext.psw.addr is reported correctly.
>
> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
> ---
> tests/tcg/s390x/Makefile.target | 1 +
> tests/tcg/s390x/signal.c | 163 ++++++++++++++++++++++++++++++++
> 2 files changed, 164 insertions(+)
> create mode 100644 tests/tcg/s390x/signal.c
>
> diff --git a/tests/tcg/s390x/Makefile.target
> b/tests/tcg/s390x/Makefile.target
> index 241ef28f61..cdb7d85316 100644
> --- a/tests/tcg/s390x/Makefile.target
> +++ b/tests/tcg/s390x/Makefile.target
> @@ -8,3 +8,4 @@ TESTS+=exrl-trtr
> TESTS+=pack
> TESTS+=mvo
> TESTS+=mvc
> +TESTS+=signal
> diff --git a/tests/tcg/s390x/signal.c b/tests/tcg/s390x/signal.c
> new file mode 100644
> index 0000000000..c25d7dd019
> --- /dev/null
> +++ b/tests/tcg/s390x/signal.c
> @@ -0,0 +1,163 @@
> +#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) {
When I try to run 'make test-tcg' gcc 9.3.0 is complaining about a
missing case:
/home/jalbrecht/src/qemu/tests/tcg/s390x/signal.c: In function
'handle_signal':
/home/jalbrecht/src/qemu/tests/tcg/s390x/signal.c:70:5: error:
enumeration value 'exception_operation' not handled in switch
[-Werror=switch]
70 | switch (expected.exception) {
| ^~~~~~
cc1: all warnings being treated as errors
> + 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;
> + }
> +}
> +
> +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 ]");
> +
> + return 0;
> +}
On Fri, 2021-06-18 at 09:47 -0400, jonathan.albrecht wrote:
> On 2021-06-01 8:22 pm, Ilya Leoshkevich wrote:
> > Verify that s390x-specific uc_mcontext.psw.addr is reported
> > correctly.
> >
> > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
> > ---
> > tests/tcg/s390x/Makefile.target | 1 +
> > tests/tcg/s390x/signal.c | 163
> > ++++++++++++++++++++++++++++++++
> > 2 files changed, 164 insertions(+)
> > create mode 100644 tests/tcg/s390x/signal.c
> >
[...]
> > +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) {
>
> When I try to run 'make test-tcg' gcc 9.3.0 is complaining about a
> missing case:
> /home/jalbrecht/src/qemu/tests/tcg/s390x/signal.c: In function
> 'handle_signal':
> /home/jalbrecht/src/qemu/tests/tcg/s390x/signal.c:70:5: error:
> enumeration value 'exception_operation' not handled in switch
> [-Werror=switch]
> 70 | switch (expected.exception) {
> | ^~~~~~
> cc1: all warnings being treated as errors
I wonder how I didn't catch this, since I'm testing on Ubuntu 20.04
as well. Thank you, I will fix this.
Best regards,
Ilya
© 2016 - 2026 Red Hat, Inc.