test57: test that state isn't corrupted after a signal handler being executed.
This commit is contained in:
parent
b43f3b6bfc
commit
83fc90c8c3
@ -12,14 +12,14 @@ OBJ= test1 test2 test3 test4 test5 test6 test7 test8 test9 \
|
||||
test30 test31 test32 test34 test35 test36 test37 test38 \
|
||||
test39 t10a t11a t11b test40 t40a t40b t40c t40d t40e t40f test41 \
|
||||
test42 test45 test47 test48 test49 test50 test51 test52 test53 \
|
||||
test54 test55 test56
|
||||
test54 test55 test56
|
||||
|
||||
BIGOBJ= test20 test24
|
||||
ROOTOBJ= test11 test33 test43 test44 test46
|
||||
GCCOBJ= test45-gcc test49-gcc
|
||||
GCCFPUOBJ= test51-gcc test52-gcc
|
||||
|
||||
all: $(OBJ) $(BIGOBJ) $(GCCOBJ) $(GCCFPUOBJ) $(ROOTOBJ)
|
||||
all: $(OBJ) $(BIGOBJ) $(GCCOBJ) $(GCCFPUOBJ) $(ROOTOBJ) test57
|
||||
chmod 755 *.sh run
|
||||
|
||||
$(OBJ):
|
||||
@ -112,3 +112,5 @@ test52-gcc: test52.c
|
||||
test54: test54.c
|
||||
test55: test55.c
|
||||
test56: test56.c
|
||||
test57: test57.c test57loop.S
|
||||
which $(GCC) >/dev/null && $(GCC) $(CFLAGS-GCC) -o $@ test57.c test57loop.S
|
||||
|
2
test/run
2
test/run
@ -14,7 +14,7 @@ badones= # list of tests that failed
|
||||
tests=" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
||||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||
41 42 43 44 45 45-gcc 46 47 48 49 49-gcc 50 \
|
||||
51 51-gcc 52 52-gcc 53 54 55 \
|
||||
51 51-gcc 52 52-gcc 53 54 55 57 \
|
||||
sh1.sh sh2.sh"
|
||||
tests_no=`expr 0`
|
||||
|
||||
|
102
test/test57.c
Normal file
102
test/test57.c
Normal file
@ -0,0 +1,102 @@
|
||||
|
||||
/* This test tests whether registers are correctly restored after a
|
||||
* signal handler is executed. The assembly file (test57loop.S) puts
|
||||
* 'random' values in the registers, and the C code checks whether
|
||||
* these values are the same, before and after the signal handler.
|
||||
*/
|
||||
|
||||
#define _POSIX_SOURCE 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <err.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#define SIGNAL SIGUSR1
|
||||
|
||||
volatile int remaining_invocations = 2, handler_level = 0;
|
||||
|
||||
void check_context_loop(void);
|
||||
|
||||
#define REGS 8 /* how many registers pusha and popa save. */
|
||||
|
||||
#define ESP 3 /* where is esp saved? */
|
||||
|
||||
unsigned long newstate[REGS], origstate[REGS];
|
||||
|
||||
void handler(int signal)
|
||||
{
|
||||
int st;
|
||||
sigset_t set, oset;
|
||||
handler_level++;
|
||||
remaining_invocations--;
|
||||
if(remaining_invocations < 1)
|
||||
return;
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGNAL);
|
||||
sigprocmask(SIG_UNBLOCK, &set, &oset);
|
||||
wait(&st);
|
||||
handler_level--;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pid_t child_pid;
|
||||
|
||||
printf("Test 57 ");
|
||||
|
||||
if(signal(SIGNAL, handler) == SIG_ERR)
|
||||
err(1, "signal");
|
||||
|
||||
fflush(NULL);
|
||||
|
||||
if((child_pid=fork()) < 0)
|
||||
err(1, "fork");
|
||||
|
||||
if(child_pid == 0) {
|
||||
pid_t ppid = 0;
|
||||
|
||||
/* Keep signaling the parent until
|
||||
* it disappears.
|
||||
*/
|
||||
while((ppid = getppid()) > 1) {
|
||||
if(kill(ppid, SIGNAL) < 0)
|
||||
err(1, "kill");
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
} else {
|
||||
int i;
|
||||
int err = 0;
|
||||
|
||||
check_context_loop();
|
||||
|
||||
/* correct 2nd esp for 'pusha' difference. */
|
||||
newstate[ESP] += REGS*4;
|
||||
|
||||
for(i = 0; i < REGS; i++) {
|
||||
#if 0
|
||||
printf("%d %08lx %08lx diff ",
|
||||
i, newstate[i], origstate[i]);
|
||||
#endif
|
||||
if(newstate[i] != origstate[i]) {
|
||||
fprintf(stderr, "reg %d changed; "
|
||||
"found 0x%lx, expected 0x%lx\n",
|
||||
i, newstate[i], origstate[i]);
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(!err) printf(" ok\n");
|
||||
|
||||
exit(err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
65
test/test57loop.S
Normal file
65
test/test57loop.S
Normal file
@ -0,0 +1,65 @@
|
||||
|
||||
.globl _check_context_loop
|
||||
.globl _remaining_invocations
|
||||
.globl _origstate
|
||||
.globl _newstate
|
||||
|
||||
#define JUNK 0xCC0FFEE0
|
||||
|
||||
#define COPY(dest, offset) \
|
||||
mov $dest, %ebp ; \
|
||||
mov 4*offset(%esp), %ebx ; \
|
||||
mov %ebx, 4*offset(%ebp) ;
|
||||
|
||||
/* Copy the result of a pusha to dest. */
|
||||
#define COPYA(dest) \
|
||||
COPY(dest, 0); COPY(dest, 1); COPY(dest, 2); COPY(dest, 3); \
|
||||
COPY(dest, 4); COPY(dest, 5); COPY(dest, 6); COPY(dest, 7);
|
||||
|
||||
.text
|
||||
/* void check_context_loop() */
|
||||
_check_context_loop:
|
||||
/* Save original context so we can restore it. */
|
||||
pusha
|
||||
|
||||
/* Put some junk in the registers.
|
||||
* We want to junk the state, and junk it differently per reg,
|
||||
* so it's likelier corruption is actually detected. We can't
|
||||
* touch %esp but we can verify that it doesn't change from its
|
||||
* current value.
|
||||
*/
|
||||
mov $JUNK+1, %eax
|
||||
mov $JUNK+2, %ebx
|
||||
mov $JUNK+3, %ecx
|
||||
mov $JUNK+4, %edx
|
||||
mov $JUNK+5, %ebp
|
||||
mov $JUNK+6, %esi
|
||||
mov $JUNK+7, %edi
|
||||
|
||||
/* Save the junked state so we can compare it. */
|
||||
pusha
|
||||
cont:
|
||||
/* Check if we're done. */
|
||||
cmpl $0, (_remaining_invocations)
|
||||
jz done
|
||||
|
||||
/* We're not done. */
|
||||
|
||||
/* Restart loop. */
|
||||
jmp cont
|
||||
|
||||
done:
|
||||
/* Save the junked, but should be unmodified state
|
||||
* so we can copy it.
|
||||
*/
|
||||
pusha
|
||||
COPYA(_newstate);
|
||||
popa
|
||||
|
||||
/* copy and restore junked state */
|
||||
COPYA(_origstate);
|
||||
popa
|
||||
|
||||
/* restore original state and return */
|
||||
popa
|
||||
ret
|
Loading…
x
Reference in New Issue
Block a user