示例#1
0
/**
 * \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;
}
示例#2
0
/**
 * \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.                */
}