signals-s390x.c (abf7aee72ea66944a62962603e4c2381f5e473e7) signals-s390x.c (1a75b14038bd77b0af7d2ddb0cf230b31f75623e)
1#include <assert.h>
1#include <assert.h>
2#include <execinfo.h>
2#include <signal.h>
3#include <string.h>
4#include <sys/mman.h>
5#include <ucontext.h>
6#include <unistd.h>
7
8/*
9 * Various instructions that generate SIGILL and SIGSEGV. They could have been
10 * defined in a separate .s file, but this would complicate the build, so the
11 * inline asm is used instead.
12 */
13
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
14void illegal_op(void);
23void illegal_op(void);
15void after_illegal_op(void);
16asm(".globl\tillegal_op\n"
17 "illegal_op:\t.byte\t0x00,0x00\n"
18 "\t.globl\tafter_illegal_op\n"
19 "after_illegal_op:\tbr\t%r14");
24extern const char after_illegal_op;
25DEFINE_ASM_FUNCTION(illegal_op,
26 ".byte 0x00,0x00\n"
27 ".globl after_illegal_op\n"
28 "after_illegal_op:")
20
21void stg(void *dst, unsigned long src);
29
30void stg(void *dst, unsigned long src);
22asm(".globl\tstg\n"
23 "stg:\tstg\t%r3,0(%r2)\n"
24 "\tbr\t%r14");
31DEFINE_ASM_FUNCTION(stg, "stg %r3,0(%r2)")
25
26void mvc_8(void *dst, void *src);
32
33void mvc_8(void *dst, void *src);
27asm(".globl\tmvc_8\n"
28 "mvc_8:\tmvc\t0(8,%r2),0(%r3)\n"
29 "\tbr\t%r14");
34DEFINE_ASM_FUNCTION(mvc_8, "mvc 0(8,%r2),0(%r3)")
30
35
36extern const char return_from_main_1;
37
31static void safe_puts(const char *s)
32{
33 write(0, s, strlen(s));
34 write(0, "\n", 1);
35}
36
37enum exception {
38 exception_operation,

--- 5 unchanged lines hidden (view full) ---

44 int sig;
45 void *addr;
46 unsigned long psw_addr;
47 enum exception exception;
48} expected;
49
50static void handle_signal(int sig, siginfo_t *info, void *ucontext)
51{
38static void safe_puts(const char *s)
39{
40 write(0, s, strlen(s));
41 write(0, "\n", 1);
42}
43
44enum exception {
45 exception_operation,

--- 5 unchanged lines hidden (view full) ---

51 int sig;
52 void *addr;
53 unsigned long psw_addr;
54 enum exception exception;
55} expected;
56
57static void handle_signal(int sig, siginfo_t *info, void *ucontext)
58{
59 int err, i, n_frames;
60 void *frames[16];
52 void *page;
61 void *page;
53 int err;
54
55 if (sig != expected.sig) {
56 safe_puts("[ FAILED ] wrong signal");
57 _exit(1);
58 }
59
60 if (info->si_addr != expected.addr) {
61 safe_puts("[ FAILED ] wrong si_addr");

--- 19 unchanged lines hidden (view full) ---

81 if (err != 0) {
82 safe_puts("[ FAILED ] mprotect() failed");
83 _exit(1);
84 }
85 break;
86 default:
87 break;
88 }
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");

--- 19 unchanged lines hidden (view full) ---

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 }
89}
90
91static void check_sigsegv(void *func, enum exception exception,
92 unsigned long val)
93{
94 int prot;
95 unsigned long *page;
96 unsigned long *addr;

--- 20 unchanged lines hidden (view full) ---

117 mvc_8(addr, &val);
118 }
119 assert(*addr == val);
120
121 err = munmap(page, 4096);
122 assert(err == 0);
123}
124
108}
109
110static void check_sigsegv(void *func, enum exception exception,
111 unsigned long val)
112{
113 int prot;
114 unsigned long *page;
115 unsigned long *addr;

--- 20 unchanged lines hidden (view full) ---

136 mvc_8(addr, &val);
137 }
138 assert(*addr == val);
139
140 err = munmap(page, 4096);
141 assert(err == 0);
142}
143
125int main(void)
144int main_1(void)
126{
127 struct sigaction act;
128 int err;
129
130 memset(&act, 0, sizeof(act));
131 act.sa_sigaction = handle_signal;
132 act.sa_flags = SA_SIGINFO;
133 err = sigaction(SIGILL, &act, NULL);
134 assert(err == 0);
135 err = sigaction(SIGSEGV, &act, NULL);
136 assert(err == 0);
137
138 safe_puts("[ RUN ] Operation exception");
139 expected.sig = SIGILL;
140 expected.addr = illegal_op;
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;
141 expected.psw_addr = (unsigned long)after_illegal_op;
160 expected.psw_addr = (unsigned long)&after_illegal_op;
142 expected.exception = exception_operation;
143 illegal_op();
144 safe_puts("[ OK ]");
145
146 safe_puts("[ RUN ] Translation exception from stg");
147 check_sigsegv(stg, exception_translation, 42);
148 safe_puts("[ OK ]");
149

--- 8 unchanged lines hidden (view full) ---

158 safe_puts("[ RUN ] Protection exception from mvc");
159 check_sigsegv(mvc_8, exception_protection, 42424242);
160 safe_puts("[ OK ]");
161
162 safe_puts("[ PASSED ]");
163
164 _exit(0);
165}
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

--- 8 unchanged lines hidden (view full) ---

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
194DEFINE_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");