/** * Call omrdump_create() without passing in core file name. This does not actually test that a core file was actually created. */ TEST(PortDumpTest, dump_test_create_dump_with_NO_name) { OMRPORT_ACCESS_FROM_OMRPORT(portTestEnv->getPortLibrary()); const char *testName = "omrdump_test_create_dump_with_NO_name"; uintptr_t rc = 99; char coreFileName[EsMaxPath]; BOOLEAN doFileVerification = FALSE; #if defined(AIXPPC) struct vario myvar; int sys_parmRC; #endif reportTestEntry(OMRPORTLIB, testName); coreFileName[0] = '\0'; #if 0 /* try out a NULL test (turns out this crashes) */ rc = omrdump_create(NULL, NULL, NULL); /* this crashes */ #endif /* try out a more sane NULL test */ portTestEnv->log("calling omrdump_create with empty filename\n"); #if defined(J9ZOS390) rc = omrdump_create(coreFileName, "IEATDUMP", NULL); #else rc = omrdump_create(coreFileName, NULL, NULL); #endif if (rc == 0) { uintptr_t verifyFileRC = 99; portTestEnv->log("omrdump_create claims to have written a core file to: %s\n", coreFileName); #if defined(AIXPPC) /* We defer to fork abort on AIX machines that don't have "Enable full CORE dump" enabled in smit, * in which case omrdump_create will not return the filename. * So, only check for a specific filename if we are getting full core dumps */ sys_parmRC = sys_parm(SYSP_GET, SYSP_V_FULLCORE, &myvar); if ((sys_parmRC == 0) && (myvar.v.v_fullcore.value == 1)) { doFileVerification = TRUE; } #else /* defined(AIXPPC) */ doFileVerification = TRUE; #endif /* defined(AIXPPC) */ if (doFileVerification) { verifyFileRC = verifyFileExists(PORTTEST_ERROR_ARGS, coreFileName); if (verifyFileRC == 0) { removeDump(OMRPORTLIB, coreFileName, testName); } } } else { outputErrorMessage(PORTTEST_ERROR_ARGS, "omrdump_create returned: %u, with filename: %s", rc, coreFileName); } reportTestExit(OMRPORTLIB, testName); }
/** * Create a dump file of the OS state. * * @param[in] portLibrary The port library. * @param[in] filename Buffer for filename optionally containing the filename where dump is to be output. * @param[out] filename filename used for dump file or error message. * @param[in] dumpType Type of dump to perform. * @param[in] userData Implementation specific data. * * @return 0 on success, non-zero otherwise. * * @note filename buffer can not be NULL. * @note user allocates and frees filename buffer. * @note filename buffer length is platform dependent, assumed to be EsMaxPath/MAX_PATH * * @note if filename buffer is empty, a filename will be generated. * @note if J9UNIQUE_DUMPS is set, filename will be unique. */ uintptr_t omrdump_create(struct OMRPortLibrary *portLibrary, char *filename, char *dumpType, void *userData) { #if !defined(J9OS_I5) char *lastSep; intptr_t pid; #if defined(AIXPPC) int rc = -1; struct vario myvar; int sys_parmRC; /* check to see if full core dumps are enabled */ sys_parmRC = sys_parm(SYSP_GET, SYSP_V_FULLCORE, &myvar); if ((sys_parmRC == 0) && (myvar.v.v_fullcore.value == 1)) { /* full core dumps are enabled, go ahead and use gencore */ unlimitCoreFileSize(portLibrary); rc = genSystemCoreUsingGencore(portLibrary, filename); if (rc == 0) { /* we have successfully generated the system core file */ return rc; } } else { portLibrary->tty_err_printf(portLibrary, "Note: \"Enable full CORE dump\" in smit is set to FALSE and as a result there will be limited threading information in core file.\n"); } #endif /* aix_ppc */ lastSep = filename ? strrchr(filename, DIR_SEPARATOR) : NULL; /* fork a child process from which we'll dump a core file */ if ((pid = fork()) == 0) { /* in the child process */ #if defined(LINUX) /* * on Linux, shared library pages don't appear in core files by default. * Mark all pages writable to force these pages to appear */ markAllPagesWritable(portLibrary); #endif /* defined(LINUX) */ #ifdef AIXPPC /* On AIX we need to ask sigaction for full dumps */ { struct sigaction act; act.sa_handler = SIG_DFL; act.sa_flags = SA_FULLDUMP; sigfillset(&act.sa_mask); sigaction(SIGIOT, &act, 0); } #endif /* * CMVC 95748: don't use abort() after fork() on Linux as this seems to upset certain levels of glibc */ #if defined(LINUX) || defined(OSX) #define J9_DUMP_SIGNAL SIGSEGV #else /* defined(LINUX) || defined(OSX) */ #define J9_DUMP_SIGNAL SIGABRT #endif /* defined(LINUX) || defined(OSX) */ /* Ensure we get default action (core) - reset primary&app handlers */ OMRSIG_SIGNAL(J9_DUMP_SIGNAL, SIG_DFL); /* Move to specified folder before dumping? */ if (lastSep != NULL) { lastSep[1] = '\0'; chdir(filename); } /* * Ensure that ulimit doesn't get in our way */ unlimitCoreFileSize(portLibrary); #if defined(LINUX) || defined(OSX) pthread_kill(pthread_self(), J9_DUMP_SIGNAL); #endif /* defined(LINUX) || defined(OSX) */ abort(); } /* end of child process */ /* We are now in the parent process. First check that the fork() worked OK (CMVC 130439) */ if (pid < 0) { portLibrary->str_printf(portLibrary, filename, EsMaxPath, "insufficient system resources to generate dump, errno=%d \"%s\"", errno, strerror(errno)); return 1; } #if defined(LINUX) || defined(OSX) if (NULL != filename) { /* Wait for child process that is generating core file to finish */ waitpid(pid, NULL, 0); return renameDump(portLibrary, filename, pid, J9_DUMP_SIGNAL); } else { return 1; } #elif defined(AIXPPC) if (filename && filename[0] != '\0') { char corepath[EsMaxPath] = ""; /* Wait for child process that is generating core file to finish */ waitpid(pid, NULL, 0); /* Copy path and remove basename */ if (lastSep != NULL) { strcpy(corepath, filename); corepath[1 + lastSep - filename] = '\0'; } findOSPreferredCoreDir(portLibrary, corepath); /* Search for expected names in the directory <corepath> * and get the absolute path for the generated core file */ appendCoreName(portLibrary, corepath, pid); /* check if the generated core filename ends in .Z (which indicates core compression was on) */ if (strstr(corepath, ".Z") == (corepath + strlen(corepath) - strlen(".Z"))) { /* append the filename with ".Z" */ if ((strlen(filename) + strlen(".Z") + 1) < EsMaxPath) { strcat(filename, ".Z"); } } /* Apply suggested name */ if (rename(corepath, filename)) { portLibrary->str_printf(portLibrary, filename, EsMaxPath, "cannot find core file: \"%s\". check \"ulimit -Hc\" is set high enough", strerror(errno)); return 1; } return 0; } portLibrary->tty_err_printf(portLibrary, "Note: dump may be truncated if \"ulimit -c\" is set too low\n"); /* guess typical filename */ if (lastSep != NULL) { lastSep[1] = '\0'; strcat(filename, "{default OS core name}"); } else if (filename != NULL) { strcpy(filename, "{default OS core name}"); } return 0; #else #error "This platform doesn't have an implementation of omrdump_create" #endif /* #if defined(AIX) */ #else /* J9OS_I5 */ if (getenv("I5_JVM_SUPPLIED_DUMP") == 0) { char corefile[EsMaxPath + 1] = ""; intptr_t i5Pid = getpid(); /* Ensure that ulimit doesn't get in our way */ unlimitCoreFileSize(portLibrary); if (filename && filename[0] != '\0') { if (getenv("J9NO_DUMP_RENAMING")) { char *lastSep = filename ? strrchr(filename, DIR_SEPARATOR) : NULL; if (lastSep != NULL) { lastSep[1] = '\0'; strcat(filename, "core"); } strcpy(corefile, filename); } else { strcpy(corefile, filename); } } else { strcpy(corefile, "core"); strcpy(filename, "{default OS core name}"); } /* Generate the core file. On I5 gencore will always generate a full core dump */ struct coredumpinfo coredumpinfop; memset(&coredumpinfop, 0, sizeof(coredumpinfop)); coredumpinfop.length = strlen(corefile) + 1; coredumpinfop.name = corefile; coredumpinfop.pid = i5Pid; coredumpinfop.flags = GENCORE_VERSION_1; return gencore(&coredumpinfop); } #endif /* J9OS_I5 */ }