Classfile
Java classfile formatter / decompiler / compiler using python object notation
Install / Use
/learn @joelhockey/ClassfileREADME
classfile.py
classfile.py is a java class file formatter / decompiler / compiler that transforms between binary java class files and a python object graph (dicts and arrays).
classfile can be used as a python module or run as a script.
usage:
classfile.py -d <classfile>
classfile.py -c <pyobjfile> <classfile>
Why
The JVM is a great piece of technology, but I prefer not to use the Java language. classfile.py makes it possible to view and manipulate class files in python.
More Info
Info about the java class file format at:
- http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html
- http://jcp.org/aboutJava/communityprocess/final/jsr202/index.html
Supported Features
Round tripping should work for any class file. There are some class file attributes that are not yet supported, but when these are encountered, the attributes are written in binary format and can be read back from binary format.
Example
Start with a Java source file or class file:
public class Example {
private static String foo = "world";
public static void main(String[] args) {
int times = 2;
for (int i = 0; i < times; i++) {
System.out.println("hello " + foo);
}
}
}
Compile and Run:
$ javac Example.java
$ java Example
hello world
hello world
Now use classfile to decompile:
$ ./classfile.py -d Example.class > Example.py
This will show the contents of the classfile as a python object:
{'01_magic': 'cafebabe',
'02_minor_version': 0,
'03_major_version': 50,
'04_constant_pool_count': 57,
'05_cp_info': [{'00_index': 0,
'00_tag_name': 'unusable at start to get numbering working',
'01_tag': 0},
{'00_index': 1,
'00_tag_name': 'CONSTANT_Class',
'01_tag': 7,
'02_name_index': 2},
{'00_index': 2,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 7,
'03_bytes': 'Example'},
{'00_index': 3,
'00_tag_name': 'CONSTANT_Class',
'01_tag': 7,
'02_name_index': 4},
{'00_index': 4,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 16,
'03_bytes': 'java/lang/Object'},
{'00_index': 5,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 3,
'03_bytes': 'foo'},
{'00_index': 6,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 18,
'03_bytes': 'Ljava/lang/String;'},
{'00_index': 7,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 8,
'03_bytes': '<clinit>'},
{'00_index': 8,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 3,
'03_bytes': '()V'},
{'00_index': 9,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 4,
'03_bytes': 'Code'},
{'00_index': 10,
'00_tag_name': 'CONSTANT_String',
'00_value': 'world',
'01_tag': 8,
'02_string_index': 11},
{'00_index': 11,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 5,
'03_bytes': 'world'},
{'00_index': 12,
'00_tag_name': 'CONSTANT_Fieldref',
'01_tag': 9,
'02_class_index': 1,
'03_name_and_type_index': 13},
{'00_index': 13,
'00_tag_name': 'CONSTANT_NameAndType',
'01_tag': 12,
'02_name_index': 5,
'03_descriptor_index': 6},
{'00_index': 14,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 15,
'03_bytes': 'LineNumberTable'},
{'00_index': 15,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 18,
'03_bytes': 'LocalVariableTable'},
{'00_index': 16,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 6,
'03_bytes': '<init>'},
{'00_index': 17,
'00_tag_name': 'CONSTANT_Methodref',
'01_tag': 10,
'02_class_index': 3,
'03_name_and_type_index': 18},
{'00_index': 18,
'00_tag_name': 'CONSTANT_NameAndType',
'01_tag': 12,
'02_name_index': 16,
'03_descriptor_index': 8},
{'00_index': 19,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 4,
'03_bytes': 'this'},
{'00_index': 20,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 9,
'03_bytes': 'LExample;'},
{'00_index': 21,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 4,
'03_bytes': 'main'},
{'00_index': 22,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 22,
'03_bytes': '([Ljava/lang/String;)V'},
{'00_index': 23,
'00_tag_name': 'CONSTANT_Fieldref',
'01_tag': 9,
'02_class_index': 24,
'03_name_and_type_index': 26},
{'00_index': 24,
'00_tag_name': 'CONSTANT_Class',
'01_tag': 7,
'02_name_index': 25},
{'00_index': 25,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 16,
'03_bytes': 'java/lang/System'},
{'00_index': 26,
'00_tag_name': 'CONSTANT_NameAndType',
'01_tag': 12,
'02_name_index': 27,
'03_descriptor_index': 28},
{'00_index': 27,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 3,
'03_bytes': 'out'},
{'00_index': 28,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 21,
'03_bytes': 'Ljava/io/PrintStream;'},
{'00_index': 29,
'00_tag_name': 'CONSTANT_Class',
'01_tag': 7,
'02_name_index': 30},
{'00_index': 30,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 23,
'03_bytes': 'java/lang/StringBuilder'},
{'00_index': 31,
'00_tag_name': 'CONSTANT_String',
'00_value': 'hello ',
'01_tag': 8,
'02_string_index': 32},
{'00_index': 32,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 6,
'03_bytes': 'hello '},
{'00_index': 33,
'00_tag_name': 'CONSTANT_Methodref',
'01_tag': 10,
'02_class_index': 29,
'03_name_and_type_index': 34},
{'00_index': 34,
'00_tag_name': 'CONSTANT_NameAndType',
'01_tag': 12,
'02_name_index': 16,
'03_descriptor_index': 35},
{'00_index': 35,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 21,
'03_bytes': '(Ljava/lang/String;)V'},
{'00_index': 36,
'00_tag_name': 'CONSTANT_Methodref',
'01_tag': 10,
'02_class_index': 29,
'03_name_and_type_index': 37},
{'00_index': 37,
'00_tag_name': 'CONSTANT_NameAndType',
'01_tag': 12,
'02_name_index': 38,
'03_descriptor_index': 39},
{'00_index': 38,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 6,
'03_bytes': 'append'},
{'00_index': 39,
'00_tag_name': 'CONSTANT_Utf8',
'01_tag': 1,
'02_length': 45,
'03_bytes': '(Ljava/l
