Prev / Next / たまにっき。

EXESEQ 動的バースマーク for Java

Category: [Java][研究][birthmark]
2005-09-22

ふと思いついて現実逃避に,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


Referrer (Inside): [2007-09-27-1]
Category: [Java][研究][birthmark]