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.
15 #define DEFINE_ASM_FUNCTION(name, body) \
16 asm(".globl " #name "\n" \
23 void illegal_op(void);
24 extern const char after_illegal_op
;
25 DEFINE_ASM_FUNCTION(illegal_op
,
27 ".globl after_illegal_op\n"
30 void stg(void *dst
, unsigned long src
);
31 DEFINE_ASM_FUNCTION(stg
, "stg %r3,0(%r2)")
33 void mvc_8(void *dst
, void *src
);
34 DEFINE_ASM_FUNCTION(mvc_8
, "mvc 0(8,%r2),0(%r3)")
36 extern const char return_from_main_1
;
38 static void safe_puts(const char *s
)
40 write(0, s
, strlen(s
));
46 exception_translation
,
53 unsigned long psw_addr
;
54 enum exception exception
;
57 static void handle_signal(int sig
, siginfo_t
*info
, void *ucontext
)
63 if (sig
!= expected
.sig
) {
64 safe_puts("[ FAILED ] wrong signal");
68 if (info
->si_addr
!= expected
.addr
) {
69 safe_puts("[ FAILED ] wrong si_addr");
73 if (((ucontext_t
*)ucontext
)->uc_mcontext
.psw
.addr
!= expected
.psw_addr
) {
74 safe_puts("[ FAILED ] wrong psw.addr");
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");
87 case exception_protection
:
88 err
= mprotect(expected
.addr
, 4096, PROT_READ
| PROT_WRITE
);
90 safe_puts("[ FAILED ] mprotect() failed");
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
) {
105 safe_puts("[ FAILED ] backtrace() is broken");
110 static void check_sigsegv(void *func
, enum exception exception
,
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);
126 addr
= page
+ (val
& 0x1ff);
128 expected
.sig
= SIGSEGV
;
129 expected
.addr
= page
;
130 expected
.psw_addr
= (unsigned long)func
;
131 expected
.exception
= exception
;
135 assert(func
== mvc_8
);
138 assert(*addr
== val
);
140 err
= munmap(page
, 4096);
146 struct sigaction act
;
149 memset(&act
, 0, sizeof(act
));
150 act
.sa_sigaction
= handle_signal
;
151 act
.sa_flags
= SA_SIGINFO
;
152 err
= sigaction(SIGILL
, &act
, NULL
);
154 err
= sigaction(SIGSEGV
, &act
, NULL
);
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
;
165 safe_puts("[ RUN ] Translation exception from stg");
166 check_sigsegv(stg
, exception_translation
, 42);
169 safe_puts("[ RUN ] Translation exception from mvc");
170 check_sigsegv(mvc_8
, exception_translation
, 4242);
173 safe_puts("[ RUN ] Protection exception from stg");
174 check_sigsegv(stg
, exception_protection
, 424242);
177 safe_puts("[ RUN ] Protection exception from mvc");
178 check_sigsegv(mvc_8
, exception_protection
, 42424242);
181 safe_puts("[ PASSED ]");
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.
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"
206 ".cfi_def_cfa_offset 160");