Skip to content

Instantly share code, notes, and snippets.

@apangin
Created September 10, 2018 00:49
Show Gist options
  • Save apangin/d81c5bef977e2ac910e2badc0390852c to your computer and use it in GitHub Desktop.
Save apangin/d81c5bef977e2ac910e2badc0390852c to your computer and use it in GitHub Desktop.
#include <jvmti.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define INSIDE_MAIN 0x10000000
static volatile int max_depth = INSIDE_MAIN;
static intptr_t get_current_stack_depth(jvmtiEnv *jvmti) {
intptr_t depth = 0;
(*jvmti)->GetThreadLocalStorage(jvmti, NULL, (void**)&depth);
return (int)depth;
}
static void set_current_stack_depth(jvmtiEnv *jvmti, int depth) {
(*jvmti)->SetThreadLocalStorage(jvmti, NULL, (const void*)(intptr_t)depth);
}
static int is_main_method(jvmtiEnv *jvmti, jmethodID method) {
int result = 0;
char *name;
char *signature;
if ((*jvmti)->GetMethodName(jvmti, method, &name, &signature, NULL) == 0) {
result = strcmp(name, "main") == 0 && strcmp(signature, "([Ljava/lang/String;)V") == 0;
(*jvmti)->Deallocate(jvmti, (unsigned char*)signature);
(*jvmti)->Deallocate(jvmti, (unsigned char*)name);
}
return result;
}
void JNICALL MethodEntry(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread, jmethodID method) {
int depth = get_current_stack_depth(jvmti) + 1;
if (depth == 1 && is_main_method(jvmti, method)) {
depth += INSIDE_MAIN;
}
set_current_stack_depth(jvmti, depth);
if (depth > max_depth) {
max_depth = depth;
}
}
void JNICALL MethodExit(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread, jmethodID method,
jboolean was_popped_by_exception, jvalue return_value) {
int depth = get_current_stack_depth(jvmti) - 1;
if (depth == INSIDE_MAIN) {
depth = 0;
}
set_current_stack_depth(jvmti, depth);
}
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
jvmtiEnv* jvmti;
(*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_0);
jvmtiCapabilities capabilities = {0};
capabilities.can_generate_method_entry_events = 1;
capabilities.can_generate_method_exit_events = 1;
(*jvmti)->AddCapabilities(jvmti, &capabilities);
jvmtiEventCallbacks callbacks = {0};
callbacks.MethodEntry = MethodEntry;
callbacks.MethodExit = MethodExit;
(*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_METHOD_ENTRY, NULL);
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, NULL);
return 0;
}
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm) {
printf("Max stack depth = %d\n", max_depth - INSIDE_MAIN);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment