Class文件解析

1 准备工作

获取class文件byte[]

 public static byte[] getFileBytes(File file) {
 try (FileInputStream fileInputStream = new FileInputStream(file)) {
 int available = fileInputStream.available();
 byte[] data=new byte[available];
 fileInputStream.read(data,0,available-1);
 return data;
 } catch (Exception e) {
 e.printStackTrace();
 }
 return null;
 }

这里使用jdk的ByteBuffer包装bytes

ByteBuffer data = ByteBuffer.wrap(getFileBytes(file));

因为ByteBuffer没有无符号的读取方法,所以自己实现一下,也可以直接用netty的Bytebuf,里面方法齐全

 // 图方便直接返回int
 private int readUnsignedByte(ByteBuffer data) {
 return data.get() & 0xff;
 }
 // 图方便直接返回int
 private int readUnsignedShort(ByteBuffer data) {
 return data.getShort() & 0xffff;
 }
 
 private long readUnsignedInt(ByteBuffer data) {
 return data.getInt() & 0xffffffffL;
 }

定义class文件结构

参考: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html

 private static class ClassFileStructure {
 long magic;
 int minorVersion;
 int majorVersion;
 int constantPoolCount;
 ConstantPool[] constantPool;
 int accessFlags;
 int thisClass;
 int superClass;
 int interfacesCount;
 int[] interfaces;
 int fieldsCount;
 FieldInfo[] fields;
 int methodsCount;
 MethodInfo[] methods;
 int attributesCount;
 AttributeInfo[] attributes;
 }

2 开始解析

2.1 magic

 private void magic(ClassFileStructure structure, ByteBuffer data) {
 structure.magic = readUnsignedInt(data);
 }

2.2 minorVersion

 private void minorVersion(ClassFileStructure structure, ByteBuffer data) {
 structure.minorVersion = readUnsignedShort(data);
 }

2.3 majorVersion

 private void majorVersion(ClassFileStructure structure, ByteBuffer data) {
 structure.majorVersion = readUnsignedShort(data);
 }

2.4 constantPoolCount

 private void constantPoolCount(ClassFileStructure structure, ByteBuffer data) {
 structure.constantPoolCount = readUnsignedShort(data);
 }

2.5 ConstantPool[]

ConstantPool不同tag解析方式不同,定义抽象类ConstantPool,子类按规则解析

 private abstract static class ConstantPool {
 int tag;
 public ConstantPool(int tag) {
 this.tag = tag;
 }
 abstract void parse(ByteBuffer data);
}

子类实现ConstantPool
ConstantUtf8:

 private class ConstantUtf8 extends ConstantPool {
 int length;
 byte[] bytes;
 public ConstantUtf8(int tag) {
 super(tag);
 }
 @Override
 void parse(ByteBuffer data) {
 this.length = readUnsignedShort(data);
 bytes = new byte[this.length];
 for (int i = 0; i < this.length; i++) {
 bytes[i] = (byte) readUnsignedByte(data);
 }
 }
}

ConstantMethodHandle:

 private class ConstantMethodHandle extends ConstantPool {
 short referenceKind;
 int referenceIndex;
 public ConstantMethodHandle(int tag) {
 super(tag);
 }
 @Override
 void parse(ByteBuffer data) {
 this.referenceKind = (short) readUnsignedByte(data);
 this.referenceIndex = readUnsignedShort(data);
 }
}

ConstantMethodType:

 private class ConstantMethodType extends ConstantPool {
 int descriptorIndex;
 public ConstantMethodType(int tag) {
 super(tag);
 }
 @Override
 void parse(ByteBuffer data) {
 this.descriptorIndex = readUnsignedShort(data);
 }
}

ConstantClass:

private class ConstantClass extends ConstantPool {
 int nameIndex;
 public ConstantClass(int tag) {
 super(tag);
 }
 @Override
 void parse(ByteBuffer data) {
 this.nameIndex = readUnsignedShort(data);
 }
}

ConstantClass:

 private class ConstantClass extends ConstantPool {
 int nameIndex;
 public ConstantClass(int tag) {
 super(tag);
 }
 @Override
 void parse(ByteBuffer data) {
 this.nameIndex = readUnsignedShort(data);
 }
}

ConstantFieldref:


private class ConstantFieldref extends ConstantPool {
 int classIndex;
 int nameAndTypeIndex;
 public ConstantFieldref(int tag) {
 super(tag);
 }
 @Override
 void parse(ByteBuffer data) {
 this.classIndex = readUnsignedShort(data);
 this.nameAndTypeIndex = readUnsignedShort(data);
 }
}

ConstantMethodref:

