| #include <jvmpi.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| static JVMPI_Interface *jvmpi_interface; |
| static struct methodref *mrefs; |
| static int msize = 0; |
| static struct classref *crefs; |
| static int csize = 0; |
| static FILE *outputFile; |
| static char *include; |
| static char *exclude; |
| |
| int memSize; |
| int i; |
| int j; |
| |
| struct methodref |
| { |
| jmethodID id; |
| char *name; |
| char *signature; |
| int classid; |
| }; |
| |
| struct classref |
| { |
| char *name; |
| }; |
| |
| void addClassref(char *classname) |
| { |
| memSize = sizeof(struct classref); |
| if (csize == 0) |
| crefs = (struct classref *)malloc(memSize); |
| else |
| crefs = (struct classref *)realloc(crefs, memSize * (csize + 1)); |
| (crefs + csize)->name = (char *)malloc(strlen(classname) + 1); |
| strcpy((crefs + csize)->name, classname); |
| csize++; |
| } |
| |
| void addMethodref(jmethodID id, char *name, char *signature, int classid) |
| { |
| memSize = sizeof(struct methodref); |
| if (msize == 0) |
| mrefs = (struct methodref *)malloc(memSize); |
| else |
| mrefs = (struct methodref *)realloc(mrefs, memSize * (msize + 1)); |
| |
| for (j = 0; j < msize; j++) |
| { |
| if ((mrefs + j)->id > id) |
| { |
| break; |
| } |
| } |
| if (j != msize) |
| { |
| memmove((mrefs + j + 1), (mrefs + j), memSize * (msize - j)); |
| } |
| (mrefs + j)->name = (char *)malloc(strlen(name) + 1); |
| (mrefs + j)->signature = (char *)malloc(strlen(signature) + 1); |
| (mrefs + j)->id = id; |
| strcpy((mrefs + j)->name, name); |
| strcpy((mrefs + j)->signature, signature); |
| (mrefs + j)->classid = classid; |
| msize++; |
| /* |
| (mrefs + msize)->name = (char *)malloc(strlen(name) + 1); |
| (mrefs + msize)->signature = (char *)malloc(strlen(signature) + 1); |
| (mrefs + msize)->id = id; |
| strcpy((mrefs + msize)->name, name); |
| strcpy((mrefs + msize)->signature, signature); |
| (mrefs + msize)->classid = classid; |
| msize++; |
| */ |
| } |
| |
| int lower; |
| int upper; |
| int middle; |
| jmethodID lowerid; |
| jmethodID upperid; |
| jmethodID middleid; |
| |
| void addMethodID(jmethodID id) |
| { |
| if (msize < 1) |
| return; |
| lower = 0; |
| upper = msize - 1; |
| lowerid = (mrefs + lower)->id; |
| upperid = (mrefs + upper)->id; |
| while (lowerid < id && id < upperid && (upper - lower) > 1) |
| { |
| middle = ((upper - lower) / 2) + lower; |
| middleid = (mrefs + middle)->id; |
| if (middleid > id) |
| { |
| upper = middle; |
| upperid = middleid; |
| } |
| else if (middleid < id) |
| { |
| lower = middle; |
| lowerid = middleid; |
| } |
| else |
| { |
| upper = middle; |
| upperid = middleid; |
| break; |
| } |
| } |
| if (lowerid == id) |
| middle = lower; |
| else if (upperid == id) |
| middle = upper; |
| else |
| middle = -1; |
| if (middle != -1) |
| { |
| fputs((crefs + (mrefs + middle)->classid)->name, outputFile); |
| fputs("#", outputFile); |
| fputs((mrefs + middle)->name, outputFile); |
| fputs("#", outputFile); |
| fputs((mrefs + middle)->signature, outputFile); |
| fputs(" ", outputFile); |
| if (middle != (msize - 1)) |
| memmove((mrefs + middle), (mrefs + middle + 1), sizeof(struct methodref) * (msize - (middle + 1))); |
| msize--; |
| return; |
| } |
| /* |
| for (i = 0; i < msize; i++) |
| { |
| if ((mrefs + i)->id == id) |
| { |
| fputs((crefs + (mrefs + i)->classid)->name, outputFile); |
| fputs("#", outputFile); |
| fputs((mrefs + i)->name, outputFile); |
| fputs("#", outputFile); |
| fputs((mrefs + i)->signature, outputFile); |
| fputs(" ", outputFile); |
| memmove((mrefs + i), (mrefs + i + 1), sizeof(struct methodref) * (msize - (i + 1))); |
| msize--; |
| return; |
| } |
| } |
| */ |
| } |
| |
| void notifyEvent(JVMPI_Event *event) |
| { |
| switch(event->event_type) |
| { |
| case JVMPI_EVENT_CLASS_LOAD: |
| if (strstr(event->u.class_load.class_name, include) != NULL && (exclude == NULL || strstr(event->u.class_load.class_name, exclude) == NULL)) |
| { |
| addClassref((char *)event->u.class_load.class_name); |
| for (i = 0; i < event->u.class_load.num_methods; i++) |
| { |
| addMethodref(event->u.class_load.methods[i].method_id, (char *)event->u.class_load.methods[i].method_name, (char *)event->u.class_load.methods[i].method_signature, csize - 1); |
| } |
| } |
| break; |
| case JVMPI_EVENT_METHOD_ENTRY: |
| addMethodID(event->u.method.method_id); |
| break; |
| case JVMPI_EVENT_JVM_SHUT_DOWN: |
| fclose(outputFile); |
| break; |
| } |
| } |
| |
| JNIEXPORT jint JNICALL |
| JVM_OnLoad(JavaVM *jvm, char *options, void *reserved) |
| { |
| if ((*jvm)->GetEnv(jvm, (void **)&jvmpi_interface, JVMPI_VERSION_1) < 0) |
| return JNI_ERR; |
| outputFile = fopen(getenv("apiagent_output"), "a"); |
| include = getenv("apiagent_include"); |
| exclude = getenv("apiagent_exclude"); |
| if (outputFile != NULL && include != NULL) |
| { |
| jvmpi_interface->NotifyEvent = notifyEvent; |
| jvmpi_interface->EnableEvent(JVMPI_EVENT_CLASS_LOAD, NULL); |
| jvmpi_interface->EnableEvent(JVMPI_EVENT_METHOD_ENTRY, NULL); |
| jvmpi_interface->EnableEvent(JVMPI_EVENT_JVM_SHUT_DOWN, NULL); |
| } |
| return JNI_OK; |
| } |