#include #include #include #include #include #include #define ACCVIO_ADDR 0x42 #define NTHREADS 8 typedef struct { void *hThread; int thId; int *pExitNow; int bCrashNow; char Name[10]; } ThreadContext; static inline void crunch() { * (long *) ACCVIO_ADDR = 0x56L; } /*-----------------------------------------------------------------*/ /* Linux passes the signal no. and signal context as parameters. */ /* In Linux 2.4 it will support the "standard" 3 parameter conven- */ /* tion used by other UN*X systems - this includes the context */ /* which will be the 3rd parameter. Keep an eye on this!! */ /*-----------------------------------------------------------------*/ int sigCount = 0; void * fSegvHandler(int sigNo, struct sigcontext ctx) { int i_Reg, rc; stackLayout *stack; Dl_info dlInfo; void *retPoint; ThreadContext *pCtx; struct sigcontext *context = &ctx; printf("\n%d.\tContext: %08X\n",sigCount++,context); fflush(stdout); printf("gs: %04X\tfs: %04X\tes: %04X\tds: %04X\n" "edi: %08X\tesi: %08X\tebp: %04X\tesp: %04X\n" "ebx: %08X\tedx: %08X\tecx: %08X\teax: %08X\n" "trap: %d\terr: %d\teip: %08X\tcs: %04X\n" "flag: %08X\tSP: %08X\tss: %04X\tcr2: %08X\n", context->gs, context->fs, context->es, context->ds, context->edi, context->esi, context->ebp, context->esp, context->ebx, context->edx, context->ecx, context->eax, context->trapno, context->err, context->eip, context->cs, context->eflags, context->esp_at_signal, context->ss, context->cr2); fflush(stdout); exit(0); } /* * Fak, FakEven and FakOdd are an involved way to burn some * cpu cycles, nothing else. */ int Fak(ThreadContext *pCtx, int i); int FakEven(int i, ThreadContext *pCtx) { if (i) { return i * Fak(pCtx, i - 1); } else { return 1; } } int FakOdd(int i, ThreadContext *pCtx) { return i * Fak(pCtx, i - 1); } int Fak(ThreadContext *pCtx, int i) { /* * test if our boss wants us to accvio */ if (pCtx->bCrashNow) { /* * if your debugger supports it, you may continue after the line * causing the crash below. the program should then end normally. * * using MSDEV this can be done via right clicking at the line * and selecting 'set next statement' from the menu. */ pCtx->bCrashNow = 0; printf("[%s] Crashing (%08X) at %08X\n",pCtx->Name, pCtx, crunch); crunch(); * pCtx->pExitNow = 1; } if (i % 2) { return FakOdd(i, pCtx); } else { return FakEven(i, pCtx); } } void * WorkerThread (void *arg) { int i; ThreadContext *pCtx = (ThreadContext *) arg; struct sigaction sigAction; if (pCtx->thId != (NTHREADS-1)) { sigemptyset(&sigAction.sa_mask); sigaddset(&sigAction.sa_mask, SIGSEGV); pthread_sigmask(SIG_UNBLOCK, &sigAction.sa_mask, NULL); do { for (i = 0; i < 5; i++) { Fak(pCtx, 6+i); } } while (! * pCtx->pExitNow); } else { sigfillset(&sigAction.sa_mask); sigwait(&sigAction.sa_mask, &i); printf("\n*** sigwait activated by signal %d ***\n",i); fflush(stdout); } return(0); } int main(int argc, char ** argv) { int cc; int i; ThreadContext C[NTHREADS]; void *status; unsigned int nMilliSeconds; int nThread; int ExitNow; struct sigaction sSegvHdl; if (argc > 1) { printf("Usage: %s\n", argv[0]); fflush(stdout); return(-1); } printf("============================================================\n"); printf("[Main] Test : %s\n", argv[0]); printf("[Main] Pid : %d\tHandler : %08X\n",getpid(),fSegvHandler); printf("============================================================\n"); fflush(stdout); sleep(1); sigemptyset(&sSegvHdl.sa_mask); sigaddset(&sSegvHdl.sa_mask, SIGSEGV); sSegvHdl.sa_flags = SA_ONESHOT; sSegvHdl.sa_handler = fSegvHandler; cc = sigaction(SIGSEGV, &sSegvHdl, NULL); ExitNow = 0; for (i = 0; i < NTHREADS; i++) { C[i].bCrashNow = 0; C[i].pExitNow = &ExitNow; C[i].thId = i; sprintf (C[i].Name, "WRK-%02d", i); cc = pthread_create(&C[i].hThread, 0, WorkerThread, (void *) (&C[i])); } nMilliSeconds = 4; printf("[Main] %d worker threads created...\n", NTHREADS); printf("[Main] sleeping %d mSecs...\n", nMilliSeconds); fflush(stdout); sleep(nMilliSeconds); nThread = NTHREADS/2; printf("[Main] telling thread %d to accvio...\n", nThread); fflush(stdout); C[nThread].bCrashNow = 1; printf("[Main] joining all threads now...\n"); fflush(stdout); for (i = 0; i < NTHREADS; i++) { pthread_join(C[i].hThread, &status); } sleep(nMilliSeconds*2); printf("[Main] all threads joined, terminating program...\n"); fflush(stdout); return(0); }