#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; /*-----------------------------------------------------------------*/ /* Layout of the Linux/390 stack... */ /*-----------------------------------------------------------------*/ typedef struct stackLayout { void *backChain; /* Pointer to previous stackarea */ int *endOfStack; /* Unused by Linux/390 */ int glue[2]; int scratch[2]; int gprArgs[10]; /* Registers 6-15 saved on entry */ int notUsed[9]; char stackWork; } stackLayout; /*-----------------------------------------------------------------*/ /* 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; char *thName; struct sigcontext *context = &ctx; pCtx = (ThreadContext *) context->sregs->regs.acrs[2]; if (pCtx == NULL) thName = "Main"; else thName = pCtx->Name; printf("\n%d.\t[%s] Context: %08X\n",sigCount++,thName,context); fflush(stdout); /*-----------------------------------------------------------------*/ /* Display Program Status Word (PSW). This contains of 2 32 bit */ /* words: the 1st contains important flags and masks, the second */ /* consists of a bit indicating addressing mode (24 or 31 bit) and */ /* a 31 bit program counter. */ /*-----------------------------------------------------------------*/ printf("PSW: %08X %08X\n",context->sregs->regs.psw.mask, context->sregs->regs.psw.addr); fflush(stdout); /*-----------------------------------------------------------------*/ /* Display general registers... */ /*-----------------------------------------------------------------*/ printf("\nGeneral Registers\n-----------------\n"); for (i_Reg = 0; i_Reg <= 15; i_Reg += 2) printf("GPR%02d = %08X\tGPR%02d = %08X\n", i_Reg,context->sregs->regs.gprs[i_Reg], i_Reg+1,context->sregs->regs.gprs[i_Reg+1]); fflush(stdout); /*-----------------------------------------------------------------*/ /* Display access control registers... */ /*-----------------------------------------------------------------*/ printf("\nAccess Registers\n----------------\n"); for (i_Reg = 0; i_Reg <= 15; i_Reg += 2) printf("ACR%02d = %08X\tACR%02d = %08X\n", i_Reg,context->sregs->regs.acrs[i_Reg], i_Reg+1,context->sregs->regs.acrs[i_Reg+1]); /*-----------------------------------------------------------------*/ /* Attempt backtrace... Extract the value of R15 from the context */ /* and use it to backchain through the stack area as this is the */ /* register Linux/390 uses as a stack pointer. Keep backtracking */ /* until a NULL pointer is encountered. R14 is used as the link- */ /* age register by Linux/390, it points to the return address of */ /* the routine calling the owner of this stack area. We use dladdr */ /* on the off chance that the routine is in a shared library. */ /*-----------------------------------------------------------------*/ printf("\nStack Backtrace\n---------------\n"); for (stack = (stackLayout *) context->sregs->regs.gprs[15]; stack != NULL; stack = stack->backChain) { /*------------------------------------------------------------*/ /* Linux/390 is really 31 bit, the top bit is ignored in */ /* forming addresses. */ /*------------------------------------------------------------*/ retPoint = (void *) (stack->gprArgs[8] & 0x7fffffff); dladdr((void *) retPoint, &dlInfo); printf("Called by: %08X %s\tStack: %08X\n", retPoint, dlInfo.dli_sname, (int) stack & 0x7fffffff); } 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)\n",pCtx->Name, pCtx); * (long *) ACCVIO_ADDR = 0x56L; * 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; __asm__ __volatile__ ("\tsar\t2,%0" : : "r" (pCtx) : "memory" ); if (pCtx->thId != (NTHREADS-1)) { 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); }