United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6263317 : JVMTI Spec: Need the ability to instrument native methods

Details
Type:
Enhancement
Submit Date:
2005-04-29
Status:
Resolved
Updated Date:
2011-02-16
Project Name:
JDK
Resolved Date:
2005-05-18
Component:
hotspot
OS:
generic
Sub-Component:
jvmti
CPU:
generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports
Relates:

Sub Tasks

Description
With JVM TI and java.lang.instrument we now have rich
support for instrumenting Java programming language
methods.  But what about native methods?

The NativeMethodBind event allows us to interpose a native
function around the implementation of a native method. This
works well for known native methods which we want to
intercept -- since we can hand craft the interposer.
However, for arbitrary native methods it would require
generating native code on the fly that could do arbitrary
argument processing.  This would be an implementation and
testing nightmare, and worse it is platform specific.

We need an approach which avoids the above.  Interposing
at the Java programming language level would achieve this.
It also has the advantage that it is at the same level as 
Java programming language method instrumentation.

For example, if we had:

  native boolean foo(int x);

We could transform the class file (at load time, since
this transformation isn't allowed in a redefine) so that
this becomes:

  boolean foo(int x) {
     ... record entry to foo ...
     return wrapper_foo(x);
  }

  native boolean wrapped_foo(int x);

Where foo becomes a wrapper for the actual native method
with the appended prefix "wrapped_".  Note that
"wrapped_" would be a bad prefix and that something like
"$$$MyAgentWrapped$$$_" would be better but would make
these examples less readable.

But now the problem is linking up the wrapped method with 
the native implementation.  That is, the method 
wrapped_foo needs to be resolved to the native 
implementation of foo, e.g.:

  Java_somePackage_someClass_foo(JNIEnv* env, jint x)

There are two ways that resolution occurs, explicit
resolution with the JNI function RegisterNatives and
the normal automatic resolution.  For RegisterNatives, it
will attempt this association:

  method(foo) -> nativeImplementation(foo)

This needs to be changed to:

  method(wrapped_foo) -> nativeImplementation(foo)

For automatic resolution, it will attempt:

  method(wrapped_foo) -> nativeImplementation(wrapped_foo)

This needs to be changed to:

  method(wrapped_foo) -> nativeImplementation(foo)

Possible solutions:

(1) Build some prefix into the VM to try on failure.

  Besides being a hack, this won't work if there are
  multiple agents wrapping native methods.

(2) For RegisterNatives the JNI interception functionality
   could be used to change the arguments.

  Yes, but there are order of wrapper application issues
  for multiple agents.

(3) Provide events on native resolution failure.

  This will work.  But to work in a multiple agent case
  the events would be complex and very specifically tied
  to this application.  For example: the event on
  automatic resolution failure would have to be called
  in the reverse environment ordering from standard event
  processing in order the remove the last prefix first,
  both events would need to have before and after strings,
  and each agent getting the RegisterNatives case would
  have to check intermediate links in the wrapper chain.

(4) Each environment can specify a native method prefix.

  This is what I propose.  It is simple and easy to use.
  It is uncomfortably specific to this application, but
  per the event solution above, this is unavoidable.

The JVM TI function could simply be:

  jvmtiError SetNativeMethodPrefix(jvmtiEnv* env,
                                   char* prefix);

What about java.lang.instrument, it would have the analog:

  void setNativeMethodPrefix(ClassFileTransformer transformer,
                             String prefix);

But the JVM TI agent that implements java.lang.instrument
(at least in the RI) is a meta agent, that is, there is
one JVM TI environment no matter how many
java.lang.instrument agents there are.  So, the JVM TI
function will need to be:

  jvmtiError SetNativeMethodPrefixes(jvmtiEnv* env,
                                     jint prefixCount,
                                     char** prefixes);

###@###.### 2005-04-29 01:13:37 GMT

                                    

Comments
EVALUATION

Important for critical tools, include JCov.
###@###.### 2005-04-29 20:13:57 GMT
                                     
2005-04-29



Hardware and Software, Engineered to Work Together