JVM 字节码的存储格式 docs.oracle.com/javase/spec…
/** * <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 + '}'; } } 复制代码