/******************************************************************************* * Copyright IBM Corp. and others 1998 * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ * or the Apache License, Version 2.0 which accompanies this distribution and * is available at https://www.apache.org/licenses/LICENSE-2.0. * * This Source Code may also be made available under the following * Secondary Licenses when the conditions for such availability set * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU * General Public License, version 2 with the GNU Classpath * Exception [1] and GNU General Public License, version 2 with the * OpenJDK Assembly Exception [2]. * * [1] https://www.gnu.org/software/classpath/license.html * [2] https://openjdk.org/legal/assembly-exception.html * * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0 *******************************************************************************/ #include <string.h> #include <stdarg.h> #include <stddef.h> #include <stdlib.h> #include <sys/types.h> #include <time.h> #include "omrcomp.h" #include "omrtrace_internal.h" #include "pool_api.h" /******************************************************************************* * name - getTraceLock * description - Obtains the trace lock * parameters - OMR_TraceThread * returns - True or false ******************************************************************************/ int32_t getTraceLock(OMR_TraceThread *thr) { incrementRecursionCounter(thr); omrthread_monitor_enter(OMR_TRACEGLOBAL(traceLock)); return TRUE; } /******************************************************************************* * name - freeTraceLock * description - Frees the trace lock * parameters - OMR_TraceThread * returns - True or false ******************************************************************************/ int32_t freeTraceLock(OMR_TraceThread *thr) { omrthread_monitor_exit(OMR_TRACEGLOBAL(traceLock)); decrementRecursionCounter(thr); return TRUE; } void incrementRecursionCounter(OMR_TraceThread *thr) { thr->recursion++; } void decrementRecursionCounter(OMR_TraceThread *thr) { thr->recursion--; } /** * Acquire the global trace lock if the trace engine's initialization phase * has completed. */ void checkGetTraceLock(OMR_TraceThread *thr) { if (NULL != thr) { getTraceLock(thr); } else { UT_ASSERT(OMR_TRACE_ENGINE_MT_ENABLED != OMR_TRACEGLOBAL(initState)); } } /** * Release the global trace lock if the trace engine's initialization phase * has completed. */ void checkFreeTraceLock(OMR_TraceThread *thr) { if (NULL != thr) { freeTraceLock(thr); } else { UT_ASSERT(OMR_TRACE_ENGINE_MT_ENABLED != OMR_TRACEGLOBAL(initState)); } } /******************************************************************************* * name - expandString * description - take a string and substutue pid number for %p, date for * %d and time for %t * parameters - returnBuffer - the expanded string as return * value - the original string * returns - OMR_ERROR_NONE or OMR_ERROR_ILLEGAL_ARGUMENT ******************************************************************************/ omr_error_t expandString(char *returnBuffer, const char *original, BOOLEAN atRuntime) { OMRPORT_ACCESS_FROM_OMRPORT(OMR_TRACEGLOBAL(portLibrary)); char formatString[MAX_IMAGE_PATH_LENGTH]; char resultString[MAX_IMAGE_PATH_LENGTH]; const char *originalCursor = original; char *formatCursor = formatString; size_t formatSpace = sizeof(formatString) - 1; /* leave room for trailing NUL */ if ((NULL == returnBuffer) || (NULL == original)) { return OMR_ERROR_ILLEGAL_ARGUMENT; } for (;; originalCursor += 1) { char originalChar = *originalCursor; const char *replacement = originalCursor; size_t replacementLength = 1; if ('\0' == originalChar) { break; } if ('%' == originalChar) { originalCursor += 1; originalChar = *originalCursor; if ('p' == originalChar) { const char * const pidTokenString = "%pid"; replacement = pidTokenString; replacementLength = strlen(pidTokenString); } else if ('d' == originalChar) { const char * const dateTokenString = "%Y%m%d"; replacement = dateTokenString; replacementLength = strlen(dateTokenString); } else if ('t' == originalChar) { const char * const timeTokenString = "%H%M%S"; replacement = timeTokenString; replacementLength = strlen(timeTokenString); } else { /* character following % was not 'p', 'd' or 't' */ reportCommandLineError( atRuntime, "Invalid special character '%%%c' in a trace filename. Only %%p, %%d and %%t are allowed.", originalChar); returnBuffer[0] = '\0'; return OMR_ERROR_ILLEGAL_ARGUMENT; } } if (formatSpace < replacementLength) { /* insufficient space for replacement */ break; } memcpy(formatCursor, replacement, replacementLength); formatCursor += replacementLength; formatSpace -= replacementLength; } *formatCursor = '\0'; { int64_t curTime = omrtime_current_time_millis(); struct J9StringTokens *stringTokens = omrstr_create_tokens(curTime); if (NULL == stringTokens) { returnBuffer[0] = '\0'; return OMR_ERROR_ILLEGAL_ARGUMENT; } if (omrstr_subst_tokens(resultString, MAX_IMAGE_PATH_LENGTH, formatString, stringTokens) > MAX_IMAGE_PATH_LENGTH) { returnBuffer[0] = '\0'; omrstr_free_tokens(stringTokens); return OMR_ERROR_ILLEGAL_ARGUMENT; } omrstr_free_tokens(stringTokens); } strncpy(returnBuffer, resultString, 255); returnBuffer[255] = '\0'; return OMR_ERROR_NONE; } /******************************************************************************* * name - listCounters * description - Print out the entire trace counter table. * parameters - void * returns - void ******************************************************************************/ void listCounters(void) { int i; #define TEMPBUFLEN 150 char tempBuf[TEMPBUFLEN]; intptr_t f; UtComponentData *compData = OMR_TRACEGLOBAL(componentList)->head; OMRPORT_ACCESS_FROM_OMRPORT(OMR_TRACEGLOBAL(portLibrary)); UT_DBGOUT(1, ("<UT> Listing trace counters\n")); if ((f = omrfile_open("utTrcCounters", EsOpenText | EsOpenWrite | EsOpenTruncate | EsOpenCreateNoTag, 0)) < 0) { if ((f = omrfile_open("utTrcCounters", EsOpenText | EsOpenWrite | EsOpenCreate | EsOpenCreateNoTag, 0666)) < 0) { /* Unable to open tracepoint counter file %s, counters redirected to stderr. */ } } /* Writing trace count info to %s */ /* list currently loaded components */ while (compData != NULL) { if (compData->tracepointcounters != NULL) { for (i = 0; i < compData->tracepointCount; i++) { if (compData->tracepointcounters[i] > 0) { if (f < 0) { omrtty_err_printf("%s.%d %ld \n", compData->qualifiedComponentName, i, compData->tracepointcounters[i]); } else { omrstr_printf(tempBuf, TEMPBUFLEN, "%s.%d %lld \n", compData->qualifiedComponentName, i, compData->tracepointcounters[i]); /* convert to ebcdic if on zos */ omrfile_write_text(f, tempBuf, strlen(tempBuf)); } } } } compData = compData->next; } /* list the unloaded components */ compData = OMR_TRACEGLOBAL(unloadedComponentList)->head; while (compData != NULL) { if (compData->tracepointcounters != NULL) { for (i = 0; i < compData->tracepointCount; i++) { if (compData->tracepointcounters[i] > 0) { if (f < 0) { omrtty_err_printf("%s.%d %ld \n", compData->qualifiedComponentName, i, compData->tracepointcounters[i]); } else { omrstr_printf(tempBuf, TEMPBUFLEN, "%s.%d %lld \n", compData->qualifiedComponentName, i, compData->tracepointcounters[i]); /* convert to ebcdic if on zos */ omrfile_write_text(f, tempBuf, strlen(tempBuf)); } } } } compData = compData->next; } if (f > 0) { omrfile_close(f); } #undef TEMPBUFLEN } /******************************************************************************* * name - getTimestamp * description - Get the time in various component units * parameters - pointers to result for hours, minutes, seconds and milliseconds * returns - void * ******************************************************************************/ void getTimestamp(int64_t time, uint32_t *pHours, uint32_t *pMinutes, uint32_t *pSeconds, uint32_t *pMillis) { uint32_t hours, minutes, seconds, millis; #define MILLIS2SECONDS 1000 #define SECONDS2MINUTES 60 #define MINUTES2HOURS 60 #define HOURS2DAYS 24 seconds = (uint32_t)(time / MILLIS2SECONDS); millis = (uint32_t)(time % MILLIS2SECONDS); minutes = seconds / SECONDS2MINUTES; seconds = seconds % SECONDS2MINUTES; hours = minutes / MINUTES2HOURS; minutes = minutes % MINUTES2HOURS; hours = hours % HOURS2DAYS; *pHours = hours; *pMinutes = minutes; *pSeconds = seconds; *pMillis = millis; #undef MILLIS2SECONDS #undef SECONDS2MINUTES #undef MINUTES2HOURS #undef HOURS2DAYS } /******************************************************************************* * name - addTraceConfig * description - add trace configuration command to list stored in utglobal data * parameters - OMR_TraceThread, trace configuration command * returns - return code ******************************************************************************/ omr_error_t addTraceConfig(OMR_TraceThread *thr, const char *cmd) { UtTraceCfg *tmp; omr_error_t rc = OMR_ERROR_NONE; OMRPORT_ACCESS_FROM_OMRPORT(OMR_TRACEGLOBAL(portLibrary)); /* * Obtain and initialize a config buffer */ UtTraceCfg *cfg = (UtTraceCfg *)omrmem_allocate_memory(sizeof(UtTraceCfg) + strlen(cmd) + 1, OMRMEM_CATEGORY_TRACE); if (NULL != cfg) { initHeader(&cfg->header, UT_TRACE_CONFIG_NAME, sizeof(UtTraceCfg) + strlen(cmd) + 1); cfg->next = NULL; strcpy(cfg->command, cmd); /* * Add it to the end of config chain while holding traceLock */ checkGetTraceLock(thr); if ((tmp = OMR_TRACEGLOBAL(config)) == NULL) { OMR_TRACEGLOBAL(config) = cfg; } else { while (tmp->next != NULL) { tmp = tmp->next; } tmp->next = cfg; } /* We should update the trace header here (if it has already been initialized) to * reflect the change in trace settings. * Unfortunately it may be in use by a snap dump or we may have returned a pointer to * it via trcGetTraceMetadata so freeing it or nulling it is unsafe. * For now we are leaving it unchanged. * If nothing has requested the trace header yet and it is NULL then it will be created * correctly when it is first used. */ checkFreeTraceLock(thr); } else { UT_DBGOUT(1, ("<UT> Out of memory in addTraceConfig\n")); rc = OMR_ERROR_OUT_OF_NATIVE_MEMORY; } return rc; } /******************************************************************************* * name - addTraceConfigKeyValuePair * description - add trace configuration command key/value pair to list * parameters - OMR_TraceThread, trace configuration command key, trace configuration * value * value can safely be null, but null key is an error. * returns - OMR_ERROR_NONE if it worked, * OMR_ERROR_OUT_OF_NATIVE_MEMORY or OMR_ERROR_ILLEGAL_ARGUMENT if problem ******************************************************************************/ omr_error_t addTraceConfigKeyValuePair(OMR_TraceThread *thr, const char *cmdKey, const char *cmdValue) { uintptr_t cmdLen = 1; /* terminating null */ char *cmd = NULL; omr_error_t rc = OMR_ERROR_NONE; int32_t addBraces = FALSE; OMRPORT_ACCESS_FROM_OMRPORT(OMR_TRACEGLOBAL(portLibrary)); /* could use a sprintf equivalent, but would have to mock up empty strings * for cases where cmdValue was null */ if (cmdKey != NULL) { cmdLen += strlen(cmdKey); } else { UT_DBGOUT(1, ("<UT> Out of memory recording option : \"%s\"\n", cmdKey)); return OMR_ERROR_ILLEGAL_ARGUMENT; } if (cmdValue != NULL) { cmdLen += strlen("="); cmdLen += strlen(cmdValue); if (strchr(cmdValue, ',') != NULL) { /* we have a comma separated item whose braces will have been stripped */ addBraces = TRUE; cmdLen += strlen("{}"); } } cmd = (char *)omrmem_allocate_memory(cmdLen, OMRMEM_CATEGORY_TRACE); if (NULL == cmd) { UT_DBGOUT(1, ("<UT> Out of memory recording option : \"%s\"\n", cmdKey)); return OMR_ERROR_OUT_OF_NATIVE_MEMORY; } if (cmdKey != NULL) { strcpy(cmd, cmdKey); } if (cmdValue != NULL) { strcat(cmd, "="); if (addBraces == TRUE) { strcat(cmd, "{"); } strcat(cmd, cmdValue); if (addBraces == TRUE) { strcat(cmd, "}"); } } rc = addTraceConfig(thr, cmd); omrmem_free_memory(cmd); return rc; } /******************************************************************************* * name - initHeader * description - Header initialization routine * parameters - UtDataHeader, name and size * returns - None ******************************************************************************/ void initHeader(UtDataHeader *header, const char *name, uintptr_t size) { memcpy(header->eyecatcher, name, 4); header->length = (int32_t)size; header->version = UT_VERSION; header->modification = UT_MODIFICATION; } /******************************************************************************* * name - hexStringLength * description - Return the number of consecutive hex characters * parameters - string pointer * returns - Length of hex string ******************************************************************************/ int hexStringLength(const char *str) { int i; for (i = 0; ((str[i] >= '0' && str[i] <= '9') || (str[i] >= 'A' && str[i] <= 'F') || (str[i] >= 'a' && str[i] <= 'f')); i++) { } return i; }