Friday May 23, 2008

Announcing statically-defined DTrace probes in Java!

It's taken a while (too long, perhaps), but the latest JDK7 snapshot build (b27) now has the capability of allowing you to define tracepoints in your Java application and then trace those tracepoints using DTrace. It's come a long way since our initial prototypes, and features a flexible, easy-to-use interface and somewhere around 95% reduction in disabled probe overhead. I hope the wait has been worth it.

To try it out, download the latest JDK binaries. The interface to the tracing system is defined in the com.sun.tracing package, and additional DTrace-specific attributes are defined in the com.sun.tracing.dtrace package. As you can see by the package naming convention, these interfaces are specific to the Sun JVM, and are not technically part of Java, so the usual warnings apply. Also, since it's not an official part of the JDK, you won't find any Javadoc describing the interfaces. But, you can download them here.

The interfaces are present and functional on all platforms, even though you'll only get the DTrace-probe side effects on platforms which support DTrace (for Hotspot, that's only Solaris). On other platforms, the tracing calls will result in no-ops, so it should be safe to apply tracepoints to any Java program. Also, as you may notice, the tracing APIs are written to be generic and not specific to DTrace. It was done this way so that one could add tracepoints to their programs now, and if a different tracing mechanism becomes available and implemented in the JDK, that tracing mechanism may work without any changes to the running Java application.

For those that are interested in the technical details of how this is implemented, feel free to peruse the initial Java/native sources and Hotspot sources. The openjdk repositories will, of course, always contain the latest and greatest.

The package descriptions in the Javadoc provide all the details about how to add probes to your program, and previous blog entries cover the proposal as well, but here's a quick summary of how to do it:

Define your provider

To define your provider, create a Java interface that extends com.sun.tracing.Provider. Each method you add to your interface defines a different probe. You can add parameters to the methods, these will be passed as arguments to your probe.
interface HelloWorldProvider extends com.sun.tracing.Provider {
    void program_init();
    void friendly_greeting(String greeting);
    void program_terminate();
}

Create an instance of your provider

