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):
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
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`
--- /dev/null
+
+/* 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;
+}
+
--- /dev/null
+
+.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