JVM 字節碼的存儲格式 docs.oracle.com/javase/spec…html
/** * <pre> * 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]; * } * </pre> */
public final class BytecodeParser {
/** * 按照字節碼的存儲格式依次解析每一個部分 */
public void parse(final byte[] bytes) {
MagicNumber magicNumber = new MagicNumber(0, bytes);
magicNumber.parse();
Version version = new Version(magicNumber.end(), bytes);
version.parse();
ConstantPool constantPool = new ConstantPool(version.end(), bytes);
constantPool.parse();
AccessFlags accessFlags = new AccessFlags(constantPool.end(), bytes);
accessFlags.parse();
ThisClass thisClass = new ThisClass(accessFlags.end(), bytes);
thisClass.parse();
SuperClass superClass = new SuperClass(thisClass.end(), bytes);
superClass.parse();
Interfaces interfaces = new Interfaces(superClass.end(), bytes);
interfaces.parse();
//TODO 字段表及以後的屬性解析待完善
Fields fields = new Fields(interfaces.end(), bytes);
fields.parse();
System.out.println(fields);
}
private static final String path = "xxx/BytecodeParser.class"; // 編譯以後的字節碼文件路徑
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream(new File(path));
int count = fis.available();
byte[] buff = new byte[count];
int read = fis.read(buff);
if (read != count) {
return;
}
new BytecodeParser().parse(buff);
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Utils {
/** * 獲取佔4字節的數 */
static int read4Number(byte[] bytes, int offset) {
return ((bytes[offset] & 0xFF) << 24) | ((bytes[offset + 1] & 0xFF) << 16) | ((bytes[offset + 2] & 0xFF) << 8) | ((bytes[offset + 3] & 0xFF));
}
/** * 獲取佔2字節的數, 爲了不 java 中只有 signed short 越界出現顯示了負數, 因此返回 int */
static int read2Number(byte[] bytes, int offset) {
return ((bytes[offset] & 0xFF) << 8) | (bytes[offset + 1] & 0xFF);
}
static int readUnsignedByte(byte[] bytes, int offset) {
return (bytes[offset] & 0xFF);
}
/** * 得到佔8字節的數 */
static long read8Number(byte[] bytes, int offset) {
return (
((long) bytes[offset] & 0xFF) << 56) |
(((long) bytes[offset + 1] & 0xFF) << 48) |
(((long) bytes[offset + 2] & 0xFF) << 40) |
(((long) bytes[offset + 3] & 0xFF) << 32) |
(((long) bytes[offset + 3] & 0xFF) << 24) |
(((long) bytes[offset + 3] & 0xFF) << 16) |
(((long) bytes[offset + 3] & 0xFF) << 8) |
(((long) bytes[offset + 3] & 0xFF));
}
}
abstract class Section {
final int start;
final byte[] bytes;
public Section(int start, byte[] bytes) {
this.start = start;
this.bytes = bytes;
}
public final int start() {
return start;
}
public final int end() {
return start + size();
}
abstract int size();
abstract public void parse();
}
class MagicNumber extends Section {
public MagicNumber(int start, byte[] bytes) {
super(start, bytes);
}
@Override
int size() {
return 4;
}
@Override
public void parse() {
System.out.println("MagicNumber: 0x"
+ Integer.toHexString(Utils.readUnsignedByte(bytes, start)).toUpperCase()
+ Integer.toHexString(Utils.readUnsignedByte(bytes, start + 1)).toUpperCase()
+ Integer.toHexString(Utils.readUnsignedByte(bytes, start + 2)).toUpperCase()
+ Integer.toHexString(Utils.readUnsignedByte(bytes, start + 3)).toUpperCase()
);
}
}
class Version extends Section {
public Version(int start, byte[] bytes) {
super(start, bytes);
}
@Override
int size() {
return 4;
}
@Override
public void parse() {
int minorVersion = Utils.read2Number(bytes, start);
int majorVersion = Utils.read2Number(bytes, start + 2);
System.out.println("Version: " + majorVersion + "." + minorVersion);
}
}
class ConstantPool extends Section {
private int poolSize = 2;
private ArrayList<ConstantItem> mConstantItems = new ArrayList<>();
public List<ConstantItem> getConstantItems() {
return mConstantItems;
}
public ConstantPool(int start, byte[] bytes) {
super(start, bytes);
}
@Override
int size() {
return poolSize;
}
@Override
public void parse() {
int poolCount = Utils.read2Number(bytes, start);
System.out.println("Constant Pool Count: " + poolCount);
// 遍歷常量表的每一項常量
int offset = 2;
for (short i = 1; i <= poolCount - 1; i++) {
int tag = Utils.readUnsignedByte(bytes, start + offset);
ConstantItem constantItem = null;
// 找到匹配的常量
for (ConstantItem item : ConstantItem.values()) {
if (item.tag == tag) {
constantItem = item;
break;
}
}
if (constantItem == null) {
System.err.println("Not found ConstantItem for " + tag);
return;
}
constantItem.parse(bytes, start + offset);
System.out.println("#" + i + " " + constantItem);
offset += constantItem.size();
poolSize += constantItem.size();
mConstantItems.add(constantItem);
}
}
/** * 常量項 * 每一個常量項都有 u1 的 tag, 表示其類型 */
enum ConstantItem {
UTF8(1) {
private int length;
private String value;
@Override
protected int contentSize() {
return length /* 字符串佔用的字節數 */ + 2 /* u2 的字符串長度 length*/;
}
@Override
void parse(byte[] bytes, int start) {
length = Utils.read2Number(bytes, start + 1);
value = new String(bytes, start + 3, length);
}
@Override
public String toString() {
return "Utf8{" +
"length=" + length +
", value='" + value + '\'' +
'}';
}
},
INTEGER(3) {
int value;
@Override
protected int contentSize() {
return 4 /*u4 值*/;
}
@Override
void parse(byte[] bytes, int start) {
value = Utils.read4Number(bytes, start + 1);
}
@Override
public String toString() {
return "Integer{" +
"value=" + value +
'}';
}
},
FLOAT(4) {
float value;
@Override
protected int contentSize() {
return 4 /* 同 INTEGER 的註釋 */;
}
@Override
void parse(byte[] bytes, int start) {
value = Utils.read4Number(bytes, start + 1);
}
@Override
public String toString() {
return "Float{" +
"value=" + value +
'}';
}
},
LONG(5) {
long value;
@Override
protected int contentSize() {
return 8 /* u8 值*/;
}
@Override
void parse(byte[] bytes, int start) {
value = Utils.read8Number(bytes, start);
}
@Override
public String toString() {
return "Long{" +
"value=" + value +
'}';
}
},
DOUBLE(6) {
double value;
@Override
protected int contentSize() {
return 8 /*u8 值*/;
}
@Override
void parse(byte[] bytes, int start) {
value = Utils.read8Number(bytes, start + 1);
}
@Override
public String toString() {
return "Double{" +
"value=" + value +
'}';
}
},
CLASS(7) {
int index;
@Override
protected int contentSize() {
return 2 /*u2 常量池索引*/;
}
@Override
void parse(byte[] bytes, int start) {
index = Utils.read2Number(bytes, start + 1);
}
@Override
public String toString() {
return "Class{" +
"index=" + index +
'}';
}
},
STRING(8) {
int index;
@Override
protected int contentSize() {
return 2/*u2 常量池索引*/;
}
@Override
void parse(byte[] bytes, int start) {
index = Utils.read2Number(bytes, start + 1);
}
@Override
public String toString() {
return "String{" +
"index=" + index +
'}';
}
},
FIELD_REF(9) {
int classInfoIndex,nameAndTypeIndex;
@Override
protected int contentSize() {
return 2/*u2 類信息常量池索引*/ + 2/*u2 名字和類型常量池索引*/;
}
@Override
void parse(byte[] bytes, int start) {
classInfoIndex = Utils.read2Number(bytes, start + 1);
nameAndTypeIndex = Utils.read2Number(bytes, start + 3);
}
@Override
public String toString() {
return "FileRef{" +
"classInfoIndex=" + classInfoIndex +
", nameAndTypeIndex=" + nameAndTypeIndex +
'}';
}
},
METHOD_REF(10) {
int classInfoIndex,nameAndTypeIndex;
@Override
protected int contentSize() {
return 4 /*同 FIELD_REF*/;
}
@Override
void parse(byte[] bytes, int start) {
classInfoIndex = Utils.read2Number(bytes, start + 1);
nameAndTypeIndex = Utils.read2Number(bytes, start + 3);
}
@Override
public String toString() {
return "MethodRef{" +
"classInfoIndex=" + classInfoIndex +
", nameAndTypeIndex=" + nameAndTypeIndex +
'}';
}
},
Interface_Method_Ref(11) {
int classInfoIndex,nameAndTypeIndex;
@Override
protected int contentSize() {
return 4/*同FIELD_REF*/;
}
@Override
void parse(byte[] bytes, int start) {
classInfoIndex = Utils.read2Number(bytes, start + 1);
nameAndTypeIndex = Utils.read2Number(bytes, start + 3);
}
@Override
public String toString() {
return "InterfaceMethodRef{" +
"classInfoIndex=" + classInfoIndex +
", nameAndTypeIndex=" + nameAndTypeIndex +
'}';
}
},
NAME_AND_TYPE(12) {
int nameIndex,descriptorIndex;
@Override
protected int contentSize() {
return 2/*u2 名稱在常量池的索引*/ + 2/*u2 描述符在常量池的索引*/;
}
@Override
void parse(byte[] bytes, int start) {
nameIndex = Utils.read2Number(bytes, start + 1);
descriptorIndex = Utils.read2Number(bytes, start + 3);
}
@Override
public String toString() {
return "NameAndType{" +
"nameIndex=" + nameIndex +
", descriptorIndex=" + descriptorIndex +
'}';
}
},
Method_Handle(15) {
int referenceKind; //unsigned byte
int referenceIndex;
@Override
protected int contentSize() {
return 1/**/ + 2/**/;
}
@Override
void parse(byte[] bytes, int start) {
referenceKind = Utils.readUnsignedByte(bytes, start + 1);
referenceIndex = Utils.read2Number(bytes, start + 2);
}
@Override
public String toString() {
return "MethodHandle{" +
"referenceKind=" + referenceKind +
", referenceIndex=" + referenceIndex +
'}';
}
},
Method_Type(16) {
int descriptorIndex;
@Override
protected int contentSize() {
return 2;
}
@Override
void parse(byte[] bytes, int start) {
descriptorIndex = Utils.read2Number(bytes, start + 1);
}
@Override
public String toString() {
return "MethodType{" +
"descriptorIndex=" + descriptorIndex +
'}';
}
},
Invoke_Dynamic(18) {
int bootstrapAttrIndex,nameAndTypeIndex;
@Override
protected int contentSize() {
return 4;
}
@Override
void parse(byte[] bytes, int start) {
bootstrapAttrIndex = Utils.read2Number(bytes, start + 1);
nameAndTypeIndex = Utils.read2Number(bytes, start + 3);
}
@Override
public String toString() {
return "InvokeDynamic{" +
"bootstrapAttrIndex=" + bootstrapAttrIndex +
", nameAndTypeIndex=" + nameAndTypeIndex +
'}';
}
};
public final int tag; // unsigned byte
ConstantItem(int tag) {
this.tag = tag;
}
public int size() {
return 1/*u1 的 tag*/ + contentSize() /* 不一樣常量佔用的字節數*/;
}
protected abstract int contentSize();
abstract void parse(byte[] bytes, int start);
}
}
class AccessFlags extends Section {
private static final int PUBLIC = 0x0001; // 0000 0000 0000 0001
private static final int FINAL = 0x0010; // 0000 0000 0001 0000
private static final int SUPER = 0x0020; // 0000 0000 0010 0000
private static final int INTERFACE = 0x0200; // 0000 0010 0000 0000
private static final int ABSTRACT = 0x0400; // 0000 0100 0000 0000
private static final int SYNTHETIC = 0x1000; // 0001 0000 0000 0000
private static final int ANNOTATION = 0x2000;// 0010 0000 0000 0000
private static final int ENUM = 0x4000; // 0100 0000 0000 0000
private int accessFlags;
public AccessFlags(int start, byte[] bytes) {
super(start, bytes);
}
@Override
int size() {
return 2;
}
@Override
public void parse() {
accessFlags = Utils.read2Number(bytes, start);
System.out.println("AccessFlags: " + printAccess(accessFlags));
}
private static String printAccess(int access) {
ArrayList<String> accessFlags = new ArrayList<>();
if ((access & PUBLIC) == PUBLIC) {
accessFlags.add("public");
}
if ((access & FINAL) == FINAL) {
accessFlags.add("final");
}
if ((access & SUPER) == SUPER) {
accessFlags.add("super");
}
if ((access & INTERFACE) == INTERFACE) {
accessFlags.add("interface");
}
if ((access & ABSTRACT) == ABSTRACT) {
accessFlags.add("abstract");
}
if ((access & SYNTHETIC) == SYNTHETIC) {
accessFlags.add("synthetic");
}
if ((access & ANNOTATION) == ANNOTATION) {
accessFlags.add("annotation");
}
if ((access & ENUM) == ENUM) {
accessFlags.add("enum");
}
StringBuilder sb = new StringBuilder();
accessFlags.forEach(s -> sb.append(s).append(","));
return sb.toString();
}
}
class ThisClass extends Section {
private int classInfoIndex;
public ThisClass(int start, byte[] bytes) {
super(start, bytes);
}
@Override
int size() {
return 2;
}
@Override
public void parse() {
classInfoIndex = Utils.read2Number(bytes, start);
System.out.println("This class: " + classInfoIndex);
}
}
class SuperClass extends Section {
private int classInfoIndex;
public SuperClass(int start, byte[] bytes) {
super(start, bytes);
}
@Override
int size() {
return 2;
}
@Override
public void parse() {
classInfoIndex = Utils.read2Number(bytes, start);
System.out.println("Super class: " + classInfoIndex);
}
}
class Interfaces extends Section {
private int contentSize = 0;
private ArrayList<Integer> indexs = new ArrayList<>();
public Interfaces(int start, byte[] bytes) {
super(start, bytes);
}
@Override
int size() {
return contentSize + 2;
}
@Override
public void parse() {
int interfaceCount = Utils.read2Number(bytes, start);
System.out.println("Interface count: " + interfaceCount);
int offset = 2;
for (short i = 0; i < interfaceCount; i++) {
int index = Utils.read2Number(bytes, start + offset);
indexs.add(index);
contentSize += 2;
}
System.out.println("Interface Indexes: " + indexs);
}
}
/** * <pre> * field_info { * u2 access_flags; * u2 name_index; * u2 descriptor_index; * u2 attributes_count; * attribute_info attributes[attributes_count]; * } * </pre> */
class Fields extends Section {
private int fieldsSize = 0;
int filedsCount;
int accessFlag;
int nameIndex;
int descriptorIndex;
int attributesCount;
private ArrayList<AttributeInfo> mAttributeInfos = new ArrayList<>();
public Fields(int start, byte[] bytes) {
super(start, bytes);
}
@Override
int size() {
return fieldsSize + 2;
}
@Override
public void parse() {
int offset = start;
filedsCount = Utils.read2Number(bytes, offset);
offset += 2;
accessFlag = Utils.read2Number(bytes, offset);
offset += 2;
nameIndex = Utils.read2Number(bytes, offset);
offset += 2;
descriptorIndex = Utils.read2Number(bytes, offset);
offset += 2;
attributesCount = Utils.read2Number(bytes, offset);
offset += 2;
for (int i = 0; i < attributesCount; i++) {
AttributeInfo attributeInfo = new AttributeInfo();
attributeInfo.parse(bytes, offset);
mAttributeInfos.add(attributeInfo);
offset += attributeInfo.size();
}
}
@Override
public String toString() {
return "Fields{" +
"fieldsSize=" + fieldsSize +
", filedsCount=" + filedsCount +
", accessFlag=" + accessFlag +
", nameIndex=" + nameIndex +
", descriptorIndex=" + descriptorIndex +
", attributesCount=" + attributesCount +
", mAttributeInfos=" + mAttributeInfos +
'}';
}
}
/** * <pre> * attribute_info { * u2 attribute_name_index; * u4 attribute_length; * u1 info[attribute_length]; * } * </pre> */
class AttributeInfo {
int nameIndex; //u2
int length; //u4
ArrayList<Info> mInfos = new ArrayList<>();
public void parse(byte[] bytes, int offset) {
nameIndex = Utils.read2Number(bytes, offset);
length = Utils.read4Number(bytes, offset + 2);
for (int i = 0; i < length; i++) {
}
}
public int size() {
return 2 + 4;
}
enum Info {
Code("Code") {
@Override
public void parse(byte[] bytes, int offset) {
}
@Override
public int size() {
return 0;
}
},
ConstantValue("ConstantValue") {
int nameIndex; //u2
int attributeLength; //u4
int constantValueIndex; //u2
@Override
public void parse(byte[] bytes, int offset) {
nameIndex = Utils.read2Number(bytes, offset);
attributeLength = Utils.read4Number(bytes, offset + 2);
constantValueIndex = Utils.read2Number(bytes, offset + 2);
}
@Override
public int size() {
return 2 + 4 + 2;
}
@Override
public String toString() {
return "ConstantValue{" +
"nameIndex=" + nameIndex +
", attributeLength=" + attributeLength +
", constantValueIndex=" + constantValueIndex +
'}';
}
};
private final String name;
Info(String name) {
this.name = name;
}
abstract public void parse(byte[] bytes, int offset);
abstract public int size();
}
@Override
public String toString() {
return "AttributeInfo{" +
"nameIndex=" + nameIndex +
", length=" + length +
'}';
}
}
複製代碼