How to View Bytecode of Class File

Is it possible to view a Java class files bytecode

I've been working on a decompiler that has a color-coded bytecode output mode (which I find far more readable than javap). It can also output Java code or an intermediate 'bytecode AST'.

How do I read a Java class file (Java bytecode)

javap -c X will show the disassembly of X.class.

How to determine the Java byte code version of the current class programatically?

Take a look at question: Java API to find out the JDK version a class file is compiled for?

How to view Bytecode spring framework generated proxy classes?

I do not know if Spring has on-board means to do that, but AFAIK the ASM classes embedded in Spring do not include the TraceClassVisitor. So if you like its output, you have to use ASM (artifact asm-util) directly, which I assume you did for your sample code. If you want to stick with on-board means, you can just write a transformer which dumps the full byte code as a class file into a file and then look at the file with the JDK command line tool javap, e.g. via javap -c -p -v MyDumpedBytes.class.

Anyway, an easy thing to do is to implement a Java agent and attach it to the Java command line starting the Spring project via -javaagent:/path/to/my-agent.jar. I found this article for you which explains how to implement a simple Java agent with manifest file etc. and also how to attach it to a running process via Java attach API. The article uses Javassist as an example for writing a transformer, but you can just use ASM instead.

Your Java agent + transformer would look something like this:

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.util.TraceClassVisitor;

import java.io.PrintWriter;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

class TraceClassTransformer implements ClassFileTransformer {

/**
* Attach agent dynamically after JVM start-up
*/
public static void agentmain(String commandLineOptions, Instrumentation instr) {
premain(commandLineOptions, instr);
}

/**
* Start agent via <code>-javaagent:/path/to/my-agent.jar=<i>options</i></code> JVM parameter
*/
public static void premain(String commandLineOptions, Instrumentation instrumentation) {
TraceClassTransformer transformer = new TraceClassTransformer();
instrumentation.addTransformer(transformer, true);
}

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
dumpClass(classfileBuffer);
// Do not apply any transformation
return null;
}

private void dumpClass(byte[] classfileBuffer) {
TraceClassVisitor visitor = new TraceClassVisitor(new PrintWriter(System.out));
ClassReader reader = new ClassReader(classfileBuffer);
reader.accept(visitor, 0);
}

}

Just make sure that the agent's manifest enables retransformation via Can-Retransform-Classes: true.

After the agent has started, you can just call instrumentation.retransformClasses(proxyInstance.getClass()); and then enjoy the log output.

In order to make it a bit simpler for this example, let us use byte-buddy-agent which contains a neat little tool set to attach transformers during runtime without the need to wrap them into Java agents. The artifact is small and does not contain the rest of ByteBuddy, just the agent tool.

That would simplify your class to (you can keep or drop the premain and agentmain methods, depending on whether you are planning to use the class as a Java agent or not):

import net.bytebuddy.agent.ByteBuddyAgent;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.util.TraceClassVisitor;

import java.io.Closeable;
import java.io.PrintWriter;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.reflect.Proxy;
import java.security.ProtectionDomain;

class TraceClassTransformer implements ClassFileTransformer {
public static void main(String[] args) throws UnmodifiableClassException {
// Easy way to get an Instrumentation instance, so we can directly register our transformer on it
Instrumentation instrumentation = ByteBuddyAgent.install();
// I am just creating a Java dynamic proxy for a JRE interface. In your own application,
// you would just get a reference to a dynamic proxy created by Spring.
Object proxyInstance = Proxy.newProxyInstance(
Closeable.class.getClassLoader(),
new Class<?>[] { Closeable.class },
(proxy, method, args1) -> null
);

// Register + use dummy ClassFileTransformer, then unregister again (optional)
TraceClassTransformer transformer = new TraceClassTransformer();
try {
instrumentation.addTransformer(transformer, true);
instrumentation.retransformClasses(proxyInstance.getClass());
}
finally {
instrumentation.removeTransformer(transformer);
}
}

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
dumpClass(classfileBuffer);
// Do not apply any transformation
return null;
}

private void dumpClass(byte[] classfileBuffer) {
TraceClassVisitor visitor = new TraceClassVisitor(new PrintWriter(System.out));
ClassReader reader = new ClassReader(classfileBuffer);
reader.accept(visitor, 0);
}
}

