qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

signals-s390x.c (5449B)


      1 #include <assert.h>
      2 #include <execinfo.h>
      3 #include <signal.h>
      4 #include <string.h>
      5 #include <sys/mman.h>
      6 #include <ucontext.h>
      7 #include <unistd.h>
      8 
      9 /*
     10  * Various instructions that generate SIGILL and SIGSEGV. They could have been
     11  * defined in a separate .s file, but this would complicate the build, so the
     12  * inline asm is used instead.
     13  */
     14 
     15 #define DEFINE_ASM_FUNCTION(name, body) \
     16     asm(".globl " #name "\n" \
     17         #name ":\n" \
     18         ".cfi_startproc\n" \
     19         body "\n" \
     20         "br %r14\n" \
     21         ".cfi_endproc");
     22 
     23 void illegal_op(void);
     24 extern const char after_illegal_op;
     25 DEFINE_ASM_FUNCTION(illegal_op,
     26     ".byte 0x00,0x00\n"
     27     ".globl after_illegal_op\n"
     28     "after_illegal_op:")
     29 
     30 void stg(void *dst, unsigned long src);
     31 DEFINE_ASM_FUNCTION(stg, "stg %r3,0(%r2)")
     32 
     33 void mvc_8(void *dst, void *src);
     34 DEFINE_ASM_FUNCTION(mvc_8, "mvc 0(8,%r2),0(%r3)")
     35 
     36 extern const char return_from_main_1;
     37 
     38 static void safe_puts(const char *s)
     39 {
     40     write(0, s, strlen(s));
     41     write(0, "\n", 1);
     42 }
     43 
     44 enum exception {
     45     exception_operation,
     46     exception_translation,
     47     exception_protection,
     48 };
     49 
     50 static struct {
     51     int sig;
     52     void *addr;
     53     unsigned long psw_addr;
     54     enum exception exception;
     55 } expected;
     56 
     57 static void handle_signal(int sig, siginfo_t *info, void *ucontext)
     58 {
     59     int err, i, n_frames;
     60     void *frames[16];
     61     void *page;
     62 
     63     if (sig != expected.sig) {
     64         safe_puts("[  FAILED  ] wrong signal");
     65         _exit(1);
     66     }
     67 
     68     if (info->si_addr != expected.addr) {
     69         safe_puts("[  FAILED  ] wrong si_addr");
     70         _exit(1);
     71     }
     72 
     73     if (((ucontext_t *)ucontext)->uc_mcontext.psw.addr != expected.psw_addr) {
     74         safe_puts("[  FAILED  ] wrong psw.addr");
     75         _exit(1);
     76     }
     77 
     78     switch (expected.exception) {
     79     case exception_translation:
     80         page = mmap(expected.addr, 4096, PROT_READ | PROT_WRITE,
     81                     MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
     82         if (page != expected.addr) {
     83             safe_puts("[  FAILED  ] mmap() failed");
     84             _exit(1);
     85         }
     86         break;
     87     case exception_protection:
     88         err = mprotect(expected.addr, 4096, PROT_READ | PROT_WRITE);
     89         if (err != 0) {
     90             safe_puts("[  FAILED  ] mprotect() failed");
     91             _exit(1);
     92         }
     93         break;
     94     default:
     95         break;
     96     }
     97 
     98     n_frames = backtrace(frames, sizeof(frames) / sizeof(frames[0]));
     99     for (i = 0; i < n_frames; i++) {
    100         if (frames[i] == &return_from_main_1) {
    101             break;
    102         }
    103     }
    104     if (i == n_frames) {
    105         safe_puts("[  FAILED  ] backtrace() is broken");
    106         _exit(1);
    107     }
    108 }
    109 
    110 static void check_sigsegv(void *func, enum exception exception,
    111                           unsigned long val)
    112 {
    113     int prot;
    114     unsigned long *page;
    115     unsigned long *addr;
    116     int err;
    117 
    118     prot = exception == exception_translation ? PROT_NONE : PROT_READ;
    119     page = mmap(NULL, 4096, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    120     assert(page != MAP_FAILED);
    121     if (exception == exception_translation) {
    122         /* Hopefully nothing will be mapped at this address. */
    123         err = munmap(page, 4096);
    124         assert(err == 0);
    125     }
    126     addr = page + (val & 0x1ff);
    127 
    128     expected.sig = SIGSEGV;
    129     expected.addr = page;
    130     expected.psw_addr = (unsigned long)func;
    131     expected.exception = exception;
    132     if (func == stg) {
    133         stg(addr, val);
    134     } else {
    135         assert(func == mvc_8);
    136         mvc_8(addr, &val);
    137     }
    138     assert(*addr == val);
    139 
    140     err = munmap(page, 4096);
    141     assert(err == 0);
    142 }
    143 
    144 int main_1(void)
    145 {
    146     struct sigaction act;
    147     int err;
    148 
    149     memset(&act, 0, sizeof(act));
    150     act.sa_sigaction = handle_signal;
    151     act.sa_flags = SA_SIGINFO;
    152     err = sigaction(SIGILL, &act, NULL);
    153     assert(err == 0);
    154     err = sigaction(SIGSEGV, &act, NULL);
    155     assert(err == 0);
    156 
    157     safe_puts("[ RUN      ] Operation exception");
    158     expected.sig = SIGILL;
    159     expected.addr = illegal_op;
    160     expected.psw_addr = (unsigned long)&after_illegal_op;
    161     expected.exception = exception_operation;
    162     illegal_op();
    163     safe_puts("[       OK ]");
    164 
    165     safe_puts("[ RUN      ] Translation exception from stg");
    166     check_sigsegv(stg, exception_translation, 42);
    167     safe_puts("[       OK ]");
    168 
    169     safe_puts("[ RUN      ] Translation exception from mvc");
    170     check_sigsegv(mvc_8, exception_translation, 4242);
    171     safe_puts("[       OK ]");
    172 
    173     safe_puts("[ RUN      ] Protection exception from stg");
    174     check_sigsegv(stg, exception_protection, 424242);
    175     safe_puts("[       OK ]");
    176 
    177     safe_puts("[ RUN      ] Protection exception from mvc");
    178     check_sigsegv(mvc_8, exception_protection, 42424242);
    179     safe_puts("[       OK ]");
    180 
    181     safe_puts("[  PASSED  ]");
    182 
    183     _exit(0);
    184 }
    185 
    186 /*
    187  * Define main() in assembly in order to test that unwinding from signal
    188  * handlers until main() works. This way we can define a specific point that
    189  * the unwinder should reach. This is also better than defining main() in C
    190  * and using inline assembly to call main_1(), since it's not easy to get all
    191  * the clobbers right.
    192  */
    193 
    194 DEFINE_ASM_FUNCTION(main,
    195     "stmg %r14,%r15,112(%r15)\n"
    196     ".cfi_offset 14,-48\n"
    197     ".cfi_offset 15,-40\n"
    198     "lay %r15,-160(%r15)\n"
    199     ".cfi_def_cfa_offset 320\n"
    200     "brasl %r14,main_1\n"
    201     ".globl return_from_main_1\n"
    202     "return_from_main_1:\n"
    203     "lmg %r14,%r15,272(%r15)\n"
    204     ".cfi_restore 15\n"
    205     ".cfi_restore 14\n"
    206     ".cfi_def_cfa_offset 160");