private class ConstantMethodref extends ConstantPool {
 int classIndex;
 int nameAndTypeIndex;
 public ConstantMethodref(int tag) {
 super(tag);
 }
 @Override
 void parse(ByteBuffer data) {
 this.classIndex = readUnsignedShort(data);
 this.nameAndTypeIndex = readUnsignedShort(data);
 }
}

ConstantInterfaceMethodref:

 private class ConstantInterfaceMethodref extends ConstantPool {
 int classIndex;
 int nameAndTypeIndex;
 public ConstantInterfaceMethodref(int tag) {
 super(tag);
 }
 @Override
 void parse(ByteBuffer data) {
 this.classIndex = readUnsignedShort(data);
 this.nameAndTypeIndex = readUnsignedShort(data);
 }
}

ConstantString:

 private class ConstantString extends ConstantPool {
 int stringIndex;
 public ConstantString(int tag) {
 super(tag);
 }
 @Override
 void parse(ByteBuffer data) {
 this.stringIndex = readUnsignedShort(data);
 }
}

ConstantInteger:

private class ConstantInteger extends ConstantPool {
 long bytes;
 public ConstantInteger(int tag) {
 super(tag);
 }
 @Override
 void parse(ByteBuffer data) {
 this.bytes = readUnsignedInt(data);
 }
}

ConstantFloat:

private class ConstantFloat extends ConstantPool {
 long bytes;
 public ConstantFloat(int tag) {
 super(tag);
 }
 @Override
 void parse(ByteBuffer data) {
 this.bytes = readUnsignedInt(data);
 }
}

ConstantLong:

private class ConstantLong extends ConstantPool {
 long highBytes;
 long lowBytes;
 public ConstantLong(int tag) {
 super(tag);
 }
 @Override
 void parse(ByteBuffer data) {
 this.highBytes = readUnsignedInt(data);
 this.lowBytes = readUnsignedInt(data);
 }
}

ConstantDouble:

 private class ConstantDouble extends ConstantPool {
 long highBytes;
 long lowBytes;
 public ConstantDouble(int tag) {
 super(tag);
 }
 @Override
 void parse(ByteBuffer data) {
 this.highBytes = readUnsignedInt(data);
 this.lowBytes = readUnsignedInt(data);
 }
 }

ConstantNameAndType:

 private class ConstantNameAndType extends ConstantPool {
 int nameIndex;
 int descriptorIndex;
 public ConstantNameAndType(int tag) {
 super(tag);
 }
 @Override
 void parse(ByteBuffer data) {
 this.nameIndex = readUnsignedShort(data);
 this.descriptorIndex = readUnsignedShort(data);
 }
 }

ConstantInvokeDynamic:

 private class ConstantInvokeDynamic extends ConstantPool {
 int bootstrapMethodAttrIndex;
 int nameAndTypeIndex;
 public ConstantInvokeDynamic(int tag) {
 super(tag);
 }
 @Override
 void parse(ByteBuffer data) {
 this.bootstrapMethodAttrIndex = readUnsignedShort(data);
 this.nameAndTypeIndex = readUnsignedShort(data);
 }
 }

以上是所有 constantPool 子类型,现在开始解析

坑:“所有 8 字节常量都占用文件constant_pool表中的两个条目class。 如果
CONSTANT_Long_infoorCONSTANT_Double_info结构是constant_pool表中索引n处的项目,则池中的下一个可用项目位于索引n +2 处。
constant_pool 索引n +1 必须有效但被视为不可用 。 回想起来,让 8 字节常量占用两个常量池条目是一个糟糕的选择。”

 private void constantPool(ClassFileStructure structure, ByteBuffer data) {
 structure.constantPool = new ConstantPool[structure.constantPoolCount - 1];
 for (int i = 0; i < structure.constantPool.length; i++) {
 int type = readUnsignedByte(data);
 int index = i;
 switch (type) {
 case 1: //
 structure.constantPool[i] = new ConstantUtf8(type);
 break;
 case 3: //
 structure.constantPool[i] = new ConstantInteger(type);
 break;
 case 4:
 structure.constantPool[i] = new ConstantFloat(type);
 break;
 case 5:
 structure.constantPool[i] = new ConstantLong(type);
 i++;// 占2位
 break;
 case 6:
 structure.constantPool[i] = new ConstantDouble(type);
 i++;// 占2位
 break;
 case 7: //
 structure.constantPool[i] = new ConstantClass(type);
 break;
 case 8: //
 structure.constantPool[i] = new ConstantString(type);
 break;
 case 9: //
 structure.constantPool[i] = new ConstantFieldref(type);
 break;
 case 10: //
 structure.constantPool[i] = new ConstantMethodref(type);
 break;
 case 11: //
 structure.constantPool[i] = new ConstantInterfaceMethodref(type);
 break;
 case 12: //
 structure.constantPool[i] = new ConstantNameAndType(type);
 break;
 case 15: //
 structure.constantPool[i] = new ConstantMethodHandle(type);
 break;
 case 16: //
 structure.constantPool[i] = new ConstantMethodType(type);
 break;
 case 18: //
 structure.constantPool[i] = new ConstantInvokeDynamic(type);
 break;
 default:
 throw new ParserException("class file parser exception");
 }
 structure.constantPool[index].parse(data);
 }
 }

