static void ztpfDeriveUcontext( ucontext_t *uscPtr ) { DIB * pDib = ecbp2()->ce2dib; DBFHDR * pJdb = (DBFHDR *)(pDib->dibjdb); DBFITEM * pDbi = NULL; void * lowcore = NULL; if( pJdb ) { /* If JDB contents are for this thread */ if( pJdb->ijavcnt ) { /* and the JDB is unlocked */ pDbi = (DBFITEM *)(pJdb+1); /* Point at the JDB base */ lowcore = (pDbi->ijavsbuf); /* and its low core copy. */ } else { /* Otherwise use what's in the DIB */ lowcore = pDib->dilow; /* Use the low core pointer from DIB */ } } /* * Fill in the uc_mcontext, uc_flags and uc_sigmask fields. * Leave uc_link alone, it has no meaning in or for z/TPF. */ uscPtr->uc_mcontext.psw.mask = pDib->dispw[0]; /* PSW lo half */ uscPtr->uc_mcontext.psw.addr = pDib->dispw[1]; /* PSW hi half */ memcpy( uscPtr->uc_mcontext.gregs, pDib->direg, sizeof(pDib->direg) ); /*GPRs*/ memcpy( uscPtr->uc_mcontext.fpregs.fprs, pDib->dfreg, sizeof(pDib->dfreg) ); /*FPRs*/ uscPtr->uc_flags = ecbp2()->ce2thnum; /* Put the TID in ucontext->uc_flags */ sigprocmask( SIG_SETMASK, NULL, &(uscPtr->uc_sigmask) ); /* Our mask is the old mask */ return; }
void ztpf_nonpreemptible_helper(void) { safeStorage *s = allocateDurableStorage(); uint8_t holdkey; sigset_t newmask; sigset_t oldmask; /* * Go translate the TPF-ish data available at interrupt time into UNIX-ish * formatted blocks in preparation to call the master synchronous signal * handler for the JVM's structured signal handling architecture. This * storage comes from a static storage segment in DJPR. */ s->pDIB = (DIB *) (ecbp2()->ce2dib); s->argv.dibPtr = s->pDIB; translateInterruptContexts(&(s->argv)); /* * Only proceed if (1) the signal is currently NOT blocked, and (2) * if no other interrupt has queued itself. In the interim, if * applicable, sleep for 50 ms. IOW, serialize all synchronous * signals -- we have to, we only have one JDB. */ sigemptyset(&newmask); /* Ensure our 'constant' mask word is zeros */ sigaddset(&newmask, s->siginfo.si_signo); /* Build a constant signal mask word */ do { PROC_LOCK(&(s->pPROC->iproc_JVMLock), holdkey); if (s->pPROC->iproc_tdibptr) { /* Are we blocked because we're already working */ PROC_UNLOCK(&(s->pPROC->iproc_JVMLock), holdkey); /* another signal? If so,unlock */ usleep(50000); /* and sleep for 50 ms. */ } pthread_sigmask(SIG_BLOCK, NULL, &oldmask); /* Test the signal mask again. */ } while ((newmask & oldmask) || (s->pPROC->iproc_tdibptr)); /* * We are released to go process this signal. Do it. The lock we also hold * on our little subsection of the PROC block is also still in effect. * But first, stash the DIB pointer in the IPROC block, then unlock it. */ s->pPROC->iproc_tdibptr = (uint64_t) s->pDIB; /* Stash the faulting DIB pointer */ PROC_UNLOCK(&(s->pPROC->iproc_JVMLock), holdkey); /* * Call the master structured signal handler for synchronous signals. * It's not possible that an async signal can get here. The signal handler will * either hand off execution to the JIT, or will run the dump agents. Do not * expect a return; else the normal SIG_DFL (bye, bye) rule applies. */ masterSynchSignalHandler(s->siginfo.si_signo, &(s->siginfo), &(s->ucontext), s->pDIB->dbrevn); /* * If execution returns to this point, the signal handler returned * here. This means that the thread accepts the consequences of a * return from the SIG_DFL treatment of a fatal signal, which means * an end to the process. */ exit(0); /* UNREACHABLE */ }
int os_check_server(char *server) { #ifndef USE_TPF_DAEMON int rv; int *current_acn; if((rv = inetd_getServerStatus(server)) == INETD_SERVER_STATUS_INACTIVE) return 1; else { current_acn = (int *)cinfc_fast(CINFC_CMMACNUM); if(ecbp2()->ce2acn != *current_acn) return 1; } #endif return 0; }
void ztpf_preemptible_helper(void) { safeStorage *s = allocateDurableStorage(); translateInterruptContexts(&(s->argv)); s->argv.flags = J9TPF_NO_PORT_LIBRARY; s->pDIB = ecbp2()->ce2dib; s->argv.dibPtr = s->pDIB; masterSynchSignalHandler(s->siginfo.si_signo, &(s->siginfo), &(s->ucontext), s->pDIB->dbrevn); /* * Like its "harder" cousin, below, if the signal handler returns here, it is * acknowledging that it wants to exit. Otherwise, don't expect a return. In * the normal case, the faulting thread gets returned to the J9 thread pool * so there's no chance of an accidental return here. */ exit(0); /* UNREACHABLE */ }
/** * \internal * * \details Build the data (in the user-passed <TT>buffer</TT> address) * block to which an Elf64_Phdr will point. Its role is to extract * information passed to it in CE2DIB and IJAVDBF and put them in the * proper places. Sometimes these values require translation to put * them into proper contextual meaning, for example, a hardware PIC code * can infer a signal value. As long as we get close enough, it's good. * The contents of the NOTE section are very poorly documented. * * \note The final sub-section, tagged <i><tt>NT_ZTPF_SERRC</tt></i>, is invented * for this routine's purposes: its role is to express the SE number associated * with the already-written traditional SERRC dump as requested during design. Its * existence may require addition of a method to the Java class which processes * ELF NOTEs in <b><tt>jdmpview</tt></b> - there is no ELF NOTE tag otherwise * suited for this purpose. Otherwise, this information stays buried. * * This function returns the total size of the buffer as its Elf64_Phdr * must report it. * * \param[in] buffer Writeable memory large enough to house the NOTE * section (see \ref NOTE_TABLE_SIZE, above). * \param[in] dibPtr Address of the CPSE<->JVM Dump Interchange Block * belonging to the faulting or requesting Unit Of Work. * \returns * Size, in bytes, of the NOTE table section as written. */ static uintptr_t buildELFNoteArea(Elf64_Nhdr *buffer, DIB *dibPtr) { uintptr_t tableSize = NOTE_TABLE_SIZE; /* Return value */ /* Pointers to the different required NOTE subsections, in sequential * order of appearance: PRSTATUS, PRPSINFO, AUXV, FPREGSET, and * S390_LAST_BREAK. The NOTE subsections are a little bizarre: each has a * header of 0x0c bytes in length, followed by a displayable label of * what it is. In general, these headers end up being 0x14 bytes in length * because their data needs to be fullword-aligned. So, in general, the ptr * prefixed with "nsh_" is the lower of the two addresses, being the * Elf64_Nhdr pointer, and the un-prefixed pointer is where the data goes. * Kinda screwy, but so is the NOTE section itself when there are a number * of subsections in sequence. */ Elf64_Nhdr *nsh_prstat; /* NT_PRSTATUS NOTE header */ prstatus_t *prstat; /* PRSTATUS NOTE data ptr */ Elf64_Nhdr *nsh_prpsin; /* NT_PRPSINFO NOTE header */ prpsinfo_t *prinfo; /* PRPSINFO NOTE data ptr */ Elf64_Nhdr *nsh_auxvxx; /* NT_AUXV NOTE header */ AUXV *auxv; /* NT_AUXV NOTE data ptr */ Elf64_Nhdr *nsh_fpregs; /* NT_FPREGSET NOTE header */ fpregset_t *fpregs; /* NT_FPREGSET data ptr */ Elf64_Nhdr *nsh_lastbr; /* NT_S390_LAST_BREAK NOTE hdr */ uint16_t signalNumber; siginfo_t wSiginfo; DIB *holdDibPtr; DBFHDR *dbfPtr = dibPtr->dibjdb; /* * The ERI sits as the first JDB index item. We have to bump its pointer * past the DBFHDR, which just so happens to be the same length as a DBFITEM * itself. */ DBFITEM *eriRef = (DBFITEM *) dbfPtr + 1; struct cderi *eriPtr = (struct cderi *) (eriRef->ijavsbuf); /* * z/TPF keeps its process information in a unique IPROC block, address it. */ struct iproc *pIPROC = iproc_process; /* Ptr to this PID's IPROC block */ struct iproc *pPIPROC; /* Ptr to mom's PID IPROC block */ /* * The datatypes inside each NOTE section and subsection are so diverse * as to make the commonly-used typecasting approach cumbersome and difficult * to understand. Often working pointer fields which have a length of 1 for * address arithmetic uses are the easiest or best way to do this yet still * have legible code. We use all three of the following data objects in that * vein. */ uint8_t *wSrc; /* General uint8_t address pointer */ uint8_t *wDest; /* General uint8_t address pointer */ uint8_t *wPtr; /* General uint8_t address pointer */ /* * Build the NT_PRSTATUS subsection first */ KEY0(); memset(buffer, 0, tableSize); /* Clear the entire buffer */ nsh_prstat = buffer; /* Start the data sec hdr ptr. */ prstat = (prstatus_t *) NOTE_DATA_OFFSET(nsh_prstat); /* Point at its data*/ nsh_prstat->n_namesz = 5; /* Size of "CORE" = 5 */ nsh_prstat->n_descsz = sizeof(prstatus_t); nsh_prstat->n_type = NT_PRSTATUS; /* Type = 1 */ memcpy(nsh_prstat + 1, "CORE", 5); /* Label this one "CORE". */ /* * The "current signal" value is inferred from the h/w PIC value lookup. * Unfortunately, ztpfDeriveSiginfo() is coded to use the DIB hung off * page 2 of the ECB, not the passed DIB. So hold on to the real * DIB address for this ECB in a safe place, and stuff the passed dibPtr * into page 2 of the ECB before the call, then replace it after the * call. */ holdDibPtr = ecbp2()->ce2dib; /* Substitute the passed DIB */ ecbp2()->ce2dib = dibPtr; /* for the real one, then ... */ UNKEY(); /* reset the SPK to prob state */ ztpfDeriveSiginfo(&wSiginfo); /* While we go build a long */ KEY0(); /* siginfo_t from which to */ prstat->info.si_signo = wSiginfo.si_signo; /* feed the short one. After */ prstat->info.si_code = wSiginfo.si_code; /* we've returned, get back */ prstat->info.si_errno = wSiginfo.si_errno; /* into supv state prot key. */ prstat->cursig = wSiginfo.si_errno; ecbp2()->ce2dib = holdDibPtr; /* Replace the real DIB pointer */ /* * The relative PID values come from the process block .... Just read * them dirty; don't bother with a lock at first, see if it works before * we take a chance on losing ctl with a lock */ prstat->pid = pIPROC->iproc_pid; /* My PID */ prstat->pgid = pIPROC->iproc_pgid; /* My PGID */ prstat->ppid = pIPROC->iproc_pptr->iproc_pid; /* Mom's PID */ /* No concept of a session ID */ /* * The System z TOD clock ticks once every 244 picoseconds. To get to accurate * nanoseconds, we'd need to divide its value by 4.09836. Since we can't * divide by a fractional quantity without going to floating point (and * thereby introducing approximation error & burning more cycles), we * usually trade precision for speed by shifting right 2 bits (dividing by 4) * to yield nanoseconds from a little less than a quarter of a ns. That's * considered close enough. But now that we need _micro_second (ns * 1000) * precision, we'd be amplifying the error. And since we have to divide by 1000 * anyway, we might as well divide by 4098 (would shifting right 12 bits, for * 4096, be close enough? No. That would cause us to lose a full millisecond in * precision error!) to be accurate. So that's what we're doing below, since * we have to eat the cycles in the division operation anyway -- might as well * use the right divisor. Never mind rounding up with the remainder; we're * already generating a larger result than reality because we can't go * fractional. Does it really matter? Nah. But if you're gonna do it, you might * as well do it right .... */ prstat->stime.tv_usec = ecbptr()->ce1istim / 4098; /* Used CPU time */ wDest = (char *) &(prstat->reg); /* Point at offset +0 of reg fld */ /* * The PGM/O PSW is followed by a 16-wide array of ULONGs which * represent the values of all 16 general registers, 0 through 15, * as they were at the time the PGM/N PSW fired. Prepare to copy * them into the NT_PRSTATUS section, lth=128+16 (144). */ wSrc = (char *) (dibPtr->dispw); /* Point @ PSW & general regs */ memcpy(wDest, wSrc, 144); /* Preserve all that data. */ prstat->fpvalid = TRUE; /* Yes, we have floating point */ /* * NT_PRPSINFO is next */ nsh_prpsin = (Elf64_Nhdr *) (prstat + 1); /* Point to next NOTE hdr */ prinfo = (prpsinfo_t *) NOTE_DATA_OFFSET(nsh_prpsin); nsh_prpsin->n_namesz = 5; /* Size of "CORE" = 5 */ nsh_prpsin->n_descsz = sizeof(prpsinfo_t); nsh_prpsin->n_type = NT_PRPSINFO; /* Type = 3 */ memcpy(nsh_prpsin + 1, "CORE", 5); /* Set "CORE" name ... */ prinfo->char_state = 'R'; /* We were 'R'unning. */ prinfo->flag = 0x00400440L; /* Flags are constant */ prinfo->uid = pIPROC->iproc_uid; /* User id & */ prinfo->gid = pIPROC->iproc_gid; /* group id. */ memcpy(&prinfo->pid, &prstat->pid, 16); /* Process ID set again */ strcpy(prinfo->fname, "main"); /* Just like Linux does it */ wSrc = getenv("IBM_JAVA_COMMAND_LINE"); if (wSrc) { strncpy(prinfo->psargs, wSrc, PRARGSZ); prinfo->psargs[PRARGSZ - 1] = '\0'; } /* * NT_AUXV after that ... we fake it (we have no ELF protocols involved * in task switching and thus have no AUXV structure or meaning). */ nsh_auxvxx = (Elf64_Nhdr *) (prinfo + 1); /* Next NOTE header */ auxv = (AUXV *) NOTE_DATA_OFFSET(nsh_auxvxx); /* and data region ptr. */ nsh_auxvxx->n_namesz = 5; /* Size of "CORE" = 5 */ nsh_auxvxx->n_descsz = sizeof(AUXV); nsh_auxvxx->n_type = NT_AUXV; /* Type = 6 */ memcpy(nsh_auxvxx + 1, "CORE", 5); /* Set "CORE" name ... */ memset(auxv, 0, sizeof(AUXV)); /* Fill it out. */ /* * ... then NT_FPREGSET */ nsh_fpregs = (Elf64_Nhdr *) (auxv + 1); /* Next NOTE header */ fpregs = (fpregset_t *) NOTE_DATA_OFFSET(nsh_fpregs); /* and data ptr */ nsh_fpregs->n_namesz = 5; /* Size of "CORE" = 5 */ nsh_fpregs->n_descsz = sizeof(fpregset_t); nsh_fpregs->n_type = NT_FPREGSET; /* Type = 2 */ memcpy(nsh_fpregs + 1, "CORE", 5); /* Set "CORE" name ... */ /* * We don't care what the real FPCR contained. We're setting the mask * only to state that 16 fprs exist. The real FPCR is too hard to get, * anyway. */ fpregs->fpcr = 0x00800000; wSrc = (uint8_t *) &(dibPtr->dfreg); /* Get the adrs of the fp */ wDest = (uint8_t *) &(fpregs->fpreg); /* regs, then copy them */ memcpy(wDest, wSrc, sizeof(fpregs->fpreg)); /* into the note area. */ /* * ... then NT_S390_LAST_BREAK */ nsh_lastbr = (Elf64_Nhdr *) (fpregs + 1); nsh_lastbr->n_namesz = 6; /* Size of "LINUX" = 6 */ nsh_lastbr->n_descsz = 8; /* Always 0x008 bytes. */ nsh_lastbr->n_type = 0x306; /* Type = NT_S390_LAST_BR */ wDest = (uint8_t *) NOTE_DATA_OFFSET(nsh_lastbr); memcpy(nsh_lastbr + 1, "LINUX", 6); /* Set "LINUX" name */ wSrc = (char *) (dibPtr->dbrevn); /* Get NOTE data source ptr */ memcpy(wDest, wSrc, 8); /* and move it in. */ UNKEY(); return tableSize; /* We're done. */ /* * ... and finally, NT_ZTPF_SERRC (made up; we'll need to add the Java * class code to display this) */ wPtr += 8; nsh_lastbr = (Elf64_Nhdr *) (wDest + 8); nsh_lastbr->n_namesz = 5; /* Size of "ZTPF" = 5 */ nsh_lastbr->n_descsz = 68; /* Always 0x044 bytes. */ nsh_lastbr->n_type = 0x500; /* Type = 500 */ memcpy(nsh_lastbr + 1, "ZTPF", 5); /* Set "ZTPF" name ... */ wDest += 0x14; /* and point at data */ sprintf(wDest, "SE-%4.4d OPR-%c%6.6X PGM-%4.4s %5.5c %8.8s", eriPtr->eriseq, eriPtr->eridpfx, eriPtr->eridnum, eriPtr->eridate, eriPtr->eritime); UNKEY(); return tableSize; /* We're done. */ }
void ztpfDeriveSiginfo( siginfo_t *build ) { uint16_t pic; uint16_t ilc; uint8_t dxc; sigvpair_t *translated = NULL; void *lowcore = NULL; DIB *pDib = ecbp2()->ce2dib; DBFHDR *pDbf = (DBFHDR *)(pDib->dibjdb); DBFITEM *pDbi; struct cderi *pEri = NULL; struct iproc *procPtr = iproc_process; /* * If we have a java dump buffer (ijavdbf) which belongs to this * thread AND that buffer is not locked, then use it. We prefer * the low core image in the java dump buffer to the copy in the * DIB; but use the DIB's copy if there's no buffer. */ if( pDbf && pDbf->ijavcnt ) { /* We have the full Error Recording Info, use it. */ pDbi = (DBFITEM *)pDbf+1; /* We have a bunch of void ptrs */ pEri = (struct cderi *)(pDbi->ijavsbuf); /* to cast through ... ugh... */ lowcore = pEri; /* And struct cderi is incomplete ... */ lowcore += (unsigned long int)0x310; /* ai yi yi Lucy. */ } else { /* All we have is the DIB, so use it instead. */ lowcore = pDib->dilow; /* Fixup low core pointer */ pEri = NULL; /* And indicate there's no full ERI. */ } pic = s390FetchPIC( lowcore ); /* Translate the PIC into si_signo & si_code */ translated = (sigvpair_t *)&pic2pair[pic]; build->si_signo = translated->si_signo; build->si_code = translated->si_code; /* * This could just as well have been an "if-then-else" construct, but * it was felt wise to leave it in case testing revealed something else * that requires analysis. */ switch( build->si_signo ) { case SIGFPE: if( 0 == build->si_code ) { /* If we need to interpret DXC bits, */ /* * Returning a good si_code value means we have to interrogate the * DXC value, so go get a normalized version of it. */ dxc = s390FetchDXC( lowcore ); /* * "Sluice" through the acceptable values of the DXC for known si_code * values. If we don't find one, call it SI_KERNEL for lack of any * better idea. */ if( 0x09 == dxc ) build->si_code = FPE_INTDIV; else if( 0x08 == dxc ) build->si_code = FPE_INTOVF; else if( 0x40 == dxc ) build->si_code = FPE_FLTDIV; else if( 0x20 == dxc ) build->si_code = FPE_FLTOVF; else if( 0x10 == dxc ) build->si_code = FPE_FLTUND; else if( 0x08 == dxc ) build->si_code = FPE_FLTRES; else if( 0x80 == dxc ) build->si_code = FPE_FLTINV; else build->si_code = SI_KERNEL; /* Unknown synchronous signal */ } break; /* * SIGSEGV signals need si_addr set to the addr that failed translation * It's in the ERI, but not in the DIB. So if we have an ERI, use it. */ case SIGSEGV: if( build->si_code == SEGV_MAPERR && pEri ) { uint64_t *address; lowcore = pEri; /* The failing vaddr is at ISVTRXAD */ address = lowcore+(unsigned long int)0x1b8; /* at offset 0x1B8 into the ERI*/ build->si_addr = (void *)*address; /* Move the failed address. */ } /* Otherwise leave it zero. */ break; case SIGILL: build->si_addr = (char *)pDib->dispw[1]; /* Failing PSW $IP */ break; default: break; } build->si_pid = procPtr->iproc_pid; /* All of them need PID and */ build->si_uid = procPtr->iproc_uid; /* UID values, with TID & errno */ build->si_ztpf_tid = ecbp2()->ce2thnum; /* values, too. */ build->si_errno = errno; return; }