ふと思いついて現実逃避に,JVMPI を使って,EXESEQ 動的バースマーク を抽出するコードを書いてみた.hprof のソースを参照にすると簡単に書けた.
J2SDK 1.4 用.気が向けば JDK 5.0 用に JVMTI を使って書くと思う.
$ cat extb.cc
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <jvmpi.h>
typedef struct _method_list_item{
jmethodID method_id;
char *class_name;
char *method_name;
char *method_signature;
struct _method_list_item *next;
} method_list_item;
// global jvmpi interface pointer
static JVMPI_Interface *jvmpi_interface;
method_list_item *first = NULL;
void add_list(const char *class_name, JVMPI_Method method){
method_list_item* m;
m = (method_list_item *)malloc(sizeof(method_list_item));
m->method_id = method.method_id;
m->class_name = (char *)malloc(sizeof(char) * (strlen(class_name) + 1));
strcpy(m->class_name, class_name);
m->method_name = (char *)malloc(sizeof(char) * (strlen(method.method_name) + 1));
strcpy(m->method_name, method.method_name);
m->method_signature = (char *)malloc(sizeof(char) * (strlen(method.method_signature) + 1));
strcpy(m->method_signature, method.method_signature);
m->next = first;
first = m;
}
method_list_item *find_list(jmethodID method_id){
method_list_item *m;
method_list_item *prev = NULL;
for(m = first; m != NULL; prev = m, m = m->next){
if(m->method_id == method_id){
if(prev != NULL){ // 見付かったら一番前へ
prev->next = m->next;
m->next = first;
first = m;
}
return m;
}
}
return NULL;
}
// function for handling event notification
void notifyEvent(JVMPI_Event *event){
method_list_item *item;
int i;
switch(event->event_type) {
case JVMPI_EVENT_METHOD_ENTRY2:
item = find_list(event->u.method_entry2.method_id);
if(item == NULL){
fprintf(stderr, "birthmark> \n");
}
else{
fprintf(stderr, "birthmark> %s %s %s\n", item->class_name,
item->method_name, item->method_signature);
}
break;
case JVMPI_EVENT_JVM_SHUT_DOWN:
for(item = first; item != NULL; ){
method_list_item *m;
m = item;
item = item->next;
free(m->class_name);
free(m->method_name);
free(m->method_signature);
free(m);
}
break;
case JVMPI_EVENT_CLASS_LOAD:
for(i = 0; i < event->u.class_load.num_methods; i++){
add_list(event->u.class_load.class_name, event->u.class_load.methods[i]);
}
break;
}
}
// profiler agent entry point
extern "C" {
JNIEXPORT jint JNICALL JVM_OnLoad(JavaVM *jvm, char *options, void *reserved) {
// get jvmpi interface pointer
if ((jvm->GetEnv((void **)&jvmpi_interface, JVMPI_VERSION_1)) < 0) {
fprintf(stderr, "birthmark> error in obtaining jvmpi interface pointer\n");
return JNI_ERR;
}
// initialize jvmpi interface
jvmpi_interface->NotifyEvent = notifyEvent;
// enabling class load event notification
jvmpi_interface->EnableEvent(JVMPI_EVENT_JVM_SHUT_DOWN, NULL);
jvmpi_interface->EnableEvent(JVMPI_EVENT_METHOD_ENTRY2, NULL);
jvmpi_interface->EnableEvent(JVMPI_EVENT_CLASS_LOAD, NULL);
return JNI_OK;
}
}
$ gcc -mdll -Wl,--enable-auto-import -Wl,--add-stdcall-alias \
-mrtd -g -O3 -Wall -I /usr/local/java/j2sdk1.4.2_04/include/ \
-I /usr/local/java/j2sdk1.4.2_04/include/win32/ -mno-cygwin \
-o extb.dll extb.cc
$ java -Xrunextb HelloWorld