void CrashCatcher_Entry(const CrashCatcherExceptionRegisters* pExceptionRegisters) { Object object = initStackPointers(pExceptionRegisters); advanceStackPointerToValueBeforeException(&object); initFloatingPointFlag(&object); do { setStackSentinel(); CrashCatcher_DumpStart(); dumpSignature(&object); dumpFlags(&object); dumpR0toR3(&object); dumpR4toR11(&object); dumpR12(&object); dumpSP(&object); dumpLR_PC_PSR(&object); dumpExceptionPSR(&object); if (object.flags & CRASH_CATCHER_FLAGS_FLOATING_POINT) dumpFloatingPointRegisters(&object); dumpMemoryRegions(CrashCatcher_GetMemoryRegions()); if (!isARMv6MDevice()) dumpFaultStatusRegisters(); checkStackSentinelForStackOverflow(); } while (CrashCatcher_DumpEnd() == CRASH_CATCHER_TRY_AGAIN); }
static void errMsg(args *argv, uint8_t *message, ...) { va_list plist; va_start(plist, message); vsprintf(workSpace(argv), message, plist); va_end(plist); dumpFlags(argv) |= J9TPF_ERRMSG_IN_WKSPC; return; }
/** * \internal Build the z/TPF ELF-format core dump from the JDB built by CCCPSE. * * First figure out the absolute file path (starts with a '/' and * ends with a file suffix) we are to write the dump to, then ensure we * have enough room left over in the Java dump buffer left for us by * CCCPSE. If we do not, return an error. Otherwise, section the buffer * space off, building in order: * - The ELF64 header * - The ELF64 Program Header section * - The ELF64 NOTE section * * Finally, write all the above to the indicated filename, and follow it * with a copy of storage contents from the Java dump buffer, which is * laid out in ascending address order, with the ELF64_Phdrs created to * match the dump buffer. Expect a final file size measured in tens * of megabytes. * * As a matter of protocol, set the first 8 bytes of the Java Dump * Buffer (struct ijavdbf) to zeros so CCCPSE knows it's okay to * write over its contents once we're done working with it. * * The arg block is used for the bi-directional passing of data. Those of its * members which are pointers (most of them, in fact) are used mainly for * output or at least have an output role. The fields of <arg> which are * required are shown as input parameters below. The fields of <arg> which * are used for output are detailed as return values. * * Since the pthread_create() calls limits us to one pointer to type void as the * function's input, and the function is required to return a void pointer, this * function will take the address of the <arg> block as the input parameter, and * will return a pointer to type char which represents the file name which now * contains the full path name of the ELF-format core dump file. There are also * fields in <arg> that will be updated as described below. * * \param[in][out] arg pointer to a user-created datatype 'args', declared * in header file j9osdump_helpers.h * \param[in] arg->OSFilename Pointer to scratch storage for a path + * file name string. It will be presumed * to be at least PATH_MAX+1 in size. * \param[in] arg->wkspcSize 32-bit quantity representing the size in * bytes of the wkSpace field, following. * \param[in] arg->wkSpace 64-bit pointer to scratch workspace for * use by this function. It is recommended * to make it equal to PATH_MAX, since file & * path names will be built in this space. * \param[in][out] arg->flags Indicators as to what is present and what * is not. * \param[in] arg->sii Pointer to scratch storage to be used * forever more as a siginfo_t block * \param[in] arg->uct Pointer to scratch storage to be used * forever more as a ucontext_t block * \param[in] arg->sct Pointer to scratch storage to be used * forever more as a sigcontext block * \param[in] arg->portLibrary Pointer to an initialized OMRPortLibrary * block. If there isn't one at call time, * leave this value NULL and set flag * J9ZTPF_NO_PORT_LIBRARY * \param[in] arg->dibPtr Address of the DIB attached to the faulting * UOW at post-interrupt time. * * \returns Pointer to a hz-terminated string representing the absolute path * name at which the core dump file was written. * * \returns arg->sii Filled in. * \returns arg->uct Filled in. * \returns arg->sct Filled in. * \returns arg->rc Final return code. Zero if successful * (core file built), non-zero if not. * \returns arg->OSFilename Same as the function return value. */ void * ztpfBuildCoreFile(void *argv_block) { #define MOUNT_TFS 4 /* TPF Filesystem equate from imount.h */ args *arg = (args *) argv_block; uint8_t *buffer, *endBuffer; DBFHDR *dbfptr; /* Ptr to JDB's index header */ DIB *dibPtr = dibAddr(arg); /* Ptr to the Dump I'chg Block */ Elf64_Ehdr *ehdrp; /* Pointer to Elf64 file header */ Elf64_Phdr *phdrp; /* Pointer to Elf64_Phdr block */ Elf64_Nhdr *narea; /* Pointer to the ELF NOTE data */ char pathName[PATH_MAX]; /* Working buffer for core.* fname.*/ char *ofn = dumpFilename(arg); /* Output dump file path */ uint32_t ofd; /* File descriptor for output dump */ uintptr_t rc; /* Working return code d.o. */ uintptr_t wPtr; /* Working byte-sized pointer d.o. */ uint64_t phCount; /* Counter of Elf64_Phdrs required */ uint8_t *imageBuffer; /* Start of the JDB's ICB */ uint64_t imageBufferSize; /* Size of data in the ICB */ uint64_t octetsToWrite = 0UL; /* Count of bytes to write */ uint64_t octetsWritten = 0UL; /* Count of bytes written */ uint64_t spcAvailable; /* * If there is a Java dump buffer belonging to this process, then * convert its contents into an Elf64 core dump file; otherwise * return failure. */ if (!(dibPtr->dibjdb)) { /* No dump buffer? Not possible.*/ dumpFlags(arg) |= J9TPF_NO_JAVA_DUMPBUFFER; returnCode (arg) = -1; /* Set error flags & bad RC ... */ return NULL; /* 'Bye. */ } dbfptr = dibPtr->dibjdb; /* Pick up the dump buffer ptr */ if (0L == dbfptr->ijavcnt) { /* Did CCCPSE write us one? */ returnCode (arg) = -1; /* Nope. JDB is locked... */ dumpFlags(arg) |= J9TPF_JDUMPBUFFER_LOCKED; return NULL; /* See ya next time. */ } /* * Calculate the start, end, and net length of the output buffer we'll * use for the ELF-dictated start of the file content. The start address * should, as a matter of good practice, start on a paragraph boundary. */ buffer = (uint8_t *) (dbfptr->ijavbfp); /* Get buffer start as uint8_t ptr */ buffer = (uint8_t *) NEXT_PARA(buffer); /* Start it on next paragraph */ /* boundary. */ endBuffer = buffer + dbfptr->ijavbfl; /* Get bytes left in buffer */ spcAvailable = endBuffer - buffer; /* Get corrected count of bytes */ phCount = dbfptr->ijavcnt; int numJavaPgms = sizeof(javaPgmsToDump) / 5; octetsToWrite = sizeof(Elf64_Ehdr) + ((phCount + 1 + numJavaPgms) * sizeof(Elf64_Phdr)) + NOTE_TABLE_SIZE; /* * Uh oh. Not enough free space remaining in the dump buffer. Now * we've gotta go to the heap and see if there's enough there. Not * much hope; but we have to try it. */ if (octetsToWrite > spcAvailable) { /* Check for available memory, */ buffer = malloc64(octetsToWrite); /* anywhere. We're desperate. */ if (!buffer) { /* If we can't buffer our I/Os, */ returnCode (arg) = -1; /* we are done. Indicate error */ errMsg(arg, "Cannot buffer dump file, out of memory"); dumpFlags(arg) |= J9TPF_OUT_OF_BUFFERSPACE; KEY0(); dbfptr->ijavcnt = 0L; /* Unlock the JDB so CCCPSE can reuse it*/ UNKEY(); return NULL; /* See ya 'round. */ } } /* * We're ready to write the file. First, we need a full path + filename * to represent the "OS filename" we're going to write. Get that path * from the final file name passed in the <tt>args</tt> block, then * follow that with "core.%X.%d" with the TOD in the second node and * the PID number in the third. In this way, we can identify the OS * filename later. * * Next, we'll try to open it in CREATE+WRITE_ONLY mode. If it fails, * halt; else write away! */ splitPathName(ofn, pathName); /* * The "OS filename" will look like ${path}/core.${TOD_in_hex}.${pid} */ sprintf(workSpace(arg), "core.%lX.%d", dibPtr->dstckf, dumpSiginfo(arg)->si_pid); { int pathLen = strlen(pathName); char ebcdicPath[pathLen + 1]; a2e_len(pathName, ebcdicPath, strlen(pathName)); int fsystype = pathconf(ebcdicPath, _TPF_PC_FS_TYPE); if (fsystype == MOUNT_TFS) { errMsg(arg, "Cannot use the tfs for java dumps: path used='%s'\n", pathName); returnCode (arg) = -1; KEY0(); dbfptr->ijavcnt = 0L; /* Unlock the JDB so CCCPSE can reuse it*/ UNKEY(); return NULL; //dir_path_name is within the TFS } } strcat(pathName, workSpace(arg)); ofd = open(pathName, O_WRONLY | O_CREAT | O_EXCL); if (-1 == ofd) { errMsg(arg, "Cannot open() filename %s: %s\n", strerror(errno)); returnCode (arg) = -1; KEY0(); dbfptr->ijavcnt = 0L; /* Unlock the JDB so CCCPSE can reuse it*/ UNKEY(); return NULL; } /* * The file is named and opened. Now we have to go build its ELF-dictated * parts. Set up pointers to the start of each sub-section, and then go * build them. When that's complete, write the file in two parts: first, * the ELF-dictated start, and then follow that with the data in the * ICB. */ wPtr = (uintptr_t) buffer; /* Calc section addresses with single */ /* byte arithmetic */ ehdrp = (Elf64_Ehdr *) wPtr; /* Elf64_Ehdr pointer */ phdrp = (Elf64_Phdr *) (ehdrp + 1); /* Elf64_Phdr pointer */ buildELFHeader(ehdrp); uint64_t numBytes = 0; uint64_t pCount = buildELFPheaderBlk(phdrp, dbfptr, phCount, &numBytes); KEY0(); /* Get into SPK 0, then write the */ ehdrp->e_phnum = pCount; /* absolutely final Phdr count and */ ehdrp->e_phoff = 0x40; /* offset of its table into place in */ UNKEY(); /* the Ehdr, then get back to SPK 1. */ wPtr = (uintptr_t) phdrp; /* Calculate the end address */ wPtr += ((phCount + 1 + numJavaPgms) * sizeof(Elf64_Phdr)); /* of the Elf64_Phdr section */ narea = (Elf64_Nhdr *) wPtr; /* Calculate the address of NOTE sec, */ buildELFNoteArea(narea, dibPtr); /* and go write it there. */ /* * Write the ELF-dictated portion of the file first. */ octetsWritten = writeDumpFile(ofd, buffer, octetsToWrite); if (-1 == octetsWritten) { errMsg(arg, "Error writing dump file %s: %s", ofn, strerror(errno)); dumpFlags(arg) |= J9TPF_FILE_SYSTEM_ERROR; KEY0(); dbfptr->ijavcnt = 0L; /* Unlock the JDB so CCCPSE can reuse it*/ UNKEY(); return NULL; } /* * Finish the output with the ICB portion of the Java Dump Buffer */ imageBuffer = (uint8_t *) cinfc_fast(CINFC_CMMJDB); octetsWritten = writeDumpFile(ofd, imageBuffer, numBytes); if (-1 == octetsWritten) { errMsg(arg, "Error writing dump file %s: %s", ofn, strerror(errno)); dumpFlags(arg) |= J9TPF_FILE_SYSTEM_ERROR; KEY0(); dbfptr->ijavcnt = 0L; /* Unlock the JDB so CCCPSE can reuse it*/ UNKEY(); return NULL; } int i = 0; for (i = 0; i < numJavaPgms; i++) { struct pat * pgmpat = progc(javaPgmsToDump[i], PROGC_PBI); struct ifetch *pgmbase = pgmpat->patgca; if (pgmbase != NULL) { int offset = pgmbase->_iftch_txt_off + pgmbase->_iftch_txt_size + 0x1000; char * text = ((char*) pgmbase) + offset; uint64_t size = pgmpat->patpsize - offset; octetsWritten = writeDumpFile(ofd, text, size); if (-1 == octetsWritten) { errMsg(arg, "Error writing dump file %s: %s", ofn, strerror(errno)); dumpFlags(arg) |= J9TPF_FILE_SYSTEM_ERROR; KEY0(); dbfptr->ijavcnt = 0L; /* Unlock the JDB so CCCPSE can reuse it*/ UNKEY(); return NULL; } } } /* * That's all folks. Close the file and return the so-called "OS Filename" * to the caller as if the OS had written it. */ rc = close(ofd); /* Only try to close() the file once */ if (-1 == rc) { errMsg(arg, "I/O error attempting to close %s:%s\n", ofn, strerror(errno)); KEY0(); dbfptr->ijavcnt = 0L; /* Unlock the JDB so CCCPSE can reuse it*/ UNKEY(); return NULL; } /* * Make sure we have a recognizable IPC permission on the OS filename, * then make sure the JDB buffer is unlocked in case CPSE needs it again. */ rc = chmod(workSpace(arg), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); KEY0(); dbfptr->ijavcnt = 0L; /* Unlock the JDB so CCCPSE can reuse it*/ UNKEY(); /* * Return the filename to the caller. Remember that the buffer containing * it is non-JVM-managed heap space and should be free()d back to it to * avoid a mem leak. */ strcpy(dumpFilename(arg), ofn); /* Store it in the args block so the */ return (void *) ofn; /* caller always has it, and goback.*/ }