103 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			103 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
 | |
| /* 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;
 | |
| }
 | |
| 
 | 