When running the sample main class, you get a console log like:

// class version 58.0 (58)
// access flags 0x11
public final class com/sun/proxy/$Proxy0 extends java/lang/reflect/Proxy implements java/io/Closeable {

// access flags 0xA
private static Ljava/lang/reflect/Method; m0

// access flags 0xA
private static Ljava/lang/reflect/Method; m1

// access flags 0xA
private static Ljava/lang/reflect/Method; m2

// access flags 0xA
private static Ljava/lang/reflect/Method; m3

// access flags 0x1
public <init>(Ljava/lang/reflect/InvocationHandler;)V
ALOAD 0
ALOAD 1
INVOKESPECIAL java/lang/reflect/Proxy.<init> (Ljava/lang/reflect/InvocationHandler;)V
RETURN
MAXSTACK = 2
MAXLOCALS = 2

(...)

Get bytecode from loaded class

note: the goal is to be able to load the bytecode using a custom classloader on a different JVM

A classloader doesn't just load bytecode. Therefore, if you were able to get the bytecode out of the JVM memory (which is theoretically possible if you write a lot of implementation-specific native code), it would be useless to your remote classloader. You need to give it an actual .class file.

And Class.getResource() is the best way to accomplish this task. Since it looks in the same package as the invoking class, all you need to do is take the class' simple name, append ".class" and you're done.

It does become a little more difficult if you have inner or nested classes, but that's an implementation detail that you'll have to deal with regardless (if you push the initial class, you'll still need to pull any dependent classes).

how to manually read the java bytecode for understanding purposes only?

Sometimes I find there is an assumption it has to be terribly complication when it is not. It is actually very simple.

I do not understand a single line of the bytecode. I want to understand some part of it if not all. or what some of these lines mean such as iconst_2?

iconst_2 stands for the integer constant 2

is bytecode and .class file same or .class files contains bytecode?.

The .class contains more than byte code. It also contains some constants e.g. String literals and large primitives. However, you can treat them as one and the same.

The picture below shows both .class and bytecode are same

The diagram is a simplified view. In simple terms they are the same thing.

If they are different, how is bytecode extracted from .class files by the JVM?

A .class has a specific format which if you follow that format you will find the byte code. As you can see there is more than just byte code in the file, but the byte code is the only bit you should care about. (Actually you shouldn't really care about the byte code in 99% of cases)

From the Class file format linked above.

A class file consists of a single ClassFile structure:

ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}

How to view Java's byte code in eclipse IDE?

Eclipse's default class file viewer shows the source (see VonC's answer) if it has been associated with the binaries, otherwise it gives a javap-like view of the class (with an option to attach source). I'm guessing it's the latter that you are looking for.

I've never found a way to cleanly force Eclipse to show that output rather than the linked source. What you probably want is an Eclipse plug-in that provides Javap like functionality (or an interface to javap). Look for plugins stating they "disassemble" (as opposed to "decompile," like jad).

Barring a plug-in, you could probably configure an external tool to perform javap but it might not play nicely with other eclipse features.

Edit: Let me be clear about the above: If you hit F3, Eclipse does the following (generally, the actual procedure might be slightly different):

  1. Resolves the target (if you are selecting a Java file, it will be the Java file itself; if you are selecting or your cursor is over a class name it will be the class declaration, similar for a method declaration, etc).
  2. Searches the build path (same project first) for a Java file containing the target. If found, opens up an writable editor displaying that Java source file.
  3. For class/method declarations, it continues searching references on your build path for a class file that contains the declaration. If it is found, then

    a) If the class file has had source attached to it, open up a read-only editor of the linked Java file.

    b) If the class file does not have source attached to it, then open up a read-only panel showing the disassembled (javap-like) bytecode of the compiled class file.

My guess would be that you're thinking there's a dedicated key sequence to 3.b), but I don't think there is. But again, I would love to be proven wrong here.

Is there a java classfile / bytecode editor to edit instructions?

I have not seen any byte code -> byte code frontends, but plenty backends.

I would suggest that you have a look at the many byte code manipulation libraries like javassist which allow loading byte code, manipulate it, and save it back to disk, and then write a small main that does exactly that.



Related Topics



Leave a reply



Submit