#include #include #include #include #include #include #include /* how deep at recursion */ int depth = 200000; const int max_depth = 200000; /* how deep still on the stack while returning */ int rdepth = 0; 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; /* extra frame size used for sa_handler case */ static const int frame_size_change[16] = { [1] = -1, /* sizeof_field(struct frame, un.fmt1), */ [2] = 4, /* sizeof_field(struct frame, un.fmt2), */ [3] = 4, /* sizeof_field(struct frame, un.fmt3), */ [4] = 8, /* sizeof_field(struct frame, un.fmt4), */ [5] = -1, /* sizeof_field(struct frame, un.fmt5), */ [6] = -1, /* sizeof_field(struct frame, un.fmt6), */ [7] = 52, /* sizeof_field(struct frame, un.fmt7), */ [8] = -1, /* sizeof_field(struct frame, un.fmt8), */ [9] = 12, /* sizeof_field(struct frame, un.fmt9), */ [10] = 20, /* sizeof_field(struct frame, un.fmta), */ [11] = 84, /* sizeof_field(struct frame, un.fmtb), */ [12] = -1, /* sizeof_field(struct frame, un.fmtc), */ [13] = -1, /* sizeof_field(struct frame, un.fmtd), */ [14] = -1, /* sizeof_field(struct frame, un.fmte), */ [15] = -1, /* sizeof_field(struct frame, un.fmtf), */ }; static inline int frame_extra_sizes(int f) { return frame_size_change[f]; } 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) 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"); rdepth++; } static void handler(int signo, int vector, struct sigcontext *ctx) { // use if only taking signo argument // struct sigcontext *ctx = (struct sigcontext *) ((unsigned long) &signo + 24); unsigned long *frame = (unsigned long *)((unsigned long) &signo - 4); if (signo == SIGCHLD) { unsigned long usp, end_frame, extra; int i; asm( " move.l %%sp, %0\n" : "=m" (usp) : : "memory" ); fprintf(stderr, "stack depth : %d\n", max_depth - depth); fprintf(stderr, "retn. depth : %d\n", max_depth - rdepth); fprintf(stderr, "parent usp : 0x%lx\n", parent_usp); /* top of signal stack - including extra size for * exception frames longer than four words */ // end_frame = (unsigned long) frame + 32 + sizeof(struct sigcontext); extra = frame_extra_sizes(ctx->sc_formatvec >> 12); end_frame = (unsigned long) ctx + sizeof(struct sigcontext) + extra; if (end_frame > parent_usp) fprintf(stderr, "signal frame overwrote parent usp!\n"); fprintf(stderr, "frame end : 0x%lx\n", end_frame); fprintf(stderr, "frame start : 0x%lx\n", frame); fprintf(stderr, "handler usp : 0x%lx\n", usp); // fprintf(stderr, "signal vec : 0x%lx\n", vector); fprintf(stderr, "signal usp : 0x%lx\n", ctx->sc_usp); fprintf(stderr, "signal pc : 0x%lx\n", ctx->sc_pc); fprintf(stderr, "signal fmtv : 0x%lx\n", ctx->sc_formatvec); fprintf(stderr, "\n"); } } static void rthandler(int signo, siginfo_t *info, void *ucontext) { ucontext_t *ctx = (ucontext_t *) ucontext; unsigned long *frame = (unsigned long *)((unsigned long) &signo - 4); if (signo == SIGCHLD) { unsigned long usp, end_frame; int i; asm( " move.l %%sp, %0\n" : "=m" (usp) : : "memory" ); fprintf(stderr, "stack depth : %d\n", max_depth - depth); fprintf(stderr, "retn. depth : %d\n", max_depth - rdepth); fprintf(stderr, "parent usp : 0x%lx\n", parent_usp); /* top of signal stack - extra size for exception * frames longer than four words follows uc_filler[54] */ // end_frame = (unsigned long) info + sizeof(struct siginfo) + sizeof(struct ucontext); end_frame = (unsigned long) ucontext + sizeof(struct ucontext); if (end_frame > parent_usp) fprintf(stderr, "signal stack overwrote parent usp!\n"); fprintf(stderr, "frame end : 0x%lx\n", end_frame); fprintf(stderr, "frame start : 0x%lx\n", frame); fprintf(stderr, "handler usp : 0x%lx\n", usp); fprintf(stderr, "signal usp : 0x%lx\n", ctx->uc_mcontext.gregs[15]); fprintf(stderr, "signal pc : 0x%lx\n", ctx->uc_mcontext.gregs[16]); fprintf(stderr, "signal fmtv : 0x%lx\n", ctx->uc_filler[54]); #if 0 /* dump frame contents not used for exception frame extra */ if (frame_extra_sizes(ctx->uc_filler[54] >> 12) <= 0) for (i=0; i < 26; i++) { if ( !(i & 3) ) fprintf(stderr, "\nextra %d\t", i); fprintf(stderr, "0x%lx\t", ctx->uc_filler[55+i]); } #endif fprintf(stderr, "\n"); #if 0 /* dump stored registers */ fprintf(stderr, "signal stack: 0x%lx\n", ctx->uc_stack.ss_sp); fprintf(stderr, "signal usp : 0x%lx\n", ctx->uc_mcontext.gregs[15]); fprintf(stderr, "signal pc : 0x%lx\n", ctx->uc_mcontext.gregs[16]); fprintf(stderr, "signal f.d1 : 0x%lx\n", ctx->uc_filler[41]); fprintf(stderr, "signal f.d2 : 0x%lx\n", ctx->uc_filler[42]); fprintf(stderr, "signal f.d3 : 0x%lx\n", ctx->uc_filler[43]); fprintf(stderr, "signal f.d4 : 0x%lx\n", ctx->uc_filler[44]); fprintf(stderr, "signal f.d5 : 0x%lx\n", ctx->uc_filler[45]); fprintf(stderr, "signal f.a0 : 0x%lx\n", ctx->uc_filler[46]); fprintf(stderr, "signal f.a1 : 0x%lx\n", ctx->uc_filler[47]); fprintf(stderr, "signal f.a2 : 0x%lx\n", ctx->uc_filler[48]); fprintf(stderr, "signal f.d0 : 0x%lx\n", ctx->uc_filler[49]); fprintf(stderr, "signal f.od0: 0x%lx\n", ctx->uc_filler[50]); fprintf(stderr, "signal f.sad: 0x%lx\n", ctx->uc_filler[51]); fprintf(stderr, "signal f.sr : 0x%lx\n", ctx->uc_filler[52]); fprintf(stderr, "signal f.pc : 0x%lx\n", ctx->uc_filler[53]); fprintf(stderr, "signal a2 : 0x%lx\n", ctx->uc_mcontext.gregs[10]); fprintf(stderr, "signal a3 : 0x%lx\n", ctx->uc_mcontext.gregs[11]); fprintf(stderr, "signal a4 : 0x%lx\n", ctx->uc_mcontext.gregs[12]); fprintf(stderr, "signal a5 : 0x%lx\n", ctx->uc_mcontext.gregs[13]); fprintf(stderr, "signal d2 : 0x%lx\n", ctx->uc_mcontext.gregs[2]); fprintf(stderr, "signal d3 : 0x%lx\n", ctx->uc_mcontext.gregs[3]); fprintf(stderr, "signal d4 : 0x%lx\n\n", ctx->uc_mcontext.gregs[4]); #endif } } int main(int use_rt) { struct sigaction act; stack_t ss; use_rt--; /* poor man's getopt - use none, one or two args */ fprintf(stderr, "use_rt = %d\n", use_rt); ss.ss_sp = malloc(SIGSTKSZ); if (ss.ss_sp == NULL) { perror("malloc"); exit(EXIT_FAILURE); } ss.ss_size = SIGSTKSZ; ss.ss_flags = 0; if (use_rt & 2) fprintf(stderr, "alt stack 0x%lx - 0x%lx\n", ss.ss_sp, ss.ss_sp + ss.ss_size); if (sigaltstack(&ss, NULL) == -1) { perror("sigaltstack"); exit(EXIT_FAILURE); } memset(&act, 0, sizeof(act)); sigemptyset(&act.sa_mask); if (use_rt) { act.sa_flags = SA_SIGINFO; if (use_rt & 2) act.sa_flags |= SA_ONSTACK; fprintf(stderr, "using sa_sigaction\n"); act.sa_sigaction = rthandler; } else { fprintf(stderr, "using sa_handler\n"); act.sa_handler = handler; } if (sigaction(SIGCHLD, &act, NULL) == -1) { perror("sigaction"); exit(EXIT_FAILURE); } rec(); }