2.6 accessFlags

 private void accessFlags(ClassFileStructure structure, ByteBuffer data) {
 structure.accessFlags = readUnsignedShort(data);
 }

2.7 thisClass

 private void thisClass(ClassFileStructure structure, ByteBuffer data) {
 structure.thisClass = readUnsignedShort(data);
 }

2.8 superClass

 private void superClass(ClassFileStructure structure, ByteBuffer data) {
 structure.superClass = readUnsignedShort(data);
 }

2.9 interfacesCount

 private void interfacesCount(ClassFileStructure structure, ByteBuffer data) {
 structure.interfacesCount = readUnsignedShort(data);
 }

2.10 int[] interfaces

 private void interfaces(ClassFileStructure structure, ByteBuffer data) {
 structure.interfaces = new int[structure.interfacesCount];
 for (int i = 0; i < structure.interfacesCount; i++) {
 structure.interfaces[i] = readUnsignedShort(data);
 }
 }

2.11 fieldsCount

 private ClassFile fieldsCount(ClassFileStructure structure, ByteBuffer data) {
 structure.fieldsCount = readUnsignedShort(data);
 return this;
 }

2.12 FieldInfo[] fields

FieldInfo:

 private class FieldInfo {
 int accessFlags;
 int nameIndex;
 int descriptorIndex;
 int attributesCount;
 AttributeInfo[] attributes;
 public FieldInfo parse(ByteBuffer data) {
 this.accessFlags = readUnsignedShort(data);
 this.nameIndex = readUnsignedShort(data);
 this.descriptorIndex = readUnsignedShort(data);
 this.attributesCount = readUnsignedShort(data);
 this.attributes = new AttributeInfo[attributesCount];
 for (int i = 0; i < this.attributesCount; i++) {
 this.attributes[i] = new AttributeInfo().parse(data);
 }
 return this;
 }
 }

AttributeInfo:

 private class AttributeInfo {
 int attributeNameIndex;
 long attributeLength;
 short[] info;
 public AttributeInfo parse(ByteBuffer data) {
 this.attributeNameIndex = readUnsignedShort(data);
 this.attributeLength = readUnsignedInt(data);
 this.info = new short[(int) attributeLength];
 for (int i = 0; i < this.attributeLength; i++) {
 this.info[i] = (short) readUnsignedByte(data);
 }
 return this;
 }
 }
 private void fields(ClassFileStructure structure, ByteBuffer data) {
 structure.fields = new FieldInfo[structure.fieldsCount];
 for (int i = 0; i < structure.fieldsCount; i++) {
 structure.fields[i] = new FieldInfo().parse(data);
 }
 }

2.13 methodsCount

 private ClassFile methodsCount(ClassFileStructure structure, ByteBuffer data) {
 structure.methodsCount = readUnsignedShort(data);
 return this;
 }

2.14 MethodInfo[]
MethodInfo:

 private class MethodInfo {
 int accessFlags;
 int nameIndex;
 int descriptorIndex;
 int attributesCount;
 AttributeInfo[] attributes;
 public MethodInfo parse(ByteBuffer data) {
 this.accessFlags = readUnsignedShort(data);
 this.nameIndex = readUnsignedShort(data);
 this.descriptorIndex = readUnsignedShort(data);
 this.attributesCount = readUnsignedShort(data);
 this.attributes = new AttributeInfo[attributesCount];
 for (int i = 0; i < this.attributesCount; i++) {
 this.attributes[i] = new AttributeInfo().parse(data);
 }
 return this;
 }
 }
 private void methods(ClassFileStructure structure, ByteBuffer data) {
 structure.methods = new MethodInfo[structure.methodsCount];
 for (int i = 0; i < structure.methodsCount; i++) {
 structure.methods[i] = new MethodInfo().parse(data);
 }
 }

2.15 attributesCount

 private void attributesCount(ClassFileStructure structure, ByteBuffer data) {
 structure.attributesCount = readUnsignedShort(data);
 }

2.16 AttributeInfo[]

 private void attributes(ClassFileStructure structure, ByteBuffer data) {
 structure.attributes = new AttributeInfo[structure.attributesCount];
 for (int i = 0; i < structure.attributesCount; i++) {
 structure.attributes[i] = new AttributeInfo().parse(data);
 }
 }
作者:carry1899原文地址:https://www.cnblogs.com/carry1899/p/16936455.html

%s 个评论

要回复文章请先登录注册