#include #include #include #include #include #include /* copies of ucontext struct matching 6.x kernels */ /* no extra stack contents */ typedef struct k_ucontext { unsigned long uc_flags; struct ucontext *uc_link; stack_t uc_stack; mcontext_t uc_mcontext; sigset_t uc_sigmask; /* mask last for extensibility */ } k_ucontext_t; /* extra stack contents (fpu state, exception frame part (> 4 words) */ typedef struct k_ucontextf { unsigned long uc_flags; struct ucontext *uc_link; stack_t uc_stack; mcontext_t uc_mcontext; sigset_t uc_sigmask; /* mask last for extensibility */ long int uc_filler[174]; } k_ucontextf_t; int depth = 200000 /* 32768 ; 200000 */; const unsigned long i0 = 0x91929394; const unsigned long i1 = 0xa1a2a3a4; const unsigned long i2 = 0xb1b2b3b4; const unsigned long i3 = 0xc1c2c3c4; const unsigned long i4 = 0xd1d2d3d4; const unsigned long i5 = 0xe1e2e3e4; const unsigned long i6 = 0xf1f2f3f4; unsigned long o0; unsigned long o1; unsigned long o2; unsigned long o3; unsigned long o4; unsigned long o5; unsigned long o6; unsigned long parent_usp, child_usp; static void rec(void) { // initialize registers asm( " move.l %0, %%a2\n" " move.l %1, %%a3\n" " move.l %2, %%a4\n" " move.l %3, %%a5\n" " move.l %4, %%d2\n" " move.l %5, %%d3\n" " move.l %6, %%d4\n" : : "m" (i0), "m" (i1), "m" (i2), "m" (i3), "m" (i4), "m" (i5), "m" (i6) : "a2", "a3", "a4", "a5", "d2", "d3", "d4" ); // note current usp asm( " move.l %%sp, %0\n" : "=m" (parent_usp) : : "memory" ); // maybe fork a short-lived process if ((depth & 0x7ff) == 0) if (fork() == 0) { // note current usp asm( " move.l %%sp, %0\n" : "=m" (child_usp) : : "memory" ); exit(0); } if (--depth) rec(); // callee to save & restore registers // compare register contents asm( " move.l %%a2, %0\n" " move.l %%a3, %1\n" " move.l %%a4, %2\n" " move.l %%a5, %3\n" " move.l %%d2, %4\n" " move.l %%d3, %5\n" " move.l %%d4, %6\n" : "=m" (o0), "=m" (o1), "=m" (o2), "=m" (o3), "=m" (o4), "=m" (o5), "=m" (o6) : : "memory" /* "a2", "a3", "a4", "a5", "d2", "d3", "d4" */ ); if (o0 != i0 || o1 != i1 || o2 != i2 || o3 != i3 || o4 != i4 || o5 != i5 || o6 != i6) asm("illegal"); } static void handler(int nevermind) { } static void rthandler(int signo, siginfo_t *info, void *ucontext) { /* use struct ucontext from libc headers */ // ucontext_t *ctx = (ucontext_t *) ucontext; /* use struct ucontext from kernel source */ k_ucontext_t *ctx = (k_ucontext_t *) ucontext; k_ucontextf_t *ctxf = (k_ucontextf_t *) ucontext; if (signo == SIGCHLD) { unsigned long usp, pc; int i; asm( " move.l %%sp, %0\n" : "=m" (usp) : : "memory" ); fprintf(stderr, "parent usp : 0x%lx\n", parent_usp); // fprintf(stderr, "child usp : 0x%lx\n", child_usp); /* top of signal stack - using ucontext w/o uc_filler * Adding filler (which will take additional exception * frame contents for longer tha four word frames), * top of stack may end up above parent usp! */ fprintf(stderr, "handler tos : 0x%lx\n", usp + sizeof(struct siginfo) + sizeof(struct k_ucontext) + 24); if (usp + sizeof(struct siginfo) + sizeof(struct k_ucontext) + 24 > parent_usp) fprintf(stderr, "handler stack overwrote usp!\n"); fprintf(stderr, "handler usp : 0x%lx\n", usp); fprintf(stderr, "signal usp : 0x%lx\n", ctxf->uc_mcontext.gregs[15]); fprintf(stderr, "signal pc : 0x%lx\n", ctxf->uc_mcontext.gregs[16]); fprintf(stderr, "signal fmtv : 0x%lx\n", ctxf->uc_filler[54]); fprintf(stderr, "\n"); } } int main(void) { struct sigaction act; stack_t ss; ss.ss_sp = malloc(SIGSTKSZ); if (ss.ss_sp == NULL) { perror("malloc"); exit(EXIT_FAILURE); } ss.ss_size = SIGSTKSZ; ss.ss_flags = 0; if (sigaltstack(&ss, NULL) == -1) { perror("sigaltstack"); exit(EXIT_FAILURE); } #ifdef USE_ALTSTACK fprintf(stderr, "alt sig stack: 0x%lx - 0x%lx\n", ss.ss_sp, ss.ss_sp + ss.ss_size); act.sa_flags = SA_ONSTACK; act.sa_flags |= SA_SIGINFO; act.sa_sigaction = rthandler; #else act.sa_flags = SA_SIGINFO; act.sa_handler = handler; #endif sigemptyset(&act.sa_mask); if (sigaction(SIGCHLD, &act, NULL) == -1) { perror("sigaction"); exit(EXIT_FAILURE); } rec(); }