2

I am trying to find out if it is possible to get the bytecode of a function after it was loaded to the JVM.

I know I can get the code from the .class file using ClassLoder and I can manipulate it using Instrumentation, but this is not the issue here.

Suppose I have a compiled Java program called Test.class and I run, its bytecode will be loaded the JVM, from this point can I get the bytecode?

EDIT: Following the answers I want to point again, my intention is to inspect code which is running on the JVM but I dont have access to its compiled file.

antonpuz
  • 3,256
  • 4
  • 25
  • 48
  • do you need to get it programatically or through some external tool? – Chris Mowforth Aug 20 '15 at 19:54
  • doesnt matter, suppose I know that code from the Test class was loaded, is there any way to see the bytecode(the instructions)? – antonpuz Aug 20 '15 at 19:55
  • 1
    You can read the original byte code as a resource on the ClassLoader InputStream and parse it with a library like ASM. – Peter Lawrey Aug 20 '15 at 20:09
  • @PeterLawrey as I wrote in the question I am familiar with the instrumentation, I am looking for a way to read the bytecode from the JVM not the compiled file – antonpuz Aug 20 '15 at 20:19
  • To retrieve the byte code from the JVM would only be possible if the JVM retains the byte code, even after it has optimized and compiled it into native code. – wero Aug 20 '15 at 20:49
  • @Anton.P the byte code comes from the class file which is where you need to get it from also. The JVM doesn't keep an extra copy. The only place to get the bytes code from where the JVM got it from. – Peter Lawrey Aug 20 '15 at 21:00
  • @PeterLawrey What if the bytecode comes from a network or even from a dynamically generated byte array? JVM must keep the bytecode internally. But how to get it? - I guess this is what the question is about. – apangin Aug 20 '15 at 21:22
  • @apangin it doesn't keep the byte code as it almost immediate starts changing it. If you need to record the byte code before it is loaded you can use Instrumentation. This could be used to cache the byte code of each class before it loaded so you know what it was (this doesn't consider that any other Instrumentation class could alter it before or after you are called) – Peter Lawrey Aug 20 '15 at 21:26
  • 1
    @PeterLawrey It must keep the byte code (as to HotSpot JVM, it indeed does) in order to support [Instrumentation.retransformClasses](http://docs.oracle.com/javase/8/docs/api/java/lang/instrument/Instrumentation.html#retransformClasses-java.lang.Class...-), debugging, [JVMTI GetBytecodes](http://docs.oracle.com/javase/8/docs/platform/jvmti/jvmti.html#GetBytecodes) functionality etc. – apangin Aug 20 '15 at 22:55
  • @apangin AFAIK, it obtains the byte code from source to do this (except for debugging which it only does when debugging is enabled) – Peter Lawrey Aug 21 '15 at 06:12
  • 1
    @PeterLawrey It [reconstitutes](http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/dae2d83e0ec2/src/share/vm/prims/jvmtiClassFileReconstituter.cpp) the byte code from internal structures. – apangin Aug 21 '15 at 07:45

2 Answers2

1

Without more context I'm not sure what you're trying to do, but:

If you just want to see the contents of a class file (bytecodes and all), then javap -c Test.class will spit it out for you.

If you want to see what the code looks like while a JVM is running, an agent might be what you're looking for.

Remember that if your function (method? I'm assuming we're not talking about lambdas here) relies on any variables from the parent scope then the bytecode for said method doesn't describe what it does on its own. Think of inner classes, lambdas, e.t.c.

Edit:

As Peter Lawrey said, if you want to forgo agents, feeding the raw bytes from a class loader into ASM's visitor API is a good start. The ASM doc has a tutorial; Google also turned up this (see part 2). HTH

Chris Mowforth
  • 6,689
  • 2
  • 26
  • 36
  • thanks for the answer, as I wrote in the question I am familiar with the instrumentation ability (ASM which you pointed) and I am pointing to the case where I dont have access to the class file (added in edit). Can you please tell me more about the agent option? if something can be done in agent cant it be done in another program? and whats can be done from the agent? – antonpuz Aug 20 '15 at 20:18
1

HotSpot Serviceability Agent can do this!

Here is an example how to get the bytecode of remote main(String[]) method in test.HelloWorld class:

import sun.jvm.hotspot.oops.InstanceKlass;
import sun.jvm.hotspot.oops.Method;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.tools.Tool;

public class GetBytecode extends Tool {

    @Override
    public void run() {
        VM.getVM().getSystemDictionary().allClassesDo(klass -> {
            if (klass.getName().asString().equals("test/HelloWorld")) {
                Method method = ((InstanceKlass) klass).findMethod("main", "([Ljava/lang/String;)V");
                for (byte bc : method.getByteCode()) {
                    System.out.printf("%02x ", bc);
                }
            }
        });
    }

    public static void main(String[] args) {
        new GetBytecode().execute(args);
    }
}

Run java -cp <JDK_HOME>/lib/sa-jdi.jar:. GetBytecode <PID>

apangin
  • 92,924
  • 10
  • 193
  • 247