/** * \brief Translate z/TPF-ish data into UNIX-ish context data * * This routine sets up all three failure context records needed * by UNIX-ish 3-argument signal handlers: the sigcontext, the * ucontext_t, and siginfo_t structures, one at a time. * * \param[in][out] si Address of a blank siginfo_t buffer. * \param[in][out] uc Address of a blank ucontext_t buffer. * \param[in][out] sc Address of a blank struct sigcontext buffer. * * \returns void All blank buffer regions filled in. */ void translateInterruptContexts( args *argv ) { ztpfDeriveSiginfo( dumpSiginfo(argv) ); ztpfDeriveUcontext( dumpUcontext(argv) ); ztpfDeriveSigcontext( dumpSigcontext(argv), dumpUcontext(argv) ); return; }
/** * \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. */ }