API, к которому вы, вероятно, обращаетесь: JVMTI . JVMTI позволяет регистрировать обратные вызовы для большинства событий, происходящих в JVM, включая MethodEntry, MethodExit. Вы слушаете эти события и извлекаете события Method.invoke. Есть вызовы API, чтобы получить загрузчик классов для определенного класса. Однако вам придется написать инструмент на C или C ++.
Вот пример, который получит фильтр из вызова java.lang.reflect.Method.invoke и распечатает его. Чтобы получить подробную информацию о вызываемом объекте, вам, вероятно, нужно взглянуть на кадр стека.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <jvmti.h>
static jvmtiEnv *jvmti = NULL;
static jvmtiCapabilities capa;
static jint check_jvmti_error(jvmtiEnv *jvmti,
jvmtiError errnum,
const char *str) {
if (errnum != JVMTI_ERROR_NONE) {
char *errnum_str;
errnum_str = NULL;
(void) (*jvmti)->GetErrorName(jvmti, errnum, &errnum_str);
printf("ERROR: JVMTI: %d(%s): %s\n",
errnum,
(errnum_str == NULL ? "Unknown" : errnum_str),
(str == NULL ? "" : str));
return JNI_ERR;
}
return JNI_OK;
}
void JNICALL callbackMethodEntry(jvmtiEnv *jvmti_env,
JNIEnv* jni_env,
jthread thread,
jmethodID method) {
char* method_name;
char* method_signature;
char* generic_ptr_method;
char* generic_ptr_class;
char* class_name;
jvmtiError error;
jclass clazz;
error = (*jvmti_env)->GetMethodName(jvmti_env,
method,
&method_name,
&method_signature,
&generic_ptr_method);
if (check_jvmti_error(jvmti_env, error, "Failed to get method name")) {
return;
}
if (strcmp("invoke", method_name) == 0) {
error
= (*jvmti_env)->GetMethodDeclaringClass(jvmti_env, method,
&clazz);
if (check_jvmti_error(jvmti_env, error,
"Failed to get class for method")) {
(*jvmti_env)->Deallocate(jvmti_env, method_name);
(*jvmti_env)->Deallocate(jvmti_env, method_signature);
(*jvmti_env)->Deallocate(jvmti_env, generic_ptr_method);
return;
}
error = (*jvmti_env)->GetClassSignature(jvmti_env, clazz, &class_name,
&generic_ptr_class);
if (check_jvmti_error(jvmti_env, error, "Failed to get class signature")) {
(*jvmti_env)->Deallocate(jvmti_env, method_name);
(*jvmti_env)->Deallocate(jvmti_env, method_signature);
(*jvmti_env)->Deallocate(jvmti_env, generic_ptr_method);
return;
}
if (strcmp("Ljava/lang/reflect/Method;", class_name) == 0) {
printf("Method entered: %s.%s.%s\n", class_name, method_name,
method_signature);
}
(*jvmti_env)->Deallocate(jvmti_env, class_name);
(*jvmti_env)->Deallocate(jvmti_env, generic_ptr_class);
}
(*jvmti_env)->Deallocate(jvmti_env, method_name);
(*jvmti_env)->Deallocate(jvmti_env, method_signature);
(*jvmti_env)->Deallocate(jvmti_env, generic_ptr_method);
}
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
jint result;
jvmtiError error;
jvmtiEventCallbacks callbacks;
result = (*jvm)->GetEnv(jvm, (void**) &jvmti, JVMTI_VERSION_1_0);
if (result != JNI_OK || jvmti == NULL) {
printf("error\n");
return JNI_ERR;
} else {
printf("loaded agent\n");
}
(void) memset(&capa, 0, sizeof(jvmtiCapabilities));
capa.can_generate_method_entry_events = 1;
error = (*jvmti)->AddCapabilities(jvmti, &capa);
if (check_jvmti_error(jvmti, error, "Unable to set capabilities") != JNI_OK) {
return JNI_ERR;
}
(void) memset(&callbacks, 0, sizeof(callbacks));
callbacks.MethodEntry = &callbackMethodEntry;
error = (*jvmti)->SetEventCallbacks(jvmti,
&callbacks,
(jint) sizeof(callbacks));
if (check_jvmti_error(jvmti, error, "Unable to set callbacks") != JNI_OK) {
return JNI_ERR;
}
error = (*jvmti)->SetEventNotificationMode(jvmti,
JVMTI_ENABLE,
JVMTI_EVENT_METHOD_ENTRY,
(jthread) NULL);
if (check_jvmti_error(jvmti, error,
"Unable to set method entry notifications") != JNI_OK) {
return JNI_ERR;
}
return JNI_OK;
}