At some point in your application, you need to create an instance of your provider in order to trigger your probes. You'll want to do this early on in your application life cycle since your probes won't even be declared until the provider is created (i.e., dtrace -l won't display your probes until your interface has been intantiated). Use the ProviderFactory to create your provider.
import com.sun.tracing.\*;

class Main {
    public static void main(String argv[]) {
        ProviderFactory factory = ProviderFactory.getDefaultFactory();
        HelloWorldProvider p = factory.createProvider(HelloWorldProvider.class);
        ...
    }
}

Insert probe points into your application

A probe point in the application is a method call of one of the methods your defined in your provider interface. When that method is called, a DTrace probe will be triggered. Any arguments you pass will be provided to an attached DTrace script.
class Main {
    public static void main(String argv[]) {
        ...
        p.program_init();
        String greeting = "Hello, DTracer";
        System.out.println(greeting);
        p.friendly_greeting(greeting);
        ... 
        p.program_terminate();
    }
}

Use DTrace to observe your program

The probes you defined are now traceable via DTrace. They are available as USDT-like probes, where the provider name is the name of your interface concatenated with the program PID, and the probe names are the names you gave the methods. You can control many more aspects of the probe/provider naming, refer to the Javadoc for details.
> dtrace -n 'HelloWorldProvider$target:::friendly_greeting { printf("%s\\n", copyinstr(arg0)); }' -c "java Hello"

Tuesday Oct 30, 2007

Adding user-defined DTrace probes to Java programs

Tracing Java programs with DTrace has always been a bit challenging. To such tracing easier, we propose a new Java-level tracing interface which will allow a Java programmer to instrument their code with probes which can be traced using DTrace at runtime.

Essentially, we want to provide the programmer with USDT-like probes from Java code -- the developer defining their probes and adds probe points into their application. The probes are low-cost and have no effect on the running program, but a DTrace script may attach to the process and monitor the probe points.

We propose to add this functionality as part of a generic tracing mechanism as the Java-level, in a new com.sun.tracing package, available in the JRE.

The com.sun.tracing package defines two key entities, an interface called Provider, and a factory class that creates instances of this interface called (creatively) ProviderFactory. There are a few other annotations and interfaces in there, but these two are the key players so I'll cover the others later.

To define a DTrace-provider (or any other Java-level tracing provider, but for now there's only DTrace), one must create a new interface which extends from com.sun.tracing.Provider.  Any methods declared by the new interface represent probes which are part of the provider.  The method parameters are the probe parameters that will be available to DTrace scripts.  The probe name, by default, is the name of the method.  For example, here is the definition of a simple provider:

public interface MyProvider extends com.sun.tracing.Provider {
    void startProbe();
    void workProbe(int iteration, int value);
    void endProbe();
}

This interface definition is roughly equivalent in functionality to a USDT provider specification in native code. However, activation of the provider and placing probes in the application are a bit different that USDT. To add native USDT probes to an application, you must involve DTrace in the build step, and as a result, providers are immediately activated at application load time, and probe placement is performed by adding source-level macros in your code. The Java solution for this doesn't require any build changes, but does require a bit more manual intervention at the source-code level to activate the provider and place the probes. This is where the ProviderFactory class comes in. To activate a provider, and thus make it's probes available via a dtrace -l, you must first create an instance of a ProviderFactory using the static method, getDefaultFactory. This step can be done only once for the entire application, a single factory can create many providers if needed. The point of the factory object is to create instances of each of the developer-defined providers. This is accomplished via the createProvider method. Example code shows this best:

import com.sun.tracing.ProviderFactory;

public class MyApplication {
    public static void main(String argv[]) {
        ProviderFactory factory = ProviderFactory.getDefaultFactory();
        MyProvider provider = factory.createProvider(MyProvider.class);

        doWork()   
    }
    static void doWork() {
        ...
    }
}

Now to add probe points in the application, the developer simply makes adds calls to the method that they defined using the instance returned from createProvider.

import com.sun.tracing.ProviderFactory;

public class MyApplication {
    public static MyProvider provider;
    public static void main(String argv[]) {
        ProviderFactory factory = ProviderFactory.getDefaultFactory();
        provider = factory.createProvider(MyProvider.class);   

        provider->startProbe();
        doWork();
        provider->endProbe();
    }
    static void doWork() {
        ...
        provider->workProbe(i, j);
    }
}

(As can be seen from the example, this may mean that the created provider instance must be stored in a global variable for access from multiple methods. It could be passed as a parameter if desired.)

The example code above would result in the following DTrace probes which could be traced from an attached DTrace script (assuming the process ID is stored in '$target'):

MyProvider$target:::startProbe {
    trace(probename);
}
MyProvider$target:::workProbe { 
    printf("%s: iteration = %d, value = %d\\n", probename, arg0, arg1); 
}
MyProvider$target:::endProbe {
   trace(probename);
}

As you can see, the provider class name becomes the provider name in DTrace, and the method name is the probe name. The module and function names are undefined in the simple case, but can be set using annotations as described below. The probes themselves are very lightweight and have no side effects other than the DTrace visibility.

In the rare case where setting up the arguments is a costly endeavor, one can check the status of a probe manually in order to determine if an attached DTrace script is monitoring it. In USDT, this is the "is-enabled" functionality. In Java, we use a method of the com.sun.tracing.Provider interface to get a reference to the probe, and can then query the probe to get the enabled-state:

    ...
    Method m = MyProvider.class.getMethod("startProbe");
    com.sun.tracing.Probe p = provider.getProbe(m);
    if ( p.isEnabled() ) {
        // do argument setup, etc.
    else {
        // probe is not enabled, skip argument setup
    }

The probe can also be triggered directly from a reference:

    ... 
    Method m2 = MyProvider.class.getMethod("workProbe");
    com.sun.tracing.Probe p = provider.getProbe(m2);
    p.trigger(instance, value);

This is equivalent to calling the instance method directly, though the compiler won't be able to check that you're passing the right parameters, and thus you're more likely to run into an IllegalArgumentException

One can override the provider and probe names that will be used in the tracing mechanism by adding an annotation to the provider specification or the probe specification which contains the requested name:

@ProviderName("OverriddenName") 
public interface MyProvider extends com.sun.tracing.Provider {
    @ProbeName("applicationBegin") void startProbe();
    ...
}

In this case, the resulting DTrace probe would look like this:

OverriddenName$target:::applicationBegin ()

Similarly, the module and function fields of the DTrace probes can be controlled via annotations that live in the com.sun.tracing.dtrace package. The @ModuleName annotation applied to a provider specification will apply to all probes in that provider, and a @FunctionName annotation applied to a method in that provider will specify the function field of the DTrace probe. There are also a number of stability attributes that can be applied to the provider to control the stability aspects of the generated probes.

Here is a full listing of the proposed interfaces:

package com.sun.tracing;
 
public interface Probe {
    boolean isEnabled();
    void trigger(Object ... args);
}
 
public interface Provider {
    Probe getProbe(java.lang.reflect.Method method);
    void dispose();
}
 
public abstract class ProviderFactory {
    public abstract  T createProvider(Class cls);
    public static ProviderFactory getDefaultFactory();
}
 
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ProbeName {
    String value();
}
 
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ProviderName {
    String value();
}
-------------------------------------------------------------------------------
package com.sun.tracing.dtrace;
 
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface FunctionName {
    String value();
}
 
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ModuleName {
    String value();
}
 
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Attributes {
  StabilityLevel name();
  StabilityLevel data();
  DependencyClass dependency();
}
 
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface ProviderAttributes {
    Attributes value();
}
 
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface ModuleAttributes {
    Attributes value();
}
 
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface FunctionAttributes {
    Attributes value();
}
 
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface NameAttributes {
    Attributes value();
}
 
 
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface ArgsAttributes {
  Attributes value();
}
 
public enum StabilityLevel {
    INTERNAL,
    PRIVATE,
    OBSOLETE,
    EXTERNAL,
    UNSTABLE,
    EVOLVING,
    STABLE,
    STANDARD;
}
 
public enum DependencyClass {
    UNKNOWN,
    CPU,
    PLATFORM,
    GROUP,
    ISA,
    COMMON;
}

Friday Aug 11, 2006

DVM agent to Hotspot 6.0 DTrace probe migration guide

As of the 6.0 VM, a number of dtrace probes have been built-in so that you can use them without running an agent, and for most probes, without running with any special command-line arguments.

A full description of all the available probes and their arguments is available here: DTrace probes in 6.0

The built-in, always-on probes in the VM correspond closely to the probes avialable in djvm, but the arguments are slightly different and some of the probes need to be enabled with special command-line flags (which results in some performance degredation, but much less than running with the agent). There are also additional probes for every JNI method's entry and return point.

One major difference between djvm and the built-in probes is in the way they pass string arguments. While djvm passes a null-terminated ASCII (or UTF8) string, the built-in probes pass length-deliminated UTF8 strings. In order to correctly read the strings you have to use the copyinstring() primitive which takes a length argument, since there is no guarantee of an ending null.

Here's a quick summary of the probes in djvm and the corresponding built-in Hotspot probe:

dvm::::vm-init

The VM has two built-in probes for initialization: hotspot:::vm-init-begin and hotspot:::vm-init-end. The begin probe is fired as soon as the VM starts, while the end probe is fired when the VM is ready to start executing Java code.

dvm:::vm-death

Corresponds to hotspot::vm-shutdown.

dvm:::thread-start(char\* thread_name)

The VM built-in probe that corresponds to this is hotspot:::thread-start and it has 5 arguments, the first two are a string/length pair that indicate the name of the thread. The third argument is the Java thread id, the forth is the native thread id, and the last is a boolean value that indicates whether or not the thread is a daemon thread

dvm:::thread-end

The VM built-in probe is hotspot:::thread-stop and has the same parameters as the hotspot:::thread-start probe.

dvm:::class-load(char\* class_name)

The VM built-in probe that corresponds to this is hotspot:::class-loaded which has a few additional parameters. The first two are the string/length pair for the class name. The third argument is a unique integer identifier for the class loader which loaded the class, and the last is a boolean which indicates whether or not the class is a shared class.

dvm:::class-unload(char\* class_name)

The VM build-in probe which corresponds to this is hotspot:::class-unloaded which has the same paramters as hotspot:::class-loaded.

dvm:::gc-start(), dvm:::gc_finish(), and dvm::gc-stats(long objs, long space)

The VM has two top-level probes to indicate when a garbage collection phase has started and finished: hotspot:::gc-begin and hotspot:::gc-end. The gc-begin probe has a boolean parameter which indicates if the GC cycle was started due to a full heap or by user request. As each memory pool is collected, additional probes fire which contain the statistics for that pool: hotspot:::mem-pool-gc-begin and hotspot:::mem-pool-gc-end. These probes have 8 parameters. The first two are the string/length pair for the pool manager's name. The next two are the string/length pair for the pool name. The rest are long integers that contain the stats of the pool: initial size, used space, committed space, and maximum size.

dvm:::object-alloc(char\* class_name, long size) and dvm:::object-free(char\* class_name)

The VM has a built-in probe for allocation, hotspot:::object-alloc, but it must be enabled manually when the VM starts via the command-line flag -XX:+DTraceAllocProbes or -XX:+ExtendedDTraceProbes. The VM has no corresponding object-free probe for performance reasons. The object-alloc probe's first parameter is the Java thread id which is performing the allocation. The next two arguments are the string/length pair for the name of the class of which a new instance is being allocated. The last parameter is the size of the instance.

dvm::monitor-contended-enter[ed] and dvm::monitor-wait[ed]

The VM probes probes for contended enter and wait as hotspot:::monitor-contended-enter[ed] and hotspot:::monitor-wait[ed], but the first two parameters are the Java thread id and a unique monitor id. The third and fourth parameters are the string/length pair for the name of the class being acted upon. The hotspot:::monitor-wait probe has an additional parameter which indicates the timeout. The VM provides additional probes for contended-exit and notify events: hotspot:::monitor-contended-exit, hotspot:::monitor-notify, and hotspot:::monitor-notifyAll. These probes have the same parameters the contended enter probes. All of the monitor-releted probes in the VM are only enabled if the VM has been started with the -XX:+DTraceMonitorProbes or -XX:+ExtendedDTraceProbes command-line flag.

dvm:::method-entry and dvm:::method-return

The corresponding VM probes, hotspot:::method-entry and hotspot:::method-return, have the Java thread id as the first argument, followed by 3 string/length pairs for the class and method names and the signature. The built-in VM probes are only enabled if the -XX:+DTraceMethodProbes or -XX:+ExtendedDTraceProbes command-line arguments are provided.

Other built-in VM probes

The VM has additional built-in probes with no dvm equivalent for classloading, method compilation, and for tracking the entries and returns from JNI methods. Please refer to the beforementioned documentation for additional details.

Friday May 05, 2006

Cracking the Hotspot JVM

... or alternatively titled: "Why the verifier is so important." Java is a safe language, but how much trouble can you get into if you can get around the verifier? As it turns out, quite a lot.


I've seen a couple of requests lately for the VM to skip verification in certain situations to save some startup time costs. It's possible to do this, of course (the command-line flag -Xverify:none will do the trick), but I found myself wondering, "how bad could it be?" It's clear that the verifier enforces type safety so that your Java program won't do anything insane, and it's reasonably obvious that it protects the VM as well. But other than crashing your program (or the VM itself), can a malicious Java application subvert the VM to violate language or security constraints? I set out to find out, and what I found what was, to me, a surprising conclusion:


Yes, yes it can. With reasonable insight into the implementation of the VM, it turns out that a Java program can subvert quite a bit. Let's see how.


First off, we obviously are going to need a way around the protections that are built in to the VM and the language. We're going to have to do some sleezy things in order to get direct memory pointers from object references, and there's no way that javac is going to let do things like that. So we'll have to pitch that and use some lower-level assemblers to create a classfile that will do the thing we want it to do. I used jasm to create the subversive classfile, though binary editing is always a possibility if one is desperate.


So let's start off with a simple class that will get us a pointer to a Java object given a Java object reference:


Pointer.jasm:




public class Pointer
  version 45:3
{


// Returns the address of an object
public static Method addr:"(Ljava/lang/Object;)I"
  stack 1 locals 1
{
    iload_0; // pushes the first local as an int onto the stack (?)
    ireturn; // returns the int
}


} // end class Pointer




We can use jasm to create a classfile:





> jasm Pointer.jasm
> ls Pointer.class
Pointer.class




Ok, so far so good. But will the VM accept it as a valid classfile?





> java -client Pointer
Exception in thread "main" java.lang.VerifyError: (class: Pointer, method: addr signature: (Ljava/lang/Object;)I) Register 0 contains wrong type
>




Well, I suppose that's not too surprising. The first argument of this method is a reference and we try to load it as an int. This is what the verifier is there to catch. But: we can disable it:





> java -client -Xverify:none Pointer
Exception in thread "main" java.lang.NoSuchMethodError: main
>




Perfect! There's no main method, of course, which is why we get that error message, but if we've gotten this far, that means the VM has accepted it as a valid classfile (with the appropriate strong-arming, of course). We now have a classfile that has a method addr that will hopefully convert an object reference to an integer address. Let's give it a shot:


Crack.java:




public class Crack {
  public static void main(String argv[]) {
    String s = new String("hello, world!");
    System.out.format("Address of string: 0x%08x\\n", Pointer.addr(s));
  }
}




Just compile and run:





> javac Crack.java
> java -client -Xverify:none Crack
Address of string: 0xadebe418
>




Nifty! That's the kind of data that VM doesn't want to give out, yet here it is, and none too hard to get. But... it's pretty useless -- we can see it, but we can't really do anything with it. What we really need to do in order to be subversive is to be able to read and write data at arbitrary locations. One possibility is to take that value and feed it into a native method via JNI, but we're looking to write once and crack anywhere, so let's look for a Java solution.


It turns out that not too many Java bytecodes write to heap memory. All of the load, store, push and pop operations end up operating on the expression stack or the locals, which are most likely in our thread's frame or in CPU registers. The opcodes that do end up reading and writing in the Java heap are field accessors, such as getfield and
putfield
(or the static versions). But we need an object and a field to reference, and we need somehow to spoof the VM so that it reads the memory location we want it to. Luckily, since we've long ago ditched the verifier, this is possible to do.


Objects in the Hotspot VM look like this:

-------------------------------
|  Header word (Mark word)
|  Header word (Klass pointer)
-------------------------------
|  Instance fields (\*)
|  ...
-------------------------------


So if we can convince the VM that an object is sitting in just the right place, and that the object has an integer field, we can use the getfield opcode to get the first field in the object, which will read the data at the memory location that we desire (marked by a '(\*)' in the diagram), and push it onto the expression stack. Since we can't write to memory (yet!), this will only work if during the evaluation of getfield, the VM doesn't try to access the header words of the 'phantom' object. Luckily for us, it does not.


So, what we need to do to read memory from an arbitrary location is subtract 2 words from the address, use that value as an object, and access the first field of that object. We'll need not only the (bizarre) code but a class that has an integer as the first member. We can add these to our Pointer class:





public class Pointer
  version 45:3
{


private Field value:I;


// Creates a pointer to an object
public static Method addr:"(Ljava/lang/Object;)I"
  stack 1 locals 1
{
    iload_0;
    ireturn;
}


// Dereferences a pointer
public static Method deref:"(I)I"
  stack 3 locals 1
{
    iload_0;
    iconst_4;
    iconst_2;
    imul;
    isub;
    getfield Field value:"I";
    ireturn;
}


} // end class Pointer




So... what is going on here? First off, notice we've added the value field to Pointer. This is because we're going to fool the VM into thinking that there is an instance of Pointer in the heap, starting at two words before our target address, so that when we read the value field, we're getting the value of the address we want. Let's step through the deref method, which given an address should return to us the contents of that address:


iload_0 loads the argument onto the expression stack, and the next two opcodes push 4 and then 2 onto the stack. imul pops off and multiplies 4 and 2 and pushes the result (8, duh!) back onto the stack. The isub subtracts 8 from the passed address, leaving the result (address - 2 words) on the stack. We could have done this more simply and skipped the multiplication if there were a iconst_8 bytecode, but there isn't and our only other alternative for getting 8 on that stack is putting it in the constant pool and referencing it here. Too complicated. The next instruction expects an object on the stack and reads the value field from that object. Here's where the verifier would slap us around had we not taken the foresight to disable it, since what is on the stack is actually an integer and not an object. The getfield will now happily pop the address off the stack, add the field offset to it (in this case, 8), and read the value from memory and push it back onto the stack. Then all we have to do is return that value.


By the way, should any garbage collection occur here and the object moves, we're out of luck. Sure we'll read the memory location we're interested in, it's just that the object may not even be there anymore and we can be reading garbage. Even worse, if garbage collection happens at just the right time and looks at our thread and sees this 'phantom' object, it will try to find the references in it and will probably end up choking badly and bringing the whole VM down. Such is the danger of living outside the lines...


So let's test this out:


Crack.java:




public class Crack {
  public static void main(String argv[]) {
    String s = new String("hello, world");
    int addr = Pointer.addr(s);
    int value = Pointer.deref(addr);
    System.out.format("Value at: 0x%08x: %d\\n", addr, value);
  }
}







> jasm Pointer.jasm
> javac Crack.java
> java -client -Xverify:none Crack
Value at: 0xadebe448: 5
>




So the value of the mark word (the first header word) in the object is '5'. That particular bit pattern happens to mean that the object is not locked, is biasable, and has an age and hash of '0'. We are not limited to looking at mark word; we can easily adjust the addr variable to read other words from the object. For example, addr + 8 is a reference to the character array for the string and addr + 12 is the offset into that array. By the way - these are private fields of String so you really shouldn't be looking at them. Fair warning: if you lack the moral flexibility to be ok with this you should probably stop reading here, because it only gets worse.


You're still here, huh? So reading private fields just isn't edgy enough for you? Ok, then, let's take the next step and really get our hands dirty: time to change reality by writing data to memory too. The theory is essentially the same for this: we'll create a phantom object 2 words before the address we want to write to, and use putfield to write the data into that object's first field. The code to do this is almost identical to the deref method except that we have an argument to write and don't return anything. Here's the addition to Pointer.java:





// Stores a value to an address
public static Method store:"(II)V"
  stack 3 locals 2
{
    iload_0;
    iconst_4;
    iconst_2;
    imul;
    isub;
    iload_1;
    putfield Field value:"I";
    return;
}




Once we compile that, we're the masters of our domain. We can get the address of any object, and read and write to any field in that object if we so desire. If we know enough about the VM internals, we could probably find pointers and get into those data structures as well. So what kind of trouble can we cause?


Well, remember the value we found in the mark word of the string? '5' indicates an unlocked state. One possibility for misbehavior would be for us to rewrite that '5' into the mark word when the object is already locked, thus allowing an additional thread into the monitor. The code to do this is pretty simple:


(added to Crack.java):




public static int breakLock(Object o) {
  int addr = Pointer.addr(o);
  int savedLock = Pointer.deref(addr);
  Pointer.store(addr, 5);
  return savedLock;
}


public static void restoreLock(Object o, int savedLock) {
  int addr = Pointer.addr(o);
  Pointer.store(add, savedLock);
}




We save the old value of the lock and restore it later so that the thread who may have originally locked the thread will not be surprised to find a different value when it leaves the monitor. This assumes we'll be in and out before that thread is done, but that's ok for now. So let's demonstrate that we're above the law when it comes to locks:


(added to Crack.java):




public static void demoLockBreak() {
  s = new String("uh oh!");
  synchronized (s) {
    System.out.println("Thread " + Thread.currentThread() + " entering monitor");
    Thread thread = new Thread() {
      public void run() {
        int savedLock = breakLock(s);
        System.out.println("Thread " + Thread.currentThread() +
          " attempting to enter monitor (this should deadlock)");
        synchronized (s) {
          System.out.println("Thread " + Thread.currentThread() + " entering monitor");
          // The entirety of the run() function takes place while the
          // main thread is holding the lock for string s. We shouldn't
          // be able to get here.
          System.out.println("Ack! Multiple threads in the same monitor!");
        }
        restoreLock(s, savedLock);
        System.out.println("Thread " + Thread.currentThread() + " leaving monitor");
      }};
      thread.start();
      try { thread.join(); } catch (Exception e) {}
      System.out.println("Thread " + Thread.currentThread() + " leaving monitor");
    }
  }




Just add a call to this method from main().


This creates a string and enters its monitor and then spawns a thread which tries to enter the monitor at the same time. Since the first thread waits for the spawned thread to return (via the Thread.join() call at the end), this should deadlock since the spawned thread can't enter the monitor. But if the spawned thread uses our new lock breaking functions...





> jasm Pointer.jasm
> javac Crack.java
> java -client -Xverify:none Crack
Thread Thread[main,5,main] entering monitor
Thread Thread[Thread-0,5,main] attempting to enter monitor (this should deadlock)
Thread Thread[Thread-0,5,main] entering monitor
Ack! Multiple threads in the same monitor!
Thread Thread[Thread-0,5,main] leaving monitor
Thread Thread[main,5,main] leaving monitor




(insert evil laugh here)


So we've subverted a tenent of the Java language. Can we do worse? Probably. Since we have full access to public and private fields of any method, let's see if we can do something like... disabling the security mechanisms at the java library level.


If the java command is invoked with the -Djava.security.manager, (or if someone installed one before our code runs) then a security manager object is installed in the java.lang.System class, which the libraries will check with before allowing certain operations, such as file or network accesses. The reason this works is because once the security manager is installed, one cannot override it unless you already have the correct permissions (which, by default, we do not). But we don't need no stinkin' permissions. We have god-like abilities and are free to send that security manager to sleep with the fishes.


This one is a little more complicated, though, but only because we need to figure out where the security manager is located and how to get rid of it. As it turns out, it is in a static field of java.lang.System. All we really need to do is find that address and null it out.


Static fields aren't as straightforward as instance fields, though, since they're stored in a VM-specific data structure, and happen to be allocated behind some variable length objects (like the class's virtual method table). Though it takes some digging through the VM source, we can figure out where that field is. The java.lang.Class instance's 3rd word is a pointer to an internal data structure known as an instanceKlass. There exists one instanceKlass for each class type which contains lots of information about the class, including the static fields. Through much sophisticated detective work, I was able to determine that the security manager references lives at word 83 of the instanceKlass for the java.lang.System class (ok, it's wasn't sophisticated - I just ran without -Djava.security.manager and examined the first 100 words both before and after manually setting a security manager. The field that changed from 0 to a reference was it).


Here's the code in Crack.java:




public static void breakSecurity() {
  Class c = null;
  try { c = Class.forName("java.lang.System"); } catch (Exception e) {}
  int classAddr = Pointer.addr(c);
  int instanceKlassAddr = Pointer.deref(classAddr + 8);
  int managerFieldAddr = instanceKlassAddr + 83 \* 4;
  Pointer.store(managerFieldAddr, 0);
}




And here's the code the tests our crack (there's a check at the beginning to make sure we're running with -Djava.security.manager else there's not much of a point):


(in Crack.java):




public static void demoSecurityBreak() {
  try {
    System.setSecurityManager(new SecurityManager());
    System.out.println("No security manager installed. Run with " +
      "-Djava.security.manager to test security breaking");
    return;
  } catch (AccessControlException e) {
    System.out.println("Can't set security manager. " +
      "Attempting to crack it...");
  }


  breakSecurity();
  try {
    System.setSecurityManager(new SecurityManager());
    System.out.println("Ack! Set my own security manager! This is bad!");
  } catch (AccessControlException e) {
    System.out.println("OK: Was correctly unable to set security manager");
  }
}




Here's the output: after adding the call to main()





> java -client -Xverify:none -Djava.security.manager Crack
Can't set security manager. Attempting to crack it...
Ack! Set my own security manager! This is bad!



So, now in addition to reading data we're not suppose to read (private fields), doing things we're not supposed to do (multiple threads in a monitor), we've now also managed to disable the entire security system. All from Java code. Cool, eh? The moral of the story here is... run with the verifier :)


For completeness, here follows the final code for Crack.java and Pointer.jasm. I added a check to see if the verifier was enabled and disabled the cracks when it is enabled so that one could test that the things we're doing would be correctly caught if the verifier is on.


Pointer.jasm:




public class Pointer
version 45:3
{


private Field value:I;


// Creates a pointer to an object
public static Method addr:"(Ljava/lang/Object;)I"
  stack 1 locals 1
{
    iload_0;
    ireturn;
}


// Dereferences a pointer
public static Method deref:"(I)I"
  stack 3 locals 1
{
    iload_0;
    iconst_4;
    iconst_2;
    imul;
    isub;
    getfield Field value:"I";
    ireturn;
}


// Stores a value to an address
public static Method store:"(II)V"
  stack 3 locals 2
{
    iload_0;
    iconst_4;
    iconst_2;
    imul;
    isub;
    iload_1;
    putfield Field value:"I";
    return;
}


} // end Class Pointer



Crack.java:




import java.security.AccessControlException;


public class Crack {


  static String s;
  static boolean crack;


  public static void main(String argv[]) {
    try {
      Class c = Class.forName("Pointer");
      System.out.println("No VerifyError - crack away...");
      crack = true;
    } catch (VerifyError e) {
      System.out.println("Caught VerifyError, cracks disabled");
      crack = false;
    } catch (ClassNotFoundException e) {
      System.out.println("Missing pointer class");
      crack = false;
    }
    demoSecurityBreak();
    demoLockBreak();
  }


  public static void demoLockBreak() {
    s = new String("uh oh!");
    synchronized (s) {
      System.out.println("Thread " + Thread.currentThread() +
        " entering monitor");
      Thread thread = new Thread() {
        public void run() {
          int savedLock = breakLock(s);
          System.out.println("Thread " + Thread.currentThread() +
            " attempting to enter monitor (this should deadlock)");
          synchronized (s) {
            System.out.println("Thread " + Thread.currentThread() +
              " entering monitor");
            // The entirety of the run() function takes place while the
            // main thread is holding the lock for string s. We shouldn't
            // be able to get here.
            System.out.println("Ack! Multiple threads in the same monitor!");
          }
          restoreLock(s, savedLock);
          System.out.println("Thread " + Thread.currentThread() +
            " leaving monitor");
        }};
      thread.start();
      try { thread.join(); } catch (Exception e) {}
      System.out.println("Thread " + Thread.currentThread() +
        " leaving monitor");
    }
  }


  public static int breakLock(Object o) {
    if (crack) {
      int addr = Pointer.addr(o);
      int savedLock = Pointer.deref(addr);
      Pointer.store(addr, 5);
      return savedLock;
    }
    return 0;
  }


  public static void restoreLock(Object o, int savedLock) {
    if (crack) {
      int addr = Pointer.addr(o);
      Pointer.store(addr, savedLock);
    }
  }


  public static void demoSecurityBreak() {
    try {
      System.setSecurityManager(new SecurityManager());
      System.out.println("No security manager installed. Run with " +
        "-Djava.security.manager to test security breaking");
      return;
    } catch (AccessControlException e) {
      System.out.println("Can't set security manager. " +
        "Attempting to crack it...");
    }


    breakSecurity();
    try {
      System.setSecurityManager(new SecurityManager());
      System.out.println("Ack! Set my own security manager! This is bad!");
    } catch (AccessControlException e) {
      System.out.println("OK: Was correctly unable to set security manager");
    }
  }


  public static void breakSecurity() {
    if (crack) {
      Class c = null;
      try { c = Class.forName("java.lang.System"); } catch (Exception e) {}
      int classAddr = Pointer.addr(c);
      int instanceKlassAddr = Pointer.deref(classAddr + 8);
      int managerFieldAddr = instanceKlassAddr + 83 \* 4;
      Pointer.store(managerFieldAddr, 0);
    }
  }
}




Happy hacking!

Wednesday Feb 01, 2006

Scary.

This story and video is terrifying. Not for the faint of heart.

Thursday Oct 27, 2005

Updates to the mustang dtrace probes

Well, turns out made a little slip-up with the style of the dtrace probes in mustang. Easily corrected, though. Instead of the VM flag, ExtendedDtraceProbes, the name is ExtendedDTraceProbes (note the capital T). And in the JNI entry and exit probes, it should have been (and is now) "-entry" and "-return" instead of "_entry" and "_return" (dashes instead of underscores). I've fixed up the text on my previous post, so it's fixed now, but if you referenced it before, you may want to look again.

Wednesday Oct 19, 2005

Example dtrace scripts for Hotspot

Katya has a number of cool DtraceScripts that use the probes in mustang to perform a few tricks. She also has some helper scripts that make it easier to run dtrace scripts with Hotspot (unfortunately, 'dtrace -c java ' doesn't work since the VM library isn't loaded when dtrace starts). There are some nice utility scripts and great examples for getting started with the hotspot probes!

Built-in dtrace probes in Mustang

The latest solaris builds of mustang all have some USDT dtrace probes built into them (as of build 58). This means that any VM running on Solaris can be traced using dtrace with a (stable) set of probes.

I couldn't find the dtrace documentation in the mustang docs yet, so I figured this might be a good place to post a draft of it for now, for the early adopters. No guarantee on the stability now, of course, but hopefully this info will be good enough to get people started...

DtraceProbesDoc < HotspotRuntime < J2SE

Dtrace Probes in Mustang Hotspot JVM

The hotspot and hotspot_jni providers make available probes that can be used to monitor JVM internal state and activities as well as the Java application that is running. All of the probes are USDT probes and are accessed using the process-id of the JVM process. The probe details are listed in the next section, and the API is provided in the reference section.

The hotspot Provider

The hotspot provider makes available probes that can be used to track the lifespan of the VM, thread start and stop events, GC and memory pool statistics, method compilations, and monitor activity. With a startup flag, additional probes are enabled which can be used to monitor the running Java program, such as method enter and return probes, and object allocations. All of the hotspot probes originate in the VM library (libjvm.so), so they are also provided from programs which embed the VM.

Many of the probes in the provider have arguments that can be examined to provide further details on the state of the VM. Many of these probes' arguments are opaque IDs which can be used to link probe firings to each other, however strings and other data are also provided. When string values are provided, they are always present as a pair: a pointer to unterminated modified UTF-8 data (see JVM spec: 4.4.7) , and a length value which indicates the extent of that data. Because the string data (even when none of the characters are outside the ASCII range) is not guaranteed to be terminated by a NUL character, it is necessary to use the length-terminated copyinstr() intrinsic to read the string data from the process.

VM Lifecycle Probes

The probes that relate to the VM lifecycle are indicated below. None have any arguments at this time.

vm-init-begin Probe that fires just as the VM initialization begins
vm-init-end Probe that fires when the VM initialization finishes, and the VM is ready to start running application code
vm-shutdown Probe that fires as the VM is shutting down due to program termination or an error

Thread Lifecycle Probes

Two probes are available for tracking thread start and stop events.

thread-start Probes that fires when a thread is started. Provides the arguments listed below
thread-stop Probe that fires when the thread has completed. Provides the arguments listed below

Each of these probes has the following arguments:

args[0] A pointer to UTF-8 string data which contains the thread name
args[1] The length of the thread name data (in bytes)
args[2] The Java thread ID. This is the value that will match other hotspot probes which contain a thread argument
args[3] The native/OS thread ID. This is the ID assigned by the host operating system
args[4] A boolean value which indicates if this thread is a daemon or not. A value of 0 indicates a non-daemon thread

Classloading Probes

Two probes are available for tracking class loading and unloading activity.

class-loaded Probe that fires when a class has been loaded
class-unloaded Probe that fires when a class has been unloaded from the system

Each of these probes has the following arguments:

args[0] A pointer to UTF-8 string data which contains the name of the class that was loaded
args[1] The length of the class name data (in bytes)
args[2] The class loader ID, which is a unique identifier for a class loader in the VM. This is the class loader that loaded the class
args[3] A boolean value which indicates if the class is a shared class (if the class was loaded from the shared archive)

Garbage Collection Probes

Probes are available that can be used to measure the duration of a system-wide garbage collection cycle (for those garbage collectors that have a defined begin and end). Each memory pool can be tracked independently. The probes for individual pools pass the memory manager's name, the pool name, and pool usage information at both the begin and end of pool collection.

The provided GC-related probes are:

gc-begin Probe that fires when a system-wide collection is about to start. It's one argument (arg[0]) is a boolean value which indicates if this is to be a Full GC.
gc-end Probe that fires when a system-wide collection has completed. No arguments.
mem-pool-gc-begin Probe that fires when an individual memory pool is about to be collected. Provides the arguments listed below
mem-pool-gc-end Probe that fires after an individual memory pool has been collected. Provides the arguments listed below

Memory pool probe arguments:

args[0] A pointer to UTF-8 string data which contains the name of the manager which manages this memory pool
args[1] The length of the manager name data (in bytes)
args[2] A pointer to UTF-8 string data which contains the name of the memory pool
args[3] The length of the memory pool name data (in bytes)
args[4] The initial size of the memory pool (in bytes)
args[5] The amount of memory in use in the memory pool (in bytes)
args[6] The number of committed pages in the memory pool
args[7] The maximum size of the memory pool

Method Compilation Probes

Probes are available to indicate which methods are being compiled and by which compiler. Probes are also available to track the installing and uninstalling of compiled methods.

Probes that mark the begin and end of method compilation:

method-compile-begin Probe that fires as method compilation begins. Provides the arguments listed below
method-compile-end Probe that fires when method compilation completes. In addition to the arguments listed below, argv[8] is a boolean value which indicates if the compilation was successful

Method compilation probe arguments:

args[0] A pointer to UTF-8 string data which contains the name of the compiler which is compiling this method
args[1] The length of the compiler name data (in bytes)
args[2] A pointer to UTF-8 string data which contains the name of the class of the method being compiled
args[3] The length of the class name data (in bytes)
args[4] A pointer to UTF-8 string data which contains the name of the method being compiled
args[5] The length of the method name data (in bytes)
args[6] A pointer to UTF-8 string data which contains the signature of the method being compiled
args[7] The length of the signature data (in bytes)

When compiled methods are installed for execution or uninstalled, the following probes are fired:

compiled-method-load Probe that fires when a compiled method is installed. In addition to the arguments listed below, argv[6] contains a pointer to the compiled code, and argv[7] is the size of the compiled code
compiled-method-unload Probe that fires when a compiled method is uninstalled. Provides the arguments listed below

Compiled method loading probe arguments:

args[0] A pointer to UTF-8 string data which contains the name of the class of the method being installed
args[1] The length of the class name data (in bytes)
args[2] A pointer to UTF-8 string data which contains the name of the method being installed
args[3] The length of the method name data (in bytes)
args[4] A pointer to UTF-8 string data which contains the signature of the method being installed
args[5] The length of the signature data (in bytes)

Monitor Probes

As the Java application runs, threads will enter and exit monitors, wait on monitors, and perform notifications. Probes are available for all wait and notification events, as well as for contended monitor entry and exit events. A contended monitor entry is the situation where a thread attempts to enter a monitor when another thread is already in the monitor. A contended monitor exit event occurs when a thread leaves a monitor and other threads are waiting to enter to the monitor. Thus, contended enter and contended exit events may not match up to each other in relation to the thread that encounters these events, though it is expected that a contended exit from one thread should match up to a contended enter on another thread (the thread waiting to enter the monitor).

All monitor events provide the thread ID, a monitor ID, and the type of the class of the object as arguments. It is expected that the thread and the class will help map back to the Java program, while the monitor ID can provide matching information between probe firings.

Since the existance of these probes in the VM causes performance degradation, they will only fire if the VM flags ExtendedDTraceProbes or DTraceMonitorProbes are on. These can be set on the java command line via the arguments -XX:+ExtendedDTraceProbes or -XX:+DTraceMonitorProbes. These flags can also be turned on and off dynamically at runtime by using the jinfo utility.

If the above flags are off, the monitor probes are still present in the probe listing obtainable from dtrace, but will remain dormant and will never fire. It is intended that this restriction be removed in future releases of the VM, where these probes will be enabled all the time with no impact to performance.

The available probes:

monitor-contended-enter Probe that fires as a thread attempts to enter a contended monitor
monitor-contended-entered Probe that fires when a thread successfully enters the contended monitor
monitor-contended-exit Probe that fires when a thread leaves a monitor and other threads are waiting to enter
monitor-wait Probe that fires as a thread begins a wait on a monitor via Object.wait(). The probe has an additional argument, args[4] which is a 'long' value which indicates the timeout being used.
monitor-waited Probe that fires when a thread completes an Object.wait().
monitor-notify Probe that fires when a thread calls Object.notify() to notify waiters on a monitor
monitor-notifyAll Probe that fires when a thread calls Object.notifyAll() to notify waiters on a monitor

Monitor probe arguments:

args[0] The Java thread identifier for the thread peforming the monitor operation
args[1] A unique, but opaque identifier for the specific monitor that the action is performed upon
args[2] A pointer to UTF-8 string data which contains the class name of the object being acted upon
args[3] The length of the class name data (in bytes)

Application Tracking Probes

A few probes are provided to allow fine-grained examination of Java thread execution. These consist of probes that fire anytime a method is entered or returned from, as well as a probe that fires whenever a Java object has been allocated.

Since the existance of these probes in the VM causes performance degradation, they will only fire if the VM has the appropriate flags turned on. The ExtendedDTraceProbes flag will enable all the probles, while DTraceMethodProbes enabes only the method probes and DTraceAllocProbes enables only the object allocation probe. By default the probes are all present in any listing of the probes in the VM, but are dormant without the appropriate flag. It is intended that this restriction be removed in future releases of the VM, where these probes will be enabled all the time with no impact to performance.

The method entry and return probes:

method-entry Probe which fires when a method is being entered.
method-return Probe which fires when a method returns, either normally or due to an exception.

Method probe arguments:

args[0] The Java thread ID of the thread that is entering or leaving the method
args[1] A pointer to UTF-8 string data which contains the name of the class of the method
args[2] The length of the class name data (in bytes)
args[3] A pointer to UTF-8 string data which contains the name of the method
args[4] The length of the method name data (in bytes)
args[5] A pointer to UTF-8 string data which contains the signature of the method
args[6] The length of the signature data (in bytes)

The available allocation probe:

object-alloc Probe that fires when any object is allocated, provided that the ExtendedDTraceProbes or DTraceAllocProbes flags are turned on.

The object allocation probe has the following arguments:

args[0] The Java thread ID of the thread that is allocating the object
args[1] A pointer to UTF-8 string data which contains the class name of the object being allocated
args[2] The length of the class name data (in bytes)
args[3] The size of the object being allocated

The hotspot_jni Provider

In order to call from native code to Java code, due to embedding of the VM in an application or execution of native code within a Java application, the native code must make a call through the JNI interface. The JNI interface provides a number of methods for invoking Java code and examining the state of the VM. DTrace probes are provided at the entry point and return point for each of these methods. The probes are provided by the hotspot_jni provider. The name of the probe is the name of the JNI method, appended with "-entry" for entry probes, and "-return" for return probes. The arguments available at each entry probe are the arguments that were provided to the function (with the exception of the Invoke\* methods, which omit the arguments that are passed to the Java method). The return probes have the return value of the method as an argument (if available).

Reference

provider hotspot {
  probe vm-init-begin();
  probe vm-init-end();
  probe vm-shutdown();
  probe class-loaded(
      char\* class_name, uintptr_t class_name_len, uintptr_t class_loader_id, bool is_shared);
  probe class-unloaded(
      char\* class_name, uintptr_t class_name_len, uintptr_t class_loader_id, bool is_shared);
  probe gc-begin(bool is_full);
  probe gc-end();
  probe mem-pool-gc-begin(
      char\* mgr_name, uintptr_t mgr_name_len, char\* pool_name, uintptr_t pool_name_len, 
      uintptr_t initial_size, uintptr_t used, uintptr_t committed, uintptr_t max_size);
  probe mem-pool-gc-end(
      char\* mgr_name, uintptr_t mgr_name_len, char\* pool_name, uintptr_t pool_name_len, 
      uintptr_t initial_size, uintptr_t used, uintptr_t committed, uintptr_t max_size);
  probe thread-start(
      char\* thread_name, uintptr_t thread_name_length, 
      uintptr_t java_thread_id, uintptr_t native_thread_id, bool is_daemon);
  probe thread-stop(
      char\* thread_name, uintptr_t thread_name_length, 
      uintptr_t java_thread_id, uintptr_t native_thread_id, bool is_daemon);
  probe method-compile-begin(
      char\* class_name, uintptr_t class_name_len, 
      char\* method_name, uintptr_t method_name_len,
      char\* signature, uintptr_t signature_len);
  probe method-compile-end(
      char\* class_name, uintptr_t class_name_len, 
      char\* method_name, uintptr_t method_name_len,
      char\* signature, uintptr_t signature_len,
      bool is_success);
  probe compiled-method-load(
      char\* class_name, uintptr_t class_name_len, 
      char\* method_name, uintptr_t method_name_len,
      char\* signature, uintptr_t signature_len,
      void\* code, uintptr_t code_size);
  probe compiled-method-unload(
      char\* class_name, uintptr_t class_name_len, 
      char\* method_name, uintptr_t method_name_len,
      char\* signature, uintptr_t signature_len);
  probe monitor-contended-enter(
      uintptr_t java_thread_id, uintptr_t monitor_id, 
      char\* class_name, uintptr_t class_name_len);
  probe monitor-contended-entered(
      uintptr_t java_thread_id, uintptr_t monitor_id, 
      char\* class_name, uintptr_t class_name_len);
  probe monitor-contended-exit(
      uintptr_t java_thread_id, uintptr_t monitor_id, 
      char\* class_name, uintptr_t class_name_len);
  probe monitor-wait(
      uintptr_t java_thread_id, uintptr_t monitor_id, 
      char\* class_name, uintptr_t class_name_len,
      uintptr_t timeout);
  probe monitor-waited(
      uintptr_t java_thread_id, uintptr_t monitor_id, 
      char\* class_name, uintptr_t class_name_len);
  probe monitor-notify(
      uintptr_t java_thread_id, uintptr_t monitor_id, 
      char\* class_name, uintptr_t class_name_len);
  probe monitor-notifyAll(
      uintptr_t java_thread_id, uintptr_t monitor_id, 
      char\* class_name, uintptr_t class_name_len);
  probe method-entry(
      uintptr_t java_thread_id, char\* class_name, uintptr_t class_name_len,
      char\* method_name, uintptr_t method_name_len,
      char\* signature, uintptr_t signature_len);
  probe method-return(
      uintptr_t java_thread_id, char\* class_name, uintptr_t class_name_len,
      char\* method_name, uintptr_t method_name_len,
      char\* signature, uintptr_t signature_len);
  probe object-alloc(
      uintptr_t java_thread_id, char\* class_name, uintptr_t class_name_len,
      uintptr_t size);
};

provider hotspot_jni {
  probe AllocObject-entry(void\*, void\*);
  probe AllocObject-return(void\*);
  probe AttachCurrentThreadAsDaemon-entry(void\*, void\*\*, void\*);
  probe AttachCurrentThreadAsDaemon-return(uint32_t);
  probe AttachCurrentThread-entry(void\*, void\*\*, void\*);
  probe AttachCurrentThread-return(uint32_t);
  probe CallBooleanMethodA-entry(void\*, void\*, uintptr_t);
  probe CallBooleanMethodA-return(uintptr_t);
  probe CallBooleanMethod-entry(void\*, void\*, uintptr_t);
  probe CallBooleanMethod-return(uintptr_t);
  probe CallBooleanMethodV-entry(void\*, void\*, uintptr_t);
  probe CallBooleanMethodV-return(uintptr_t);
  probe CallByteMethodA-entry(void\*, void\*, uintptr_t);
  probe CallByteMethodA-return(char);
  probe CallByteMethod-entry(void\*, void\*, uintptr_t);
  probe CallByteMethod-return(char);
  probe CallByteMethodV-entry(void\*, void\*, uintptr_t);

  probe CallByteMethodV-return(char);
  probe CallCharMethodA-entry(void\*, void\*, uintptr_t);
  probe CallCharMethodA-return(uint16_t);
  probe CallCharMethod-entry(void\*, void\*, uintptr_t);
  probe CallCharMethod-return(uint16_t);
  probe CallCharMethodV-entry(void\*, void\*, uintptr_t);
  probe CallCharMethodV-return(uint16_t);
  probe CallDoubleMethodA-entry(void\*, void\*, uintptr_t);
  probe CallDoubleMethodA-return(double);
  probe CallDoubleMethod-entry(void\*, void\*, uintptr_t);
  probe CallDoubleMethod-return(double);
  probe CallDoubleMethodV-entry(void\*, void\*, uintptr_t);
  probe CallDoubleMethodV-return(double);
  probe CallFloatMethodA-entry(void\*, void\*, uintptr_t);
  probe CallFloatMethodA-return(float);
  probe CallFloatMethod-entry(void\*, void\*, uintptr_t);
  probe CallFloatMethod-return(float);
  probe CallFloatMethodV-entry(void\*, void\*, uintptr_t);
  probe CallFloatMethodV-return(float);
  probe CallIntMethodA-entry(void\*, void\*, uintptr_t);
  probe CallIntMethodA-return(uint32_t);
  probe CallIntMethod-entry(void\*, void\*, uintptr_t);
  probe CallIntMethod-return(uint32_t);
  probe CallIntMethodV-entry(void\*, void\*, uintptr_t);
  probe CallIntMethodV-return(uint32_t);
  probe CallLongMethodA-entry(void\*, void\*, uintptr_t);
  probe CallLongMethodA-return(uintptr_t);
  probe CallLongMethod-entry(void\*, void\*, uintptr_t);
  probe CallLongMethod-return(uintptr_t);
  probe CallLongMethodV-entry(void\*, void\*, uintptr_t);
  probe CallLongMethodV-return(uintptr_t);
  probe CallNonvirtualBooleanMethodA-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualBooleanMethodA-return(uintptr_t);
  probe CallNonvirtualBooleanMethod-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualBooleanMethod-return(uintptr_t);
  probe CallNonvirtualBooleanMethodV-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualBooleanMethodV-return(uintptr_t);
  probe CallNonvirtualByteMethodA-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualByteMethodA-return(char);
  probe CallNonvirtualByteMethod-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualByteMethod-return(char);
  probe CallNonvirtualByteMethodV-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualByteMethodV-return(char);
  probe CallNonvirtualCharMethodA-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualCharMethodA-return(uint16_t);
  probe CallNonvirtualCharMethod-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualCharMethod-return(uint16_t);
  probe CallNonvirtualCharMethodV-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualCharMethodV-return(uint16_t);
  probe CallNonvirtualDoubleMethodA-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualDoubleMethodA-return(double);
  probe CallNonvirtualDoubleMethod-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualDoubleMethod-return(double);
  probe CallNonvirtualDoubleMethodV-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualDoubleMethodV-return(double);
  probe CallNonvirtualFloatMethodA-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualFloatMethodA-return(float);
  probe CallNonvirtualFloatMethod-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualFloatMethod-return(float);
  probe CallNonvirtualFloatMethodV-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualFloatMethodV-return(float);
  probe CallNonvirtualIntMethodA-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualIntMethodA-return(uint32_t);
  probe CallNonvirtualIntMethod-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualIntMethod-return(uint32_t);
  probe CallNonvirtualIntMethodV-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualIntMethodV-return(uint32_t);
  probe CallNonvirtualLongMethodA-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualLongMethodA-return(uintptr_t);
  probe CallNonvirtualLongMethod-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualLongMethod-return(uintptr_t);
  probe CallNonvirtualLongMethodV-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualLongMethodV-return(uintptr_t);
  probe CallNonvirtualObjectMethodA-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualObjectMethodA-return(void\*);
  probe CallNonvirtualObjectMethod-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualObjectMethod-return(void\*);
  probe CallNonvirtualObjectMethodV-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualObjectMethodV-return(void\*);
  probe CallNonvirtualShortMethodA-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualShortMethodA-return(uint16_t);
  probe CallNonvirtualShortMethod-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualShortMethod-return(uint16_t);
  probe CallNonvirtualShortMethodV-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualShortMethodV-return(uint16_t);
  probe CallNonvirtualVoidMethodA-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualVoidMethodA-return();
  probe CallNonvirtualVoidMethod-entry(void\*, void\*, void\*, uintptr_t);
  probe CallNonvirtualVoidMethod-return();
  probe CallNonvirtualVoidMethodV-entry(void\*, void\*, void\*, uintptr_t);  
  probe CallNonvirtualVoidMethodV-return();
  probe CallObjectMethodA-entry(void\*, void\*, uintptr_t);
  probe CallObjectMethodA-return(void\*);
  probe CallObjectMethod-entry(void\*, void\*, uintptr_t);
  probe CallObjectMethod-return(void\*);
  probe CallObjectMethodV-entry(void\*, void\*, uintptr_t);
  probe CallObjectMethodV-return(void\*);
  probe CallShortMethodA-entry(void\*, void\*, uintptr_t);
  probe CallShortMethodA-return(uint16_t);
  probe CallShortMethod-entry(void\*, void\*, uintptr_t);
  probe CallShortMethod-return(uint16_t);
  probe CallShortMethodV-entry(void\*, void\*, uintptr_t);
  probe CallShortMethodV-return(uint16_t);
  probe CallStaticBooleanMethodA-entry(void\*, void\*, uintptr_t);
  probe CallStaticBooleanMethodA-return(uintptr_t);
  probe CallStaticBooleanMethod-entry(void\*, void\*, uintptr_t);
  probe CallStaticBooleanMethod-return(uintptr_t);
  probe CallStaticBooleanMethodV-entry(void\*, void\*, uintptr_t);
  probe CallStaticBooleanMethodV-return(uintptr_t);
  probe CallStaticByteMethodA-entry(void\*, void\*, uintptr_t);
  probe CallStaticByteMethodA-return(char);
  probe CallStaticByteMethod-entry(void\*, void\*, uintptr_t);
  probe CallStaticByteMethod-return(char);
  probe CallStaticByteMethodV-entry(void\*, void\*, uintptr_t);
  probe CallStaticByteMethodV-return(char);
  probe CallStaticCharMethodA-entry(void\*, void\*, uintptr_t);
  probe CallStaticCharMethodA-return(uint16_t);
  probe CallStaticCharMethod-entry(void\*, void\*, uintptr_t);
  probe CallStaticCharMethod-return(uint16_t);
  probe CallStaticCharMethodV-entry(void\*, void\*, uintptr_t);
  probe CallStaticCharMethodV-return(uint16_t);
  probe CallStaticDoubleMethodA-entry(void\*, void\*, uintptr_t);
  probe CallStaticDoubleMethodA-return(double);
  probe CallStaticDoubleMethod-entry(void\*, void\*, uintptr_t);
  probe CallStaticDoubleMethod-return(double);
  probe CallStaticDoubleMethodV-entry(void\*, void\*, uintptr_t);
  probe CallStaticDoubleMethodV-return(double);
  probe CallStaticFloatMethodA-entry(void\*, void\*, uintptr_t);
  probe CallStaticFloatMethodA-return(float);
  probe CallStaticFloatMethod-entry(void\*, void\*, uintptr_t);
  probe CallStaticFloatMethod-return(float);
  probe CallStaticFloatMethodV-entry(void\*, void\*, uintptr_t);
  probe CallStaticFloatMethodV-return(float);
  probe CallStaticIntMethodA-entry(void\*, void\*, uintptr_t);
  probe CallStaticIntMethodA-return(uint32_t);
  probe CallStaticIntMethod-entry(void\*, void\*, uintptr_t);
  probe CallStaticIntMethod-return(uint32_t);
  probe CallStaticIntMethodV-entry(void\*, void\*, uintptr_t);
  probe CallStaticIntMethodV-return(uint32_t);
  probe CallStaticLongMethodA-entry(void\*, void\*, uintptr_t);
  probe CallStaticLongMethodA-return(uintptr_t);
  probe CallStaticLongMethod-entry(void\*, void\*, uintptr_t);
  probe CallStaticLongMethod-return(uintptr_t);
  probe CallStaticLongMethodV-entry(void\*, void\*, uintptr_t);
  probe CallStaticLongMethodV-return(uintptr_t);
  probe CallStaticObjectMethodA-entry(void\*, void\*, uintptr_t);
  probe CallStaticObjectMethodA-return(void\*);
  probe CallStaticObjectMethod-entry(void\*, void\*, uintptr_t);
  probe CallStaticObjectMethod-return(void\*);
  probe CallStaticObjectMethodV-entry(void\*, void\*, uintptr_t);
  probe CallStaticObjectMethodV-return(void\*);
  probe CallStaticShortMethodA-entry(void\*, void\*, uintptr_t);
  probe CallStaticShortMethodA-return(uint16_t);
  probe CallStaticShortMethod-entry(void\*, void\*, uintptr_t);
  probe CallStaticShortMethod-return(uint16_t);
  probe CallStaticShortMethodV-entry(void\*, void\*, uintptr_t);
  probe CallStaticShortMethodV-return(uint16_t);
  probe CallStaticVoidMethodA-entry(void\*, void\*, uintptr_t);
  probe CallStaticVoidMethodA-return();
  probe CallStaticVoidMethod-entry(void\*, void\*, uintptr_t);
  probe CallStaticVoidMethod-return(); 
  probe CallStaticVoidMethodV-entry(void\*, void\*, uintptr_t);  
  probe CallStaticVoidMethodV-return();
  probe CallVoidMethodA-entry(void\*, void\*, uintptr_t);  
  probe CallVoidMethodA-return();
  probe CallVoidMethod-entry(void\*, void\*, uintptr_t);  
  probe CallVoidMethod-return(); 
  probe CallVoidMethodV-entry(void\*, void\*, uintptr_t);  
  probe CallVoidMethodV-return();
  probe CreateJavaVM-entry(void\*\*, void\*\*, void\*);
  probe CreateJavaVM-return(uint32_t);
  probe DefineClass-entry(void\*, const char\*, void\*, char, uintptr_t);
  probe DefineClass-return(void\*);
  probe DeleteGlobalRef-entry(void\*, void\*);
  probe DeleteGlobalRef-return();
  probe DeleteLocalRef-entry(void\*, void\*);
  probe DeleteLocalRef-return();
  probe DeleteWeakGlobalRef-entry(void\*, void\*);
  probe DeleteWeakGlobalRef-return();
  probe DestroyJavaVM-entry(void\*);
  probe DestroyJavaVM-return(uint32_t);
  probe DetachCurrentThread-entry(void\*);
  probe DetachCurrentThread-return(uint32_t);
  probe EnsureLocalCapacity-entry(void\*, uint32_t);
  probe EnsureLocalCapacity-return(uint32_t);
  probe ExceptionCheck-entry(void\*);
  probe ExceptionCheck-return(uintptr_t);
  probe ExceptionClear-entry(void\*);
  probe ExceptionClear-return();
  probe ExceptionDescribe-entry(void\*);  
  probe ExceptionDescribe-return();
  probe ExceptionOccurred-entry(void\*);
  probe ExceptionOccurred-return(void\*);
  probe FatalError-entry(void\* env, const char\*);
  probe FatalError-return();
  probe FindClass-entry(void\*, const char\*);
  probe FindClass-return(void\*);
  probe FromReflectedField-entry(void\*, void\*);
  probe FromReflectedField-return(uintptr_t);
  probe FromReflectedMethod-entry(void\*, void\*);
  probe FromReflectedMethod-return(uintptr_t);
  probe GetArrayLength-entry(void\*, void\*);
  probe GetArrayLength-return(uintptr_t);
  probe GetBooleanArrayElements-entry(void\*, void\*, uintptr_t\*);
  probe GetBooleanArrayElements-return(uintptr_t\*);
  probe GetBooleanArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, uintptr_t\*);
  probe GetBooleanArrayRegion-return();
  probe GetBooleanField-entry(void\*, void\*, uintptr_t);
  probe GetBooleanField-return(uintptr_t);
  probe GetByteArrayElements-entry(void\*, void\*, uintptr_t\*);
  probe GetByteArrayElements-return(char\*);
  probe GetByteArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, char\*);
  probe GetByteArrayRegion-return();
  probe GetByteField-entry(void\*, void\*, uintptr_t);
  probe GetByteField-return(char);
  probe GetCharArrayElements-entry(void\*, void\*, uintptr_t\*);
  probe GetCharArrayElements-return(uint16_t\*);
  probe GetCharArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, uint16_t\*);
  probe GetCharArrayRegion-return();
  probe GetCharField-entry(void\*, void\*, uintptr_t);
  probe GetCharField-return(uint16_t);
  probe GetCreatedJavaVMs-entry(void\*\*, uintptr_t, uintptr_t\*);
  probe GetCreatedJavaVMs-return(uintptr_t);
  probe GetCreateJavaVMs-entry(void\*, uintptr_t, uintptr_t\*);
  probe GetCreateJavaVMs-return(uint32_t);
  probe GetDefaultJavaVMInitArgs-entry(void\*);
  probe GetDefaultJavaVMInitArgs-return(uint32_t);
  probe GetDirectBufferAddress-entry(void\*, void\*);
  probe GetDirectBufferAddress-return(void\*);
  probe GetDirectBufferCapacity-entry(void\*, void\*);
  probe GetDirectBufferCapacity-return(uintptr_t);
  probe GetDoubleArrayElements-entry(void\*, void\*, uintptr_t\*);
  probe GetDoubleArrayElements-return(double\*);
  probe GetDoubleArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, double\*);
  probe GetDoubleArrayRegion-return();
  probe GetDoubleField-entry(void\*, void\*, uintptr_t);
  probe GetDoubleField-return(double);
  probe GetEnv-entry(void\*, void\*, void\*);
  probe GetEnv-return(uint32_t);
  probe GetFieldID-entry(void\*, void\*, const char\*, const char\*);
  probe GetFieldID-return(uintptr_t);
  probe GetFloatArrayElements-entry(void\*, void\*, uintptr_t\*);
  probe GetFloatArrayElements-return(float\*);
  probe GetFloatArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, float\*);
  probe GetFloatArrayRegion-return();
  probe GetFloatField-entry(void\*, void\*, uintptr_t);
  probe GetFloatField-return(float);
  probe GetIntArrayElements-entry(void\*, void\*, uintptr_t\*);
  probe GetIntArrayElements-return(uint32_t\*);
  probe GetIntArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, uint32_t\*);
  probe GetIntArrayRegion-return();
  probe GetIntField-entry(void\*, void\*, uintptr_t);
  probe GetIntField-return(uint32_t);
  probe GetJavaVM-entry(void\*, void\*\*);
  probe GetJavaVM-return(uint32_t);
  probe GetLongArrayElements-entry(void\*, void\*, uintptr_t\*);
  probe GetLongArrayElements-return(uintptr_t\*);
  probe GetLongArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, uintptr_t\*);
  probe GetLongArrayRegion-return();
  probe GetLongField-entry(void\*, void\*, uintptr_t);
  probe GetLongField-return(uintptr_t);
  probe GetMethodID-entry(void\*, void\*, const char\*, const char\*);
  probe GetMethodID-return(uintptr_t);
  probe GetObjectArrayElement-entry(void\*, void\*, uintptr_t);
  probe GetObjectArrayElement-return(void\*);
  probe GetObjectClass-entry(void\*, void\*);
  probe GetObjectClass-return(void\*);
  probe GetObjectField-entry(void\*, void\*, uintptr_t);
  probe GetObjectField-return(void\*);
  probe GetObjectRefType-entry(void\*, void\*);
  probe GetObjectRefType-return(void\*);
  probe GetPrimitiveArrayCritical-entry(void\*, void\*, uintptr_t\*);
  probe GetPrimitiveArrayCritical-return(void\*);
  probe GetShortArrayElements-entry(void\*, void\*, uintptr_t\*);
  probe GetShortArrayElements-return(uint16_t\*);
  probe GetShortArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, uint16_t\*);
  probe GetShortArrayRegion-return();
  probe GetShortField-entry(void\*, void\*, uintptr_t);
  probe GetShortField-return(uint16_t);
  probe GetStaticBooleanField-entry(void\*, void\*, uintptr_t);
  probe GetStaticBooleanField-return(uintptr_t);
  probe GetStaticByteField-entry(void\*, void\*, uintptr_t);
  probe GetStaticByteField-return(char);
  probe GetStaticCharField-entry(void\*, void\*, uintptr_t);
  probe GetStaticCharField-return(uint16_t);
  probe GetStaticDoubleField-entry(void\*, void\*, uintptr_t);
  probe GetStaticDoubleField-return(double);
  probe GetStaticFieldID-entry(void\*, void\*, const char\*, const char\*);
  probe GetStaticFieldID-return(uintptr_t);
  probe GetStaticFloatField-entry(void\*, void\*, uintptr_t);
  probe GetStaticFloatField-return(float);
  probe GetStaticIntField-entry(void\*, void\*, uintptr_t);
  probe GetStaticIntField-return(uint32_t);
  probe GetStaticLongField-entry(void\*, void\*, uintptr_t);
  probe GetStaticLongField-return(uintptr_t);
  probe GetStaticMethodID-entry(void\*, void\*, const char\*, const char\*);
  probe GetStaticMethodID-return(uintptr_t);
  probe GetStaticObjectField-entry(void\*, void\*, uintptr_t);
  probe GetStaticObjectField-return(void\*);
  probe GetStaticShortField-entry(void\*, void\*, uintptr_t);
  probe GetStaticShortField-return(uint16_t);
  probe GetStringChars-entry(void\*, void\*, uintptr_t\*);
  probe GetStringChars-return(const uint16_t\*);
  probe GetStringCritical-entry(void\*, void\*, uintptr_t\*);
  probe GetStringCritical-return(const uint16_t\*);
  probe GetStringLength-entry(void\*, void\*);
  probe GetStringLength-return(uintptr_t);
  probe GetStringRegion-entry(void\*, void\*, uintptr_t, uintptr_t, uint16_t\*);
  probe GetStringRegion-return();
  probe GetStringUTFChars-entry(void\*, void\*, uintptr_t\*);
  probe GetStringUTFChars-return(const char\*);
  probe GetStringUTFLength-entry(void\*, void\*);
  probe GetStringUTFLength-return(uintptr_t);
  probe GetStringUTFRegion-entry(void\*, void\*, uintptr_t, uintptr_t, char\*);
  probe GetStringUTFRegion-return();
  probe GetSuperclass-entry(void\*, void\*);
  probe GetSuperclass-return(void\*);
  probe GetVersion-entry(void\*);
  probe GetVersion-return(uint32_t);
  probe IsAssignableFrom-entry(void\*, void\*, void\*);
  probe IsAssignableFrom-return(uintptr_t);
  probe IsInstanceOf-entry(void\*, void\*, void\*);
  probe IsInstanceOf-return(uintptr_t);
  probe IsSameObject-entry(void\*, void\*, void\*);
  probe IsSameObject-return(uintptr_t);
  probe MonitorEnter-entry(void\*, void\*);
  probe MonitorEnter-return(uint32_t);
  probe MonitorExit-entry(void\*, void\*);
  probe MonitorExit-return(uint32_t);
  probe NewBooleanArray-entry(void\*, uintptr_t);
  probe NewBooleanArray-return(void\*);
  probe NewByteArray-entry(void\*, uintptr_t);
  probe NewByteArray-return(void\*);
  probe NewCharArray-entry(void\*, uintptr_t);
  probe NewCharArray-return(void\*);
  probe NewDirectByteBuffer-entry(void\*, void\*, uintptr_t);
  probe NewDirectByteBuffer-return(void\*);
  probe NewDoubleArray-entry(void\*, uintptr_t);
  probe NewDoubleArray-return(void\*);
  probe NewFloatArray-entry(void\*, uintptr_t);
  probe NewFloatArray-return(void\*);
  probe NewGlobalRef-entry(void\*, void\*);
  probe NewGlobalRef-return(void\*);
  probe NewIntArray-entry(void\*, uintptr_t);
  probe NewIntArray-return(void\*);
  probe NewLocalRef-entry(void\*, void\*);
  probe NewLocalRef-return(void\*);
  probe NewLongArray-entry(void\*, uintptr_t);
  probe NewLongArray-return(void\*);
  probe NewObjectA-entry(void\*, void\*, uintptr_t);  
  probe NewObjectA-return(void\*);
  probe NewObjectArray-entry(void\*, uintptr_t, void\*, void\*);
  probe NewObjectArray-return(void\*);
  probe NewObject-entry(void\*, void\*, uintptr_t); 
  probe NewObject-return(void\*);
  probe NewObjectV-entry(void\*, void\*, uintptr_t);  
  probe NewObjectV-return(void\*);
  probe NewShortArray-entry(void\*, uintptr_t);
  probe NewShortArray-return(void\*);
  probe NewString-entry(void\*, const uint16_t\*, uintptr_t);
  probe NewString-return(void\*);
  probe NewStringUTF-entry(void\*, const char\*);
  probe NewStringUTF-return(void\*);
  probe NewWeakGlobalRef-entry(void\*, void\*);
  probe NewWeakGlobalRef-return(void\*);
  probe PopLocalFrame-entry(void\*, void\*);
  probe PopLocalFrame-return(void\*);
  probe PushLocalFrame-entry(void\*, uint32_t);
  probe PushLocalFrame-return(uint32_t);
  probe RegisterNatives-entry(void\*, void\*, const void\*, uint32_t);  
  probe RegisterNatives-return(uint32_t);
  probe ReleaseBooleanArrayElements-entry(void\*, void\*, uintptr_t\*, uint32_t);
  probe ReleaseBooleanArrayElements-return();
  probe ReleaseByteArrayElements-entry(void\*, void\*, char\*, uint32_t);
  probe ReleaseByteArrayElements-return();
  probe ReleaseCharArrayElements-entry(void\*, void\*, uint16_t\*, uint32_t);
  probe ReleaseCharArrayElements-return();
  probe ReleaseDoubleArrayElements-entry(void\*, void\*, double\*, uint32_t);
  probe ReleaseDoubleArrayElements-return();
  probe ReleaseFloatArrayElements-entry(void\*, void\*, float\*, uint32_t);
  probe ReleaseFloatArrayElements-return();
  probe ReleaseIntArrayElements-entry(void\*, void\*, uint32_t\*, uint32_t);
  probe ReleaseIntArrayElements-return();
  probe ReleaseLongArrayElements-entry(void\*, void\*, uintptr_t\*, uint32_t);
  probe ReleaseLongArrayElements-return();
  probe ReleaseObjectArrayElements-entry(void\*, void\*, void\*\*, uint32_t);
  probe ReleaseObjectArrayElements-return();
  probe ReleasePrimitiveArrayCritical-entry(void\*, void\*, void\*, uint32_t);
  probe ReleasePrimitiveArrayCritical-return();
  probe ReleaseShortArrayElements-entry(void\*, void\*, uint16_t\*, uint32_t);
  probe ReleaseShortArrayElements-return();
  probe ReleaseStringChars-entry(void\*, void\*, const uint16_t\*);
  probe ReleaseStringChars-return();
  probe ReleaseStringCritical-entry(void\*, void\*, const uint16_t\*);
  probe ReleaseStringCritical-return();
  probe ReleaseStringUTFChars-entry(void\*, void\*, const char\*);
  probe ReleaseStringUTFChars-return();
  probe SetBooleanArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, const uintptr_t\*);
  probe SetBooleanArrayRegion-return();
  probe SetBooleanField-entry(void\*, void\*, uintptr_t, uintptr_t);
  probe SetBooleanField-return();
  probe SetByteArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, const char\*);
  probe SetByteArrayRegion-return();
  probe SetByteField-entry(void\*, void\*, uintptr_t, char);
  probe SetByteField-return();
  probe SetCharArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, const uint16_t\*);
  probe SetCharArrayRegion-return();
  probe SetCharField-entry(void\*, void\*, uintptr_t, uint16_t);
  probe SetCharField-return();
  probe SetDoubleArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, const double\*);
  probe SetDoubleArrayRegion-return();
  probe SetDoubleField-entry(void\*, void\*, uintptr_t, double);
  probe SetDoubleField-return();
  probe SetFloatArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, const float\*);
  probe SetFloatArrayRegion-return();
  probe SetFloatField-entry(void\*, void\*, uintptr_t, float);
  probe SetFloatField-return();
  probe SetIntArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, const uint32_t\*);
  probe SetIntArrayRegion-return();
  probe SetIntField-entry(void\*, void\*, uintptr_t, uint32_t);
  probe SetIntField-return();
  probe SetLongArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, const uintptr_t\*);
  probe SetLongArrayRegion-return();
  probe SetLongField-entry(void\*, void\*, uintptr_t, uintptr_t);
  probe SetLongField-return();
  probe SetObjectArrayElement-entry(void\*, void\*, uintptr_t, void\*);
  probe SetObjectArrayElement-return();
  probe SetObjectField-entry(void\*, void\*, uintptr_t, void\*);
  probe SetObjectField-return();
  probe SetShortArrayRegion-entry(void\*, void\*, uintptr_t, uintptr_t, const uint16_t\*);
  probe SetShortArrayRegion-return();
  probe SetShortField-entry(void\*, void\*, uintptr_t, uint16_t);
  probe SetShortField-return();
  probe SetStaticBooleanField-entry(void\*, void\*, uintptr_t, uintptr_t);
  probe SetStaticBooleanField-return();
  probe SetStaticByteField-entry(void\*, void\*, uintptr_t, char);
  probe SetStaticByteField-return();
  probe SetStaticCharField-entry(void\*, void\*, uintptr_t, uint16_t);
  probe SetStaticCharField-return();
  probe SetStaticDoubleField-entry(void\*, void\*, uintptr_t, double);
  probe SetStaticDoubleField-return();
  probe SetStaticFloatField-entry(void\*, void\*, uintptr_t, float);
  probe SetStaticFloatField-return();
  probe SetStaticIntField-entry(void\*, void\*, uintptr_t, uint32_t);
  probe SetStaticIntField-return();
  probe SetStaticLongField-entry(void\*, void\*, uintptr_t, uintptr_t);
  probe SetStaticLongField-return();
  probe SetStaticObjectField-entry(void\*, void\*, uintptr_t, void\*);
  probe SetStaticObjectField-return();
  probe SetStaticShortField-entry(void\*, void\*, uintptr_t, uint16_t);
  probe SetStaticShortField-return();
  probe Throw-entry(void\*, void\*);
  probe ThrowNew-entry(void\*, void\*, const char\*);  
  probe ThrowNew-return(uint32_t);
  probe Throw-return(uint32_t);
  probe ToReflectedField-entry(void\*, void\*, uintptr_t, uintptr_t);
  probe ToReflectedField-return(void\*);
  probe ToReflectedMethod-entry(void\*, void\*, uintptr_t, uintptr_t);
  probe ToReflectedMethod-return(void\*);
  probe UnregisterNatives-entry(void\*, void\*);  
  probe UnregisterNatives-return(uint32_t);
};

Thursday Feb 24, 2005

The Pirates Problem

Inspired by Dave Brillhart's puzzle blog section, I've decided to create one of my own where I can post some of my favorite puzzles. Here my favorite: 5 pirates have a treasure of 100 gold pieces to split up after a long and profitable trip. The pirates are ranked by seniority and it is always the most senior pirate who decides how to divide up the booty amongst himself and any remaining pirates. However, the pirates are democratic: if the most senior pirate does not get at least 50% of the vote (including himself), then he is killed and the process repeats itself with the nextmost senior pirate proposing the breakup. The pirates are all completely rational and know that their compatriots are also completely rational. All of the pirates use the following priorities the drive their voting: 1. They don't want to get killed 2. They want to get the most money possible 3. They want to kill other pirates. How does the most senior pirate divide up the treasure such that he keeps as much as he possibly can for himself?
About

kamg

Search

Top Tags
Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today