#include "jni.h"
#include "j9.h"
#include "util_api.h"
#include "ut_j9jcl.h"
#include "rasdump_api.h"
#define COM_IBM_JVM_DUMP "com.ibm.jvm.Dump."
static void raiseExceptionFor(JNIEnv *env, omr_error_t result);
jint JNICALL
Java_com_ibm_jvm_Dump_HeapDumpImpl(JNIEnv *env, jclass clazz)
{
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
omr_error_t rc = vm->j9rasDumpFunctions->triggerOneOffDump(vm, "heap", "com.ibm.jvm.Dump.HeapDump", NULL, 0);
return omrErrorCodeToJniErrorCode(rc);
}
jint JNICALL
Java_com_ibm_jvm_Dump_JavaDumpImpl(JNIEnv *env, jclass clazz)
{
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
omr_error_t rc = vm->j9rasDumpFunctions->triggerOneOffDump(vm, "java", "com.ibm.jvm.Dump.JavaDump", NULL, 0);
return omrErrorCodeToJniErrorCode(rc);
}
jint JNICALL
Java_com_ibm_jvm_Dump_SystemDumpImpl(JNIEnv *env, jclass clazz)
{
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
omr_error_t rc = vm->j9rasDumpFunctions->triggerOneOffDump(vm, "system", "com.ibm.jvm.Dump.SystemDump", NULL, 0);
return omrErrorCodeToJniErrorCode(rc);
}
jint JNICALL
Java_com_ibm_jvm_Dump_SnapDumpImpl(JNIEnv *env, jclass clazz) {
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
omr_error_t rc = vm->j9rasDumpFunctions->triggerOneOffDump(vm, "Snap", "com.ibm.jvm.Dump.SnapDump", NULL, 0);
return omrErrorCodeToJniErrorCode(rc);
}
static jboolean scanDumpTypeForToolDump(char **typeString)
{
char *endPtr = *typeString + strlen(*typeString);
if( strchr(*typeString, ':') != NULL ) {
endPtr = strchr(*typeString, ':');
}
do {
if( try_scan(typeString, "tool") ) {
if ( *typeString[0] == '+' ||
*typeString[0] == ':' ||
*typeString[0] == '\0' ) {
return JNI_TRUE;
}
} else {
if( strchr(*typeString, '+') != NULL ) {
*typeString = strchr(*typeString, '+') + 1;
} else {
break;
}
}
} while ( *typeString < endPtr);
return JNI_FALSE;
}
jboolean JNICALL
Java_com_ibm_jvm_Dump_isToolDump(JNIEnv *env, jclass clazz, jstring jopts) {
char *optsBuffer = NULL;
int optsLength = 0;
jboolean retVal = JNI_FALSE;
PORT_ACCESS_FROM_ENV(env);
if( jopts == NULL ) {
return FALSE;
}
optsLength = (*env)->GetStringUTFLength(env, jopts);
optsBuffer = j9mem_allocate_memory(optsLength+1, J9MEM_CATEGORY_VM_JCL);
if( optsBuffer != NULL ) {
char * optsBufferPtr = optsBuffer;
memset(optsBuffer, 0, optsLength+1);
(*env)->GetStringUTFRegion(env, jopts, 0, optsLength, optsBuffer);
retVal = scanDumpTypeForToolDump(&optsBufferPtr);
j9mem_free_memory(optsBuffer);
} else {
jclass exceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
if (exceptionClass != NULL) {
(*env)->ThrowNew(env, exceptionClass, "Out of memory triggering dump");
}
retVal = JNI_FALSE;
}
return retVal;
}
jstring JNICALL
Java_com_ibm_jvm_Dump_triggerDumpsImpl (JNIEnv *env, jclass clazz, jstring jopts, jstring jevent)
{
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
char *optsBuffer = NULL;
char *eventBuffer = NULL;
char fileName[EsMaxPath+1];
int optsLength = 0;
int eventLength = 0;
omr_error_t result = OMR_ERROR_NONE;
jstring toReturn = NULL;
PORT_ACCESS_FROM_ENV(env);
optsLength = (*env)->GetStringUTFLength(env, jopts);
eventLength = (*env)->GetStringUTFLength(env, jevent);
optsBuffer = j9mem_allocate_memory(optsLength+1, J9MEM_CATEGORY_VM_JCL);
eventBuffer = j9mem_allocate_memory(strlen(COM_IBM_JVM_DUMP) + eventLength + 1, J9MEM_CATEGORY_VM_JCL);
if( optsBuffer != NULL && eventBuffer != NULL) {
memset(optsBuffer, 0, optsLength+1);
memset(eventBuffer, 0, strlen(COM_IBM_JVM_DUMP) + eventLength + 1);
strcpy(eventBuffer, COM_IBM_JVM_DUMP);
memset(fileName, 0, sizeof(fileName));
(*env)->GetStringUTFRegion(env, jopts, 0, optsLength, optsBuffer);
(*env)->GetStringUTFRegion(env, jevent, 0, eventLength, eventBuffer + strlen(eventBuffer));
result = vm->j9rasDumpFunctions->triggerOneOffDump(vm, optsBuffer, eventBuffer, fileName, sizeof(fileName));
if (OMR_ERROR_NONE == result) {
jstring actualFile = NULL;
actualFile = (*env)->NewStringUTF(env, fileName);
toReturn = actualFile;
} else {
raiseExceptionFor(env, result);
}
} else {
jclass exceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
if (exceptionClass != NULL) {
(*env)->ThrowNew(env, exceptionClass, "Out of memory triggering dump");
}
}
if( optsBuffer != NULL ) {
j9mem_free_memory(optsBuffer);
}
if( eventBuffer != NULL ) {
j9mem_free_memory(eventBuffer);
}
return toReturn;
}
jstring JNICALL
Java_openj9_internal_tools_attach_target_DiagnosticUtils_triggerDumpsImpl(JNIEnv *env, jclass clazz, jstring jopts, jstring jevent)
{
return Java_com_ibm_jvm_Dump_triggerDumpsImpl(env, clazz, jopts, jevent);
}
void JNICALL
Java_com_ibm_jvm_Dump_setDumpOptionsImpl (JNIEnv *env, jclass clazz, jstring jopts)
{
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
char *optsBuffer = NULL;
int optsLength = 0;
omr_error_t result = OMR_ERROR_NONE;
PORT_ACCESS_FROM_ENV(env);
optsLength = (*env)->GetStringUTFLength(env, jopts);
optsBuffer = j9mem_allocate_memory(optsLength+1, J9MEM_CATEGORY_VM_JCL);
if( optsBuffer != NULL ) {
memset(optsBuffer, 0, optsLength+1);
(*env)->GetStringUTFRegion(env, jopts, 0, optsLength, optsBuffer);
if (!(*env)->ExceptionCheck(env)) {
result = vm->j9rasDumpFunctions->setDumpOption(vm, optsBuffer);
if (OMR_ERROR_NONE != result) {
raiseExceptionFor(env, result);
}
}
} else {
jclass exceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
if (exceptionClass != NULL) {
(*env)->ThrowNew(env, exceptionClass, "Out of memory setting dump options");
}
}
if( optsBuffer != NULL ) {
j9mem_free_memory(optsBuffer);
}
}
jstring JNICALL
Java_com_ibm_jvm_Dump_queryDumpOptionsImpl (JNIEnv *env, jclass clazz) {
#define BUFFER_SIZE 10240
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
jint buffer_size = BUFFER_SIZE;
char options_buffer[BUFFER_SIZE];
char* options_ptr = NULL;
jint data_size;
jint* data_size_ptr = &data_size;
jstring toReturn = NULL;
omr_error_t result = OMR_ERROR_NONE;
PORT_ACCESS_FROM_ENV(env);
memset(options_buffer, 0, buffer_size);
result = vm->j9rasDumpFunctions->queryVmDump(vm, buffer_size, options_buffer, data_size_ptr);
while( data_size > buffer_size) {
buffer_size = data_size;
if( options_ptr != NULL ) {
j9mem_free_memory(options_ptr);
options_ptr = NULL;
}
options_ptr = j9mem_allocate_memory(buffer_size, J9MEM_CATEGORY_VM_JCL);
if( options_ptr != NULL ) {
memset(options_ptr, 0, buffer_size);
result = vm->j9rasDumpFunctions->queryVmDump(vm, buffer_size, options_ptr, data_size_ptr);
} else {
result = OMR_ERROR_OUT_OF_NATIVE_MEMORY;
break;
}
}
if (OMR_ERROR_NONE == result) {
if( options_ptr == NULL ) {
toReturn = (*env)->NewStringUTF(env, options_buffer);
} else {
toReturn = (*env)->NewStringUTF(env, options_ptr);
}
} else {
raiseExceptionFor(env, result);
}
if( options_ptr != NULL ) {
j9mem_free_memory(options_ptr);
}
return toReturn;
}
void JNICALL
Java_com_ibm_jvm_Dump_resetDumpOptionsImpl (JNIEnv *env, jclass clazz)
{
omr_error_t result = OMR_ERROR_NONE;
J9VMThread *thr = (J9VMThread *)env;
J9JavaVM *vm = thr->javaVM;
result = vm->j9rasDumpFunctions->resetDumpOptions(vm);
if (OMR_ERROR_NONE != result) {
raiseExceptionFor(env, result);
}
}
static void
raiseExceptionFor(JNIEnv *env, omr_error_t result)
{
jclass exceptionClass = NULL;
switch (result) {
case OMR_ERROR_INTERNAL:
exceptionClass = (*env)->FindClass(env, "openj9/management/internal/InvalidDumpOptionExceptionBase");
if (exceptionClass != NULL) {
(*env)->ThrowNew(env, exceptionClass, "Error in dump options.");
}
break;
case OMR_ERROR_OUT_OF_NATIVE_MEMORY:
exceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
if (exceptionClass != NULL) {
(*env)->ThrowNew(env, exceptionClass, "Out of memory setting dump option");
}
break;
case OMR_ERROR_NOT_AVAILABLE:
exceptionClass = (*env)->FindClass(env, "openj9/management/internal/DumpConfigurationUnavailableExceptionBase");
if (exceptionClass != NULL) {
(*env)->ThrowNew(env, exceptionClass, "Dump configuration cannot be changed while a dump is in progress.");
}
break;
default:
Assert_JCL_unreachable();
break;
}
}