Java API on top of JVMTI?
Asked Answered
E

6

16

Is there a nice Java API I can use on top of JVMTI?

Exile answered 27/1, 2011 at 16:36 Comment(3)
Which part of JVMTI is it you would like to use? Quite a lot of it wouldn't be possible to wrap in java simply because the way it is used to monitor java would cause very unpredictable situations should you do it from java code. For some events, it would certainly be possible to write a native JVMTI backend which could be accessed from java but I cannot think of a situation where it would be very useful compared to other alternatives.Walkon
After going through all the answers I have realised that I probably totally misunderstood what JVMTI is supposed to do. I probably should be using the instrument API as I want to build instrumentation applicationExile
The "closest-to-the-metal" JVMTI Java wrapper is probably the Java Debug Interface, which runs in a different JVM from the one being debugged (usually the JVMs are connected by a socket). The documentation recommends this method of connecting to the JVM's debugging utilities over using JVMTI directly from native code within the same process. You can find much more documentation on the debugger architecture and the abstractions JDI provides here.Pedaiah
H
5

ok... just tried it... seems to work as expected.... in real life the VMInit callback would return an instance of a class that implemented an interface that mirrored the C JVMTI interface.... the C agent would store this instance and call it when required on events .... additionally before the VMInit Java returned it would set up capabilities and callbacks and register events etc.... you would probably be able to get about 90% JVMTI API coverage..... it's just a case of typing it in .... I could do it in a weekend if you have a strong case :-)

the following code produces this:

C: VMInit, preparing to callback Java method
Java: JVMTI callback class, VMInit().
C: VMInit, callback Java method returned successfully
Java: And Finally... Hello, I'm the Java main


package com.stackoverflow;

public class JVMTICallback {

    public static void VMInit() {

        System.out.println("Java:\tJVMTI callback class, VMInit().");

    }

    public static void main(String[] args) {
        // This main is only here to give us something to run for the test

        System.out.println("Java:\tAnd Finally... Hello, I'm the Java main");
    }

}

and the C

#include <stdlib.h>
#include "jvmti.h"

jvmtiEnv *globalJVMTIInterface;

void JNICALL
vmInit(jvmtiEnv * jvmti_env, JNIEnv * jni_env, jthread thread)
{

  printf("C:\tVMInit, preparing to callback Java method\n");

  char *className = "com/stackoverflow/JVMTICallback";
  char *methodName = "VMInit";
  char *descriptor = "()V";

  jclass callbackClass = (*jni_env)->FindClass(jni_env, className);

  if (!callbackClass) {
      fprintf(stderr,"C:\tUnable to locate callback class.\n");
      return;
      }

  jmethodID callbackMethodID = (*jni_env)->GetStaticMethodID(jni_env, callbackClass, methodName, descriptor);

  if (!callbackMethodID)
    {
      fprintf(stderr, "C:\tUnable to locate callback VMInit method\n");
      return;
    }

  (*jni_env)->CallStaticVoidMethodV(jni_env, callbackClass, callbackMethodID, NULL);

  printf("C:\tVMInit, callback Java method returned successfully\n");


}

JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM * jvm, char *options, void *reserved)
{

  jint returnCode = (*jvm)->GetEnv(jvm, (void **) &globalJVMTIInterface,
      JVMTI_VERSION_1_0);

  if (returnCode != JNI_OK)
    {
      fprintf(stderr,
          "The version of JVMTI requested (1.0) is not supported by this JVM.\n");
      return JVMTI_ERROR_UNSUPPORTED_VERSION;
    }

  jvmtiEventCallbacks *eventCallbacks;

  eventCallbacks = calloc(1, sizeof(jvmtiEventCallbacks));
  if (!eventCallbacks)
    {
      fprintf(stderr, "Unable to allocate memory\n");
      return JVMTI_ERROR_OUT_OF_MEMORY;
    }

  eventCallbacks->VMInit = &vmInit;

  returnCode = (*globalJVMTIInterface)->SetEventCallbacks(globalJVMTIInterface,
      eventCallbacks, (jint) sizeof(*eventCallbacks));
  if (returnCode != JNI_OK)
    {
      fprintf(stderr, "C:\tJVM does not have the required capabilities (%d)\n",
          returnCode);
      exit(-1);
    }

  returnCode = (*globalJVMTIInterface)->SetEventNotificationMode(
      globalJVMTIInterface, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, (jthread) NULL);
  if (returnCode != JNI_OK)
    {
      fprintf(
          stderr,
          "C:\tJVM does not have the required capabilities, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT (%d)\n",
          returnCode);
      exit(-1);
    }

  return JVMTI_ERROR_NONE;
}
Hooke answered 7/2, 2011 at 18:59 Comment(0)
U
12

JVMTI was not built for having Java API on top. The JVM TI definition itself says:

The JVM tool interface (JVM TI) is a standard native API that allows for native libraries to capture events and control a Java Virtual Machine (JVM) for the Java platform.

Since it was built for native API to capture events & controls, I don't think there are API on top of it. May you can explain what you are trying to achieve?

I am not aware of any Java API on top of JVM TI.

Unreadable answered 31/1, 2011 at 5:41 Comment(2)
It is just that one wants to build a tool in Java, that controls another JVM. Think of a profiler, or the like. This would make debugging some weird problems easier.It
Okey, the real nifty parts of the JVMTI API are useles to use from Java... and for everything else there is java.lang.instrument!It
H
5

ok... just tried it... seems to work as expected.... in real life the VMInit callback would return an instance of a class that implemented an interface that mirrored the C JVMTI interface.... the C agent would store this instance and call it when required on events .... additionally before the VMInit Java returned it would set up capabilities and callbacks and register events etc.... you would probably be able to get about 90% JVMTI API coverage..... it's just a case of typing it in .... I could do it in a weekend if you have a strong case :-)

the following code produces this:

C: VMInit, preparing to callback Java method
Java: JVMTI callback class, VMInit().
C: VMInit, callback Java method returned successfully
Java: And Finally... Hello, I'm the Java main


package com.stackoverflow;

public class JVMTICallback {

    public static void VMInit() {

        System.out.println("Java:\tJVMTI callback class, VMInit().");

    }

    public static void main(String[] args) {
        // This main is only here to give us something to run for the test

        System.out.println("Java:\tAnd Finally... Hello, I'm the Java main");
    }

}

and the C

#include <stdlib.h>
#include "jvmti.h"

jvmtiEnv *globalJVMTIInterface;

void JNICALL
vmInit(jvmtiEnv * jvmti_env, JNIEnv * jni_env, jthread thread)
{

  printf("C:\tVMInit, preparing to callback Java method\n");

  char *className = "com/stackoverflow/JVMTICallback";
  char *methodName = "VMInit";
  char *descriptor = "()V";

  jclass callbackClass = (*jni_env)->FindClass(jni_env, className);

  if (!callbackClass) {
      fprintf(stderr,"C:\tUnable to locate callback class.\n");
      return;
      }

  jmethodID callbackMethodID = (*jni_env)->GetStaticMethodID(jni_env, callbackClass, methodName, descriptor);

  if (!callbackMethodID)
    {
      fprintf(stderr, "C:\tUnable to locate callback VMInit method\n");
      return;
    }

  (*jni_env)->CallStaticVoidMethodV(jni_env, callbackClass, callbackMethodID, NULL);

  printf("C:\tVMInit, callback Java method returned successfully\n");


}

JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM * jvm, char *options, void *reserved)
{

  jint returnCode = (*jvm)->GetEnv(jvm, (void **) &globalJVMTIInterface,
      JVMTI_VERSION_1_0);

  if (returnCode != JNI_OK)
    {
      fprintf(stderr,
          "The version of JVMTI requested (1.0) is not supported by this JVM.\n");
      return JVMTI_ERROR_UNSUPPORTED_VERSION;
    }

  jvmtiEventCallbacks *eventCallbacks;

  eventCallbacks = calloc(1, sizeof(jvmtiEventCallbacks));
  if (!eventCallbacks)
    {
      fprintf(stderr, "Unable to allocate memory\n");
      return JVMTI_ERROR_OUT_OF_MEMORY;
    }

  eventCallbacks->VMInit = &vmInit;

  returnCode = (*globalJVMTIInterface)->SetEventCallbacks(globalJVMTIInterface,
      eventCallbacks, (jint) sizeof(*eventCallbacks));
  if (returnCode != JNI_OK)
    {
      fprintf(stderr, "C:\tJVM does not have the required capabilities (%d)\n",
          returnCode);
      exit(-1);
    }

  returnCode = (*globalJVMTIInterface)->SetEventNotificationMode(
      globalJVMTIInterface, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, (jthread) NULL);
  if (returnCode != JNI_OK)
    {
      fprintf(
          stderr,
          "C:\tJVM does not have the required capabilities, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT (%d)\n",
          returnCode);
      exit(-1);
    }

  return JVMTI_ERROR_NONE;
}
Hooke answered 7/2, 2011 at 18:59 Comment(0)
L
3

I searched around and unfortunately can't find any Java API library on top of JVMTI. Seems like you're out of luck.

What you can do though is to call a native lib from your Java code. I'm not very good at C/C++ but from JVMTI docs I see that it's possible to build a small shared library from provided headers. Then you can call it using JNA**. It will give you a nice API wrapper around native library.

Take a look at examples at JNA Getting Started page

This page also links to JNAerator which can generate all necessary Java bindings for you.

The downside of this approach is a necessity of maintaining this thin native layer for your target platforms.


** JNA deals a runtime overhead compared to usual JNI but ease of development overweights performance benefits IMO. Switch to JNI only if you have to.

Lauraine answered 4/2, 2011 at 11:24 Comment(0)
E
2

It will not work. JVMTI has callbacks that the Java code has no direct control over (like ClassPrepare). If these callbacks are implemented in Java, the execution can lead other callbacks causing deadlock.

Eskil answered 4/8, 2014 at 15:41 Comment(0)
H
1

it wouldn't be difficult to write.... just thunk the JVMTI calls to callback a Java class over JNI.. you would probably face a couple of issues... firstly the Agent_onLoad.. this initial "registering" function happens too early on in the lifecycle of the JVM for it to callback your java.... secondly there are potential circularity issues and the probability that the JVM was written expecting you to do anything like this this at...

Iĺl try to write an example.... back in a few mins...

Hooke answered 7/2, 2011 at 18:23 Comment(0)
G
1

JDI is a TOP level interface written in Java, which uses JVMTI as the backend api. this link give you detailed info.

Germinative answered 14/9, 2014 at 13:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.