/*
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef JVMTI_COMMON_H
#define JVMTI_COMMON_H
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#include "jvmti.h"
/**
* Additional Java basic types
*/
#ifdef _WIN32
typedef unsigned __int64 julong;
#else
typedef unsigned long long julong;
#endif
#define LOG(...) \
{ \
printf(__VA_ARGS__); \
fflush(stdout); \
}
#define COMPLAIN LOG
const char* TranslateState(jint flags);
const char* TranslateError(jvmtiError err);
static jvmtiExtensionFunction GetVirtualThread_func = NULL;
static jvmtiExtensionFunction GetCarrierThread_func = NULL;
/**
* Convert the digits of the given value argument to a null-terminated
* character string and store the result (up to 32 bytes) in string.
* If value is negative, the first character of the stored string is
* the minus sign (-). The function returns a pointer to the begining
* of the result string.
*/
char* jlong_to_string(jlong value, char *string) {
char buffer[32];
char *pbuf, *pstr;
pstr = string;
if (value == 0) {
*pstr++ = '0';
} else {
if (value < 0) {
*pstr++ = '-';
value = -value;
}
pbuf = buffer;
while (value != 0) {
*pbuf++ = '0' + (char)(value % 10);
value = value / 10;
}
while (pbuf != buffer) {
*pstr++ = *--pbuf;
}
}
*pstr = '\0';
return string;
}
/**
* Convert the digits of the given value argument to a null-terminated
* character string and store the result (up to 32 bytes) in string.
* The function returns a pointer to the begining of the result string.
*/
char* julong_to_string(julong value, char *string) {
char buffer[32];
char *pbuf, *pstr;
pstr = string;
if (value == 0) {
*pstr++ = '0';
} else {
pbuf = buffer;
while (value != 0) {
*pbuf++ = '0' + (char)(value % 10);
value = value / 10;
}
while (pbuf != buffer) {
*pstr++ = *--pbuf;
}
}
*pstr = '\0';
return string;
}
static void
fatal(JNIEnv* jni, const char* msg) {
jni->FatalError(msg);
}
static void
check_jvmti_status(JNIEnv* jni, jvmtiError err, const char* msg) {
if (err != JVMTI_ERROR_NONE) {
LOG("check_jvmti_status: JVMTI function returned error: %s (%d)\n", TranslateError(err), err);
jni->FatalError(msg);
}
}
/* JVMTI helper wrappers. Check errors and fail or return null if jvmti operation failed. */
// Monitors often created in Agent_Initialize(..) where JNIEnv* jni doesn't exist.
jrawMonitorID
create_raw_monitor(jvmtiEnv *jvmti, const char* name) {
jrawMonitorID lock;
jvmtiError err = jvmti->CreateRawMonitor(name, &lock);
if (err != JVMTI_ERROR_NONE) {
return nullptr;
}
return lock;
}
void
destroy_raw_monitor(jvmtiEnv *jvmti, JNIEnv *jni, jrawMonitorID lock) {
check_jvmti_status(jni, jvmti->DestroyRawMonitor(lock), "DestroyRawMonitor failed.");
}
class RawMonitorLocker {
private:
jvmtiEnv* _jvmti;
JNIEnv* _jni;
jrawMonitorID _monitor;
public:
RawMonitorLocker(jvmtiEnv *jvmti,JNIEnv* jni, jrawMonitorID monitor):_jvmti(jvmti), _jni(jni), _monitor(monitor) {
check_jvmti_status(_jni, _jvmti->RawMonitorEnter(_monitor), "Fatal Error in RawMonitorEnter.");
}
~RawMonitorLocker() {
check_jvmti_status(_jni, _jvmti->RawMonitorExit(_monitor), "Fatal Error in RawMonitorEnter.");
}
void wait(jlong millis) {
check_jvmti_status(_jni, _jvmti->RawMonitorWait(_monitor, millis), "Fatal Error in RawMonitorWait.");
}
void wait() {
wait(0);
}
void notify() {
check_jvmti_status(_jni, _jvmti->RawMonitorNotify(_monitor), "Fatal Error in RawMonitorNotify.");
}
void notify_all() {
check_jvmti_status(_jni, _jvmti->RawMonitorNotifyAll(_monitor), "Fatal Error in RawMonitorNotifyAll.");
}
};
static void
deallocate(jvmtiEnv *jvmti, JNIEnv* jni, void* ptr) {
jvmtiError err = jvmti->Deallocate((unsigned char*)ptr);
check_jvmti_status(jni, err, "deallocate: error in JVMTI Deallocate call");
}
static char*
get_method_class_name(jvmtiEnv *jvmti, JNIEnv* jni, jmethodID method) {
jclass klass = NULL;
char* cname = NULL;
char* result = NULL;
jvmtiError err;
err = jvmti->GetMethodDeclaringClass(method, &klass);
check_jvmti_status(jni, err, "get_method_class_name: error in JVMTI GetMethodDeclaringClass");
err = jvmti->GetClassSignature(klass, &cname, NULL);
check_jvmti_status(jni, err, "get_method_class_name: error in JVMTI GetClassSignature");
size_t len = strlen(cname) - 2; // get rid of leading 'L' and trailing ';'
err = jvmti->Allocate((jlong)(len + 1), (unsigned char**)&result);
check_jvmti_status(jni, err, "get_method_class_name: error in JVMTI Allocate");
strncpy(result, cname + 1, len); // skip leading 'L'
result[len] = '\0';
deallocate(jvmti, jni, (void*)cname);
return result;
}
static void
print_method(jvmtiEnv *jvmti, JNIEnv* jni, jmethodID method, jint depth) {
char* cname = NULL;
char* mname = NULL;
char* msign = NULL;
jvmtiError err;
cname = get_method_class_name(jvmti, jni, method);
err = jvmti->GetMethodName(method, &mname, &msign, NULL);
check_jvmti_status(jni, err, "print_method: error in JVMTI GetMethodName");
LOG("%2d: %s: %s%s\n", depth, cname, mname, msign);
fflush(0);
deallocate(jvmti, jni, (void*)cname);
deallocate(jvmti, jni, (void*)mname);
deallocate(jvmti, jni, (void*)msign);
}
void
print_thread_info(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread_obj) {
jvmtiThreadInfo thread_info;
jint thread_state;
check_jvmti_status(jni, jvmti->GetThreadInfo(thread_obj, &thread_info), "Error in GetThreadInfo");
check_jvmti_status(jni, jvmti->GetThreadState(thread_obj, &thread_state), "Error in GetThreadInfo");
const char* state = TranslateState(thread_state);
LOG("Thread: %p, name: %s, state(%x): %s, attrs: %s %s\n", thread_obj, thread_info.name, thread_state, TranslateState(thread_state),
(jni->IsVirtualThread(thread_obj)? "virtual": "kernel"), (thread_info.is_daemon ? "daemon": ""));
}
static void
print_stack_trace_frames(jvmtiEnv *jvmti, JNIEnv *jni, jint count, jvmtiFrameInfo *frames) {
LOG("JVMTI Stack Trace: frame count: %d\n", count);
for (int depth = 0; depth < count; depth++) {
print_method(jvmti, jni, frames[depth].method, depth);
}
LOG("\n");
}
static jint
get_frame_count(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread) {
jint frame_count;
jvmtiError err = jvmti->GetFrameCount(thread, &frame_count);
check_jvmti_status(jni, err, "get_frame_count: error in JVMTI GetFrameCount call");
return frame_count;
}
static jvmtiThreadInfo
get_thread_info(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread) {
jvmtiThreadInfo thr_info;
jvmtiError err = jvmti->GetThreadInfo(thread, &thr_info);
check_jvmti_status(jni, err, "get_thread_info: error in JVMTI GetThreadInfo call");
return thr_info;
}
static jint
get_thread_state(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread) {
jint thread_state;
jvmtiError err = jvmti->GetThreadState(thread, &thread_state);
check_jvmti_status(jni, err, "get_thread_state: error in JVMTI GetThreadState call");
return thread_state;
}
static char*
get_thread_name(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread) {
jvmtiThreadInfo thr_info;
jvmtiError err;
memset(&thr_info, 0, sizeof(thr_info));
err = jvmti->GetThreadInfo(thread, &thr_info);
if (err == JVMTI_ERROR_WRONG_PHASE || err == JVMTI_ERROR_THREAD_NOT_ALIVE) {
return NULL; // VM or target thread completed its work
}
check_jvmti_status(jni, err, "get_thread_name: error in JVMTI GetThreadInfo call");
static const char* UNNAMED_STR = "";
static size_t UNNAMED_LEN = strlen(UNNAMED_STR);
char* tname = thr_info.name;
if (tname == NULL) {
err = jvmti->Allocate((jlong)(UNNAMED_LEN + 1), (unsigned char**)&tname);
check_jvmti_status(jni, err, "get_method_class_name: error in JVMTI Allocate");
strncpy(tname, UNNAMED_STR, UNNAMED_LEN);
tname[UNNAMED_LEN] = '\0';
}
return tname;
}
static char*
get_method_name(jvmtiEnv *jvmti, JNIEnv* jni, jmethodID method) {
char* mname = NULL;
jvmtiError err;
err = jvmti->GetMethodName(method, &mname, NULL, NULL);
check_jvmti_status(jni, err, "get_method_name: error in JVMTI GetMethodName call");
return mname;
}
static jclass
find_class(jvmtiEnv *jvmti, JNIEnv *jni, jobject loader, const char* cname) {
jclass *classes = NULL;
jint count = 0;
jvmtiError err;
err = jvmti->GetClassLoaderClasses(loader, &count, &classes);
check_jvmti_status(jni, err, "find_class: error in JVMTI GetClassLoaderClasses");
// Find the jmethodID of the specified method
while (--count >= 0) {
char* name = NULL;
jclass klass = classes[count];
err = jvmti->GetClassSignature(klass, &name, NULL);
check_jvmti_status(jni, err, "find_class: error in JVMTI GetClassSignature call");
bool found = (strcmp(name, cname) == 0);
deallocate(jvmti, jni, (void*)name);
if (found) {
return klass;
}
}
return NULL;
}
static jmethodID
find_method(jvmtiEnv *jvmti, JNIEnv *jni, jclass klass, const char* mname) {
jmethodID *methods = NULL;
jmethodID method = NULL;
jint count = 0;
jvmtiError err;
err = jvmti->GetClassMethods(klass, &count, &methods);
check_jvmti_status(jni, err, "find_method: error in JVMTI GetClassMethods");
// Find the jmethodID of the specified method
while (--count >= 0) {
char* name = NULL;
jmethodID meth = methods[count];
err = jvmti->GetMethodName(meth, &name, NULL, NULL);
check_jvmti_status(jni, err, "find_method: error in JVMTI GetMethodName call");
bool found = (strcmp(name, mname) == 0);
deallocate(jvmti, jni, (void*)name);
if (found) {
method = meth;
break;
}
}
deallocate(jvmti, jni, (void*)methods);
return method;
}
#define MAX_FRAME_COUNT_PRINT_STACK_TRACE 200
static void
print_current_stack_trace(jvmtiEnv *jvmti, JNIEnv* jni) {
jvmtiFrameInfo frames[MAX_FRAME_COUNT_PRINT_STACK_TRACE];
jint count = 0;
jvmtiError err = jvmti->GetStackTrace(NULL, 0, MAX_FRAME_COUNT_PRINT_STACK_TRACE, frames, &count);
check_jvmti_status(jni, err, "print_stack_trace: error in JVMTI GetStackTrace");
LOG("JVMTI Stack Trace for current thread: frame count: %d\n", count);
for (int depth = 0; depth < count; depth++) {
print_method(jvmti, jni, frames[depth].method, depth);
}
LOG("\n");
}
static void
print_stack_trace(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread) {
jvmtiFrameInfo frames[MAX_FRAME_COUNT_PRINT_STACK_TRACE];
char* tname = get_thread_name(jvmti, jni, thread);
jint count = 0;
jvmtiError err = jvmti->GetStackTrace(thread, 0, MAX_FRAME_COUNT_PRINT_STACK_TRACE, frames, &count);
check_jvmti_status(jni, err, "print_stack_trace: error in JVMTI GetStackTrace");
LOG("JVMTI Stack Trace for thread %s: frame count: %d\n", tname, count);
for (int depth = 0; depth < count; depth++) {
print_method(jvmti, jni, frames[depth].method, depth);
}
deallocate(jvmti, jni, (void*)tname);
LOG("\n");
}
static void suspend_thread(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread) {
check_jvmti_status(jni, jvmti->SuspendThread(thread), "error in JVMTI SuspendThread");
}
static void resume_thread(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread) {
check_jvmti_status(jni, jvmti->ResumeThread(thread), "error in JVMTI ResumeThread");
}
static jthread get_current_thread(jvmtiEnv *jvmti, JNIEnv* jni) {
jthread thread;
check_jvmti_status(jni, jvmti->GetCurrentThread(&thread), "error in JVMTI GetCurrentThread");
return thread;
}
/* Commonly used helper functions */
const char*
TranslateState(jint flags) {
static char str[15 * 20];
if (flags == 0) {
return "";
}
str[0] = '\0';
if (flags & JVMTI_THREAD_STATE_ALIVE) {
strcat(str, " ALIVE");
}
if (flags & JVMTI_THREAD_STATE_TERMINATED) {
strcat(str, " TERMINATED");
}
if (flags & JVMTI_THREAD_STATE_RUNNABLE) {
strcat(str, " RUNNABLE");
}
if (flags & JVMTI_THREAD_STATE_WAITING) {
strcat(str, " WAITING");
}
if (flags & JVMTI_THREAD_STATE_WAITING_INDEFINITELY) {
strcat(str, " WAITING_INDEFINITELY");
}
if (flags & JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT) {
strcat(str, " WAITING_WITH_TIMEOUT");
}
if (flags & JVMTI_THREAD_STATE_SLEEPING) {
strcat(str, " SLEEPING");
}
if (flags & JVMTI_THREAD_STATE_IN_OBJECT_WAIT) {
strcat(str, " IN_OBJECT_WAIT");
}
if (flags & JVMTI_THREAD_STATE_PARKED) {
strcat(str, " PARKED");
}
if (flags & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) {
strcat(str, " BLOCKED_ON_MONITOR_ENTER");
}
if (flags & JVMTI_THREAD_STATE_SUSPENDED) {
strcat(str, " SUSPENDED");
}
if (flags & JVMTI_THREAD_STATE_INTERRUPTED) {
strcat(str, " INTERRUPTED");
}
if (flags & JVMTI_THREAD_STATE_IN_NATIVE) {
strcat(str, " IN_NATIVE");
}
return str;
}
const char*
TranslateEvent(jvmtiEvent event_type) {
switch (event_type) {
case JVMTI_EVENT_VM_INIT:
return ("JVMTI_EVENT_VM_INIT");
case JVMTI_EVENT_VM_DEATH:
return ("JVMTI_EVENT_VM_DEATH");
case JVMTI_EVENT_THREAD_START:
return ("JVMTI_EVENT_THREAD_START");
case JVMTI_EVENT_THREAD_END:
return ("JVMTI_EVENT_THREAD_END");
case JVMTI_EVENT_CLASS_FILE_LOAD_HOOK:
return ("JVMTI_EVENT_CLASS_FILE_LOAD_HOOK");
case JVMTI_EVENT_CLASS_LOAD:
return ("JVMTI_EVENT_CLASS_LOAD");
case JVMTI_EVENT_CLASS_PREPARE:
return ("JVMTI_EVENT_CLASS_PREPARE");
case JVMTI_EVENT_VM_START:
return ("JVMTI_EVENT_VM_START");
case JVMTI_EVENT_EXCEPTION:
return ("JVMTI_EVENT_EXCEPTION");
case JVMTI_EVENT_EXCEPTION_CATCH:
return ("JVMTI_EVENT_EXCEPTION_CATCH");
case JVMTI_EVENT_SINGLE_STEP:
return ("JVMTI_EVENT_SINGLE_STEP");
case JVMTI_EVENT_FRAME_POP:
return ("JVMTI_EVENT_FRAME_POP");
case JVMTI_EVENT_BREAKPOINT:
return ("JVMTI_EVENT_BREAKPOINT");
case JVMTI_EVENT_FIELD_ACCESS:
return ("JVMTI_EVENT_FIELD_ACCESS");
case JVMTI_EVENT_FIELD_MODIFICATION:
return ("JVMTI_EVENT_FIELD_MODIFICATION");
case JVMTI_EVENT_METHOD_ENTRY:
return ("JVMTI_EVENT_METHOD_ENTRY");
case JVMTI_EVENT_METHOD_EXIT:
return ("JVMTI_EVENT_METHOD_EXIT");
case JVMTI_EVENT_NATIVE_METHOD_BIND:
return ("JVMTI_EVENT_NATIVE_METHOD_BIND");
case JVMTI_EVENT_COMPILED_METHOD_LOAD:
return ("JVMTI_EVENT_COMPILED_METHOD_LOAD");
case JVMTI_EVENT_COMPILED_METHOD_UNLOAD:
return ("JVMTI_EVENT_COMPILED_METHOD_UNLOAD");
case JVMTI_EVENT_DYNAMIC_CODE_GENERATED:
return ("JVMTI_EVENT_DYNAMIC_CODE_GENERATED");
case JVMTI_EVENT_DATA_DUMP_REQUEST:
return ("JVMTI_EVENT_DATA_DUMP_REQUEST");
case JVMTI_EVENT_MONITOR_WAIT:
return ("JVMTI_EVENT_MONITOR_WAIT");
case JVMTI_EVENT_MONITOR_WAITED:
return ("JVMTI_EVENT_MONITOR_WAITED");
case JVMTI_EVENT_MONITOR_CONTENDED_ENTER:
return ("JVMTI_EVENT_MONITOR_CONTENDED_ENTER");
case JVMTI_EVENT_MONITOR_CONTENDED_ENTERED:
return ("JVMTI_EVENT_MONITOR_CONTENDED_ENTERED");
case JVMTI_EVENT_GARBAGE_COLLECTION_START:
return ("JVMTI_EVENT_GARBAGE_COLLECTION_START");
case JVMTI_EVENT_GARBAGE_COLLECTION_FINISH:
return ("JVMTI_EVENT_GARBAGE_COLLECTION_FINISH");
case JVMTI_EVENT_OBJECT_FREE:
return ("JVMTI_EVENT_OBJECT_FREE");
case JVMTI_EVENT_VM_OBJECT_ALLOC:
return ("JVMTI_EVENT_VM_OBJECT_ALLOC");
default:
return ("");
}
}
const char*
TranslateError(jvmtiError err) {
switch (err) {
case JVMTI_ERROR_NONE:
return ("JVMTI_ERROR_NONE");
case JVMTI_ERROR_INVALID_THREAD:
return ("JVMTI_ERROR_INVALID_THREAD");
case JVMTI_ERROR_INVALID_THREAD_GROUP:
return ("JVMTI_ERROR_INVALID_THREAD_GROUP");
case JVMTI_ERROR_INVALID_PRIORITY:
return ("JVMTI_ERROR_INVALID_PRIORITY");
case JVMTI_ERROR_THREAD_NOT_SUSPENDED:
return ("JVMTI_ERROR_THREAD_NOT_SUSPENDED");
case JVMTI_ERROR_THREAD_SUSPENDED:
return ("JVMTI_ERROR_THREAD_SUSPENDED");
case JVMTI_ERROR_THREAD_NOT_ALIVE:
return ("JVMTI_ERROR_THREAD_NOT_ALIVE");
case JVMTI_ERROR_INVALID_OBJECT:
return ("JVMTI_ERROR_INVALID_OBJECT");
case JVMTI_ERROR_INVALID_CLASS:
return ("JVMTI_ERROR_INVALID_CLASS");
case JVMTI_ERROR_CLASS_NOT_PREPARED:
return ("JVMTI_ERROR_CLASS_NOT_PREPARED");
case JVMTI_ERROR_INVALID_METHODID:
return ("JVMTI_ERROR_INVALID_METHODID");
case JVMTI_ERROR_INVALID_LOCATION:
return ("JVMTI_ERROR_INVALID_LOCATION");
case JVMTI_ERROR_INVALID_FIELDID:
return ("JVMTI_ERROR_INVALID_FIELDID");
case JVMTI_ERROR_NO_MORE_FRAMES:
return ("JVMTI_ERROR_NO_MORE_FRAMES");
case JVMTI_ERROR_OPAQUE_FRAME:
return ("JVMTI_ERROR_OPAQUE_FRAME");
case JVMTI_ERROR_TYPE_MISMATCH:
return ("JVMTI_ERROR_TYPE_MISMATCH");
case JVMTI_ERROR_INVALID_SLOT:
return ("JVMTI_ERROR_INVALID_SLOT");
case JVMTI_ERROR_DUPLICATE:
return ("JVMTI_ERROR_DUPLICATE");
case JVMTI_ERROR_NOT_FOUND:
return ("JVMTI_ERROR_NOT_FOUND");
case JVMTI_ERROR_INVALID_MONITOR:
return ("JVMTI_ERROR_INVALID_MONITOR");
case JVMTI_ERROR_NOT_MONITOR_OWNER:
return ("JVMTI_ERROR_NOT_MONITOR_OWNER");
case JVMTI_ERROR_INTERRUPT:
return ("JVMTI_ERROR_INTERRUPT");
case JVMTI_ERROR_INVALID_CLASS_FORMAT:
return ("JVMTI_ERROR_INVALID_CLASS_FORMAT");
case JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION:
return ("JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION");
case JVMTI_ERROR_FAILS_VERIFICATION:
return ("JVMTI_ERROR_FAILS_VERIFICATION");
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED:
return ("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED");
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED:
return ("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED");
case JVMTI_ERROR_INVALID_TYPESTATE:
return ("JVMTI_ERROR_INVALID_TYPESTATE");
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED:
return ("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED");
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED:
return ("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED");
case JVMTI_ERROR_UNSUPPORTED_VERSION:
return ("JVMTI_ERROR_UNSUPPORTED_VERSION");
case JVMTI_ERROR_NAMES_DONT_MATCH:
return ("JVMTI_ERROR_NAMES_DONT_MATCH");
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED:
return ("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED");
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED:
return ("JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED");
case JVMTI_ERROR_UNMODIFIABLE_CLASS:
return ("JVMTI_ERROR_UNMODIFIABLE_CLASS");
case JVMTI_ERROR_NOT_AVAILABLE:
return ("JVMTI_ERROR_NOT_AVAILABLE");
case JVMTI_ERROR_MUST_POSSESS_CAPABILITY:
return ("JVMTI_ERROR_MUST_POSSESS_CAPABILITY");
case JVMTI_ERROR_NULL_POINTER:
return ("JVMTI_ERROR_NULL_POINTER");
case JVMTI_ERROR_ABSENT_INFORMATION:
return ("JVMTI_ERROR_ABSENT_INFORMATION");
case JVMTI_ERROR_INVALID_EVENT_TYPE:
return ("JVMTI_ERROR_INVALID_EVENT_TYPE");
case JVMTI_ERROR_ILLEGAL_ARGUMENT:
return ("JVMTI_ERROR_ILLEGAL_ARGUMENT");
case JVMTI_ERROR_NATIVE_METHOD:
return ("JVMTI_ERROR_NATIVE_METHOD");
case JVMTI_ERROR_OUT_OF_MEMORY:
return ("JVMTI_ERROR_OUT_OF_MEMORY");
case JVMTI_ERROR_ACCESS_DENIED:
return ("JVMTI_ERROR_ACCESS_DENIED");
case JVMTI_ERROR_WRONG_PHASE:
return ("JVMTI_ERROR_WRONG_PHASE");
case JVMTI_ERROR_INTERNAL:
return ("JVMTI_ERROR_INTERNAL");
case JVMTI_ERROR_UNATTACHED_THREAD:
return ("JVMTI_ERROR_UNATTACHED_THREAD");
case JVMTI_ERROR_INVALID_ENVIRONMENT:
return ("JVMTI_ERROR_INVALID_ENVIRONMENT");
default:
return ("");
}
}
const char*
TranslatePhase(jvmtiPhase phase) {
switch (phase) {
case JVMTI_PHASE_ONLOAD:
return ("JVMTI_PHASE_ONLOAD");
case JVMTI_PHASE_PRIMORDIAL:
return ("JVMTI_PHASE_PRIMORDIAL");
case JVMTI_PHASE_START:
return ("JVMTI_PHASE_START");
case JVMTI_PHASE_LIVE:
return ("JVMTI_PHASE_LIVE");
case JVMTI_PHASE_DEAD:
return ("JVMTI_PHASE_DEAD");
default:
return ("");
}
}
const char*
TranslateRootKind(jvmtiHeapRootKind root) {
switch (root) {
case JVMTI_HEAP_ROOT_JNI_GLOBAL:
return ("JVMTI_HEAP_ROOT_JNI_GLOBAL");
case JVMTI_HEAP_ROOT_JNI_LOCAL:
return ("JVMTI_HEAP_ROOT_JNI_LOCAL");
case JVMTI_HEAP_ROOT_SYSTEM_CLASS:
return ("JVMTI_HEAP_ROOT_SYSTEM_CLASS");
case JVMTI_HEAP_ROOT_MONITOR:
return ("JVMTI_HEAP_ROOT_MONITOR");
case JVMTI_HEAP_ROOT_STACK_LOCAL:
return ("JVMTI_HEAP_ROOT_STACK_LOCAL");
case JVMTI_HEAP_ROOT_THREAD:
return ("JVMTI_HEAP_ROOT_THREAD");
case JVMTI_HEAP_ROOT_OTHER:
return ("JVMTI_HEAP_ROOT_OTHER");
default:
return ("");
}
}
const char*
TranslateObjectRefKind(jvmtiObjectReferenceKind ref) {
switch (ref) {
case JVMTI_REFERENCE_CLASS:
return ("JVMTI_REFERENCE_CLASS");
case JVMTI_REFERENCE_FIELD:
return ("JVMTI_REFERENCE_FIELD");
case JVMTI_REFERENCE_ARRAY_ELEMENT:
return ("JVMTI_REFERENCE_ARRAY_ELEMENT");
case JVMTI_REFERENCE_CLASS_LOADER:
return ("JVMTI_REFERENCE_CLASS_LOADER");
case JVMTI_REFERENCE_SIGNERS:
return ("JVMTI_REFERENCE_SIGNERS");
case JVMTI_REFERENCE_PROTECTION_DOMAIN:
return ("JVMTI_REFERENCE_PROTECTION_DOMAIN");
case JVMTI_REFERENCE_INTERFACE:
return ("JVMTI_REFERENCE_INTERFACE");
case JVMTI_REFERENCE_STATIC_FIELD:
return ("JVMTI_REFERENCE_STATIC_FIELD");
case JVMTI_REFERENCE_CONSTANT_POOL:
return ("JVMTI_REFERENCE_CONSTANT_POOL");
default:
return ("");
}
}
int
isThreadExpected(jvmtiEnv *jvmti, jthread thread) {
static const char *vm_jfr_buffer_thread_name = "VM JFR Buffer Thread";
static const char *jfr_request_timer_thread_name = "JFR request timer";
static const char *graal_management_bean_registration_thread_name =
"HotSpotGraalManagement Bean Registration";
static const char *graal_compiler_thread_name_prefix = "JVMCI CompilerThread";
static const size_t graal_prefix_length = strlen(graal_compiler_thread_name_prefix);
static const char *unparker_thread_name_prefix = "VirtualThread-unparker";
static const size_t unparker_prefix_length = strlen(unparker_thread_name_prefix);
jvmtiThreadInfo threadinfo;
jvmtiError err = jvmti->GetThreadInfo(thread, &threadinfo);
if (err != JVMTI_ERROR_NONE) {
return 0;
}
if (strcmp(threadinfo.name, vm_jfr_buffer_thread_name) == 0) {
return 0;
}
if (strcmp(threadinfo.name, jfr_request_timer_thread_name) == 0) {
return 0;
}
if (strcmp(threadinfo.name, graal_management_bean_registration_thread_name) == 0)
return 0;
if ((strlen(threadinfo.name) > graal_prefix_length) &&
strncmp(threadinfo.name, graal_compiler_thread_name_prefix, graal_prefix_length) == 0) {
return 0;
}
if (strncmp(threadinfo.name, unparker_thread_name_prefix, unparker_prefix_length) == 0) {
return 0;
}
return 1;
}
jthread find_thread_by_name(jvmtiEnv* jvmti, JNIEnv* jni, const char name[]) {
jthread* threads = NULL;
jint count = 0;
jthread found_thread = NULL;
if (name == NULL) {
return NULL;
}
check_jvmti_status(jni, jvmti->GetAllThreads(&count, &threads), "");
for (int i = 0; i < count; i++) {
jvmtiThreadInfo info = get_thread_info(jvmti, jni, threads[i]);
if (info.name != NULL && strcmp(name, info.name) == 0) {
found_thread = threads[i];
break;
}
}
check_jvmti_status(jni, jvmti->Deallocate((unsigned char*)threads), "");
found_thread = (jthread) jni->NewGlobalRef(found_thread);
return found_thread;
}
/*
* JVMTI Extension Mechanism
*/
static const jvmtiEvent
EXT_EVENT_VIRTUAL_THREAD_MOUNT = (jvmtiEvent)((int)JVMTI_MIN_EVENT_TYPE_VAL - 2),
EXT_EVENT_VIRTUAL_THREAD_UNMOUNT = (jvmtiEvent)((int)JVMTI_MIN_EVENT_TYPE_VAL - 3);
static jvmtiExtensionFunction
find_ext_function(jvmtiEnv* jvmti, JNIEnv* jni, const char* fname) {
jint extCount = 0;
jvmtiExtensionFunctionInfo* extList = NULL;
jvmtiError err = jvmti->GetExtensionFunctions(&extCount, &extList);
check_jvmti_status(jni, err, "jvmti_common find_ext_function: Error in JVMTI GetExtensionFunctions");
for (int i = 0; i < extCount; i++) {
if (strstr(extList[i].id, (char*)fname) != NULL) {
return extList[i].func;
}
}
return NULL;
}
static jvmtiError
GetVirtualThread(jvmtiEnv* jvmti, JNIEnv* jni, jthread cthread, jthread* vthread_ptr) {
if (GetVirtualThread_func == NULL) { // lazily initialize function pointer
GetVirtualThread_func = find_ext_function(jvmti, jni, "GetVirtualThread");
}
jvmtiError err = (*GetVirtualThread_func)(jvmti, cthread, vthread_ptr);
return err;
}
static jvmtiError
GetCarrierThread(jvmtiEnv* jvmti, JNIEnv* jni, jthread vthread, jthread* cthread_ptr) {
if (GetCarrierThread_func == NULL) { // lazily initialize function pointer
GetCarrierThread_func = find_ext_function(jvmti, jni, "GetCarrierThread");
}
jvmtiError err = (*GetCarrierThread_func)(jvmti, vthread, cthread_ptr);
return err;
}
static jthread
get_virtual_thread(jvmtiEnv* jvmti, JNIEnv* jni, jthread cthread) {
jthread vthread = NULL;
jvmtiError err = GetVirtualThread(jvmti, jni, cthread, &vthread);
check_jvmti_status(jni, err, "jvmti_common get_virtual_thread: Error in JVMTI extension GetVirtualThread");
return vthread;
}
static jthread
get_carrier_thread(jvmtiEnv* jvmti, JNIEnv* jni, jthread vthread) {
jthread cthread = NULL;
jvmtiError err = GetCarrierThread(jvmti, jni, vthread, &cthread);
check_jvmti_status(jni, err, "jvmti_common get_carrier_thread: Error in JVMTI extension GetCarrierThread");
return cthread;
}
static jvmtiExtensionEventInfo*
find_ext_event(jvmtiEnv* jvmti, const char* ename) {
jint extCount = 0;
jvmtiExtensionEventInfo* extList = NULL;
jvmtiError err = jvmti->GetExtensionEvents(&extCount, &extList);
if (err != JVMTI_ERROR_NONE) {
LOG("jvmti_common find_ext_event: Error in JVMTI GetExtensionFunctions: %s(%d)\n",TranslateError(err), err);
return NULL;
}
for (int i = 0; i < extCount; i++) {
if (strstr(extList[i].id, (char*)ename) != NULL) {
return &extList[i];
}
}
return NULL;
}
static jvmtiError
set_ext_event_callback(jvmtiEnv* jvmti, const char* ename, jvmtiExtensionEvent callback) {
jvmtiExtensionEventInfo* info = find_ext_event(jvmti, ename);
if (info == NULL) {
LOG("jvmti_common set_ext_event_callback: Extension event was not found: %s\n", ename);
return JVMTI_ERROR_NOT_AVAILABLE;
}
jvmtiError err = jvmti->SetExtensionEventCallback(info->extension_event_index, callback);
return err;
}
/** Enable or disable given events. */
static jvmtiError
set_event_notification_mode(jvmtiEnv* jvmti, jvmtiEventMode mode, jvmtiEvent event_type, jthread event_thread) {
jvmtiError err = jvmti->SetEventNotificationMode(mode, event_type, event_thread);
return err;
}
static void
set_event_notification_mode(jvmtiEnv* jvmti, JNIEnv* jni, jvmtiEventMode mode, jvmtiEvent event_type, jthread event_thread) {
jvmtiError err = jvmti->SetEventNotificationMode(mode, event_type, event_thread);
check_jvmti_status(jni, err, "jvmti_common set_event_notification_mode: Error in JVMTI SetEventNotificationMode");
}
int
enable_events_notifications(jvmtiEnv* jvmti, JNIEnv* jni, jvmtiEventMode enable, int size, jvmtiEvent list[], jthread thread) {
for (int i = 0; i < size; i++) {
check_jvmti_status(jni, jvmti->SetEventNotificationMode(enable, list[i], thread), "");
}
return JNI_TRUE;
}
void
sleep_ms(int millis) {
#ifdef _WIN32
Sleep(millis);
#else
usleep(1000 * millis);
#endif
}
void
sleep_sec(jlong timeout) {
int seconds = (int)((timeout + 999) / 1000);
#ifdef _WIN32
Sleep(1000L * seconds);
#else
sleep(seconds);
#endif
}
#endif
¤ Dauer der Verarbeitung: 0.44 Sekunden
(vorverarbeitet)
¤
|
Haftungshinweis
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.
|