The API that you are probably after is JVMTI. JVMTI allows you to register callbacks for the majority of events that occur within the JVM, including MethodEntry, MethodExit. You listen for those events and pull out the Method.invoke events. There are API calls to get the classloader for a specific class. However you will have to write tool in C or C++.
Here is an example that will get the filter out the java.lang.reflect.Method.invoke call and print it out. To get details regarding the object that has been called you will probably need to look at the stack frame.
#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;
}