Skip to content

Latest commit

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

使用 Java 解析字节码文件结构

按照JVM 字节码的存储格式 https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html 规范,实现了一段程序解析字节码结构。

运行:

./run.sh

因为字节码指令太多了,所以还没有实现解析每一个字节码指令(Code属性里面的内容)。Instruction.java 实现了一个字节码指令(ldc)的解析,其他指令类似。

结果输出

========== Start Parse out/site/jiyang/Main.class =========
== Magic Number ======================================
MagicNumber{b1=CA, b2=FE, b3=BA, b4=BE}
== Version ======================================
Version{minorVersion=0, majorVersion=52}
== Constant Pool ======================================
ConstantPool{poolCount=214, constantsSize=2376, mConstantItems=
#1 MethodRef{classInfoIndex=65, nameAndTypeIndex=130}
#2 String{index=131}
...
#213 Utf8{attributeLength=20, value='()Ljava/lang/String;'}
}
== Access Flags ======================================
AccessFlags: public,final,super,
bytecode.AccessFlags@27bc2616
== This class ======================================
ClassIndex{classInfoIndex=49 -> 171 -> bytecode/BytecodeParser}
== Super class ======================================
ClassIndex{classInfoIndex=65 -> 185 -> java/lang/Object}
== Interfaces ======================================
Interface count: 0
Interface Indexes: []
== Fields ======================================
FieldOrMethod{count=2, name='Fields', mEntities=[Entity{accessFlag=[Public,Static,], nameIndex=66, name=constantItemHashMap, descriptorIndex=67, attributesCount=1, mAttributeInfos=[AttributeInfo{nameIndex=68, attributeLength=2, mInfo=Signature{signatureIndex=69 -> Ljava/util/HashMap<Ljava/lang/Integer;Lbytecode/ConstantItem;>;}}]}, Entity{accessFlag=[Private,Static,Final,], nameIndex=70, name=path, descriptorIndex=71, attributesCount=1, mAttributeInfos=[AttributeInfo{nameIndex=72, attributeLength=2, mInfo=ConstantValue{constantValueIndex=4}}]}]}
== Methods ======================================
FieldOrMethod{count=4, name='Methods', mEntities=[Entity{accessFlag=[Public,], nameIndex=73,...
== This class attribute_info ======================================
[AttributeInfo{nameIndex=128, attributeLength=2, mInfo=SourceFile{sourceFileIndex=129 -> BytecodeParser.java}}]

实现

整体流程

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];
}

按照字节码的储存顺序依次解析每一块内容。所有解析过程都共用一个 byte[] 数组,每个具体的解析过程,通过控制 offset 实现解析不同部分的数据。

publicfinalclassBytecodeParser {
// 用来在常量池解析完之后,存在全局方便后面使用publicstaticHashMap<Integer, ConstantItem> constantItemHashMap;
privatevoidparse(finalbyte[] bytes) {
printSectionDivider("Magic Number");
SectionmagicNumber = newMagicNumber(0, bytes);
magicNumber.parse();
System.out.println(magicNumber);
printSectionDivider("Version");
Sectionversion = newVersion(magicNumber.end(), bytes);
version.parse();
System.out.println(version);
printSectionDivider("Constant Pool");
ConstantPoolconstantPool = newConstantPool(version.end(), bytes);
constantPool.parse();
System.out.println(constantPool);
constantItemHashMap = constantPool.getConstantItems();
printSectionDivider("Access Flags");
SectionaccessFlags = newAccessFlags(constantPool.end(), bytes);
accessFlags.parse();
System.out.println(accessFlags);
printSectionDivider("This class");
SectionthisClass = newClassIndex(accessFlags.end(), bytes);
thisClass.parse();
System.out.println(thisClass);
printSectionDivider("Super class");
SectionsuperClass = newClassIndex(thisClass.end(), bytes);
superClass.parse();
System.out.println(superClass);
printSectionDivider("Interfaces");
Interfacesinterfaces = newInterfaces(superClass.end(), bytes);
interfaces.parse();
System.out.println(interfaces);
printSectionDivider("Fields");
FieldOrMethodfields = newFieldOrMethod("Fields", interfaces.end(), bytes);
fields.parse();
System.out.println(fields);
printSectionDivider("Methods");
FieldOrMethodmethods = newFieldOrMethod("Methods", fields.end(), bytes);
methods.parse();
System.out.println(methods);
printSectionDivider("This class attribute_info");
intoffset = methods.end();
intattributeCount = Utils.read2Number(bytes, offset);
offset += 2;
AttributeInfo[] attributeInfos = newAttributeInfo[attributeCount];
for (inti = 0; i < attributeCount; i++) {
attributeInfos[i] = newAttributeInfo();
attributeInfos[i].parse(bytes, offset);
offset += attributeInfos[i].size();
}
System.out.println(Arrays.toString(attributeInfos));
}
}
publicstaticvoidmain(String[] args) {
if (args.length < 1) {
thrownewIllegalArgumentException("Must pass class file path.");
}
Stringpath = args[0];
System.out.println("========== Start Parse=========");
try {
FileInputStreamfis = newFileInputStream(newFile(path));
intcount = fis.available();
byte[] buff = newbyte[count];
intread = fis.read(buff);
if (read != count) {
return;
}
newBytecodeParser().parse(buff);
} catch (IOExceptione) {
e.printStackTrace();
}
}
privatestaticvoidprintSectionDivider(Stringname) {
System.out.println("== " + name + " ======================================");
}

提取了一些抽象

方便后面实现时生成统一的方法

interfaceParsable {
publicvoidparse(byte[] bytes, intoffset);
}
abstractclassSection {
finalintstart; //记录每一块结构的开始位置finalbyte[] bytes; // 所有人共用的数据publicSection(intstart, byte[] bytes) {
this.start = start;
this.bytes = bytes;
}
publicfinalintstart() {
returnstart;
}
publicfinalintend() {
returnstart + size();
}
abstractintsize(); //每一块结构需要返回自己占用了多少字节abstractpublicvoidparse();
}

解析魔数

classMagicNumberextendsSection {
publicMagicNumber(intstart, byte[] bytes) {
super(start, bytes);
}
@Overrideintsize() {
return4;
}
privateintb1, b2, b3, b4;//u1@Overridepublicvoidparse() {
b1 = Utils.readUnsignedByte(bytes, start);
b2 = Utils.readUnsignedByte(bytes, start + 1);
b3 = Utils.readUnsignedByte(bytes, start + 2);
b4 = Utils.readUnsignedByte(bytes, start + 3);
}
@OverridepublicStringtoString() {
return"MagicNumber{" +
"b1=" + Integer.toHexString(b1).toUpperCase() +
", b2=" + Integer.toHexString(b2).toUpperCase() +
", b3=" + Integer.toHexString(b3).toUpperCase() +
", b4=" + Integer.toHexString(b4).toUpperCase() +
'}';
}
}

解析版本号

classVersionextendsSection {
publicVersion(intstart, byte[] bytes) {
super(start, bytes);
}
@Overrideintsize() {
return4;
}
privateintminorVersion, majorVersion; //u2@Overridepublicvoidparse() {
minorVersion = Utils.read2Number(bytes, start);
majorVersion = Utils.read2Number(bytes, start + 2);
}
@OverridepublicStringtoString() {
return"Version{" +
"minorVersion=" + minorVersion +
", majorVersion=" + majorVersion +
'}';
}
}

解析常量池

常量池这里有一点要注意:代表常量池有多少常量的 poolCount,是包括了 poolCount 它本身的。也就是真正的常量池的常量其实是 poolCount -1 个。

每个常量项都有一个 u1 的 tag 表示其类型。解析时需要先解析 tag, 然后根据 tag 做对应类型的解析。

classConstantPoolextendsSection {
intpoolCount; //u2privateintconstantsSize;
privateHashMap<Integer, ConstantItem> mConstantItems = newHashMap<>();
publicHashMap<Integer, ConstantItem> getConstantItems() {
returnmConstantItems;
}
publicConstantPool(intstart, byte[] bytes) {
super(start, bytes);
}
@Overrideintsize() {
return2/*u2 的常量池计数占用*/ + constantsSize;
}
@Overridepublicvoidparse() {
poolCount = Utils.read2Number(bytes, start);
// 遍历常量表的每一项常量intoffset = 2;
for (inti = 1; i <= poolCount - 1; i++) {
inttag = Utils.readUnsignedByte(bytes, start + offset);
// 根据 tag 找到匹配的常量ConstantItemitem = ConstantItem.getConstantItemTags(tag);
if (item == null) {
System.err.println("Not found ConstantItem for " + tag);
return;
}
item.parse(bytes, start + offset);
offset += item.size();
constantsSize += item.size();
mConstantItems.put(i, item);
}
}
@OverridepublicStringtoString() {
StringBuildersb = newStringBuilder();
for (inti = 1; i <= poolCount - 1; i++) {
sb.append(" #").append(i).append(" ").append(mConstantItems.get(i)).append("\n");
}
return"ConstantPool{" +
"poolCount=" + poolCount +
", constantsSize=" + constantsSize +
", mConstantItems=\n" + sb.toString() +
'}';
}
}

每个常量项

/** * 常量项 * 每个常量项都有 u1 的 tag, 表示其类型 * <pre> * cp_info { * u1 tag; * u1 info[]; * } * </pre> */abstractclassConstantItemimplementsParsable {
finalinttag;
ConstantItem(inttag) {
this.tag = tag;
}
abstractprotectedintcontentSize();
intsize() {
return1/*u1的tag*/ + contentSize();
}
@NullablestaticConstantItemgetConstantItemTags(inttag) {
switch (tag) {
case1:
returnnewUTF8();
case3:
returnnewINTEGER();
case4:
returnnewFLOAT();
case5:
returnnewLONG();
case6:
returnnewDOUBLE();
case7:
returnnewCLASS();
case8:
returnnewSTRING();
case9:
returnnewFIELD_REF();
case10:
returnnewMETHOD_REF();
case11:
returnnewInterface_Method_Ref();
case12:
returnnewNAME_AND_TYPE();
case15:
returnnewMethod_Handle();
case16:
returnnewMethod_Type();
case18:
returnnewInvoke_Dynamic();
default:
returnnull;
}
}
}

CONSTANT_Utf8

所有的字面量都储存在 UTF8 常量中。value 存储着以 UTF-8 编码的字符串的原始字节数据。

//region ConstantsclassUTF8extendsConstantItem {
privateintlength;
publicStringvalue;
UTF8() {
super(1);
}
@OverrideprotectedintcontentSize() {
returnlength/* 字符串占用的字节数 */ + 2/* u2 的字符串长度 attributeLength*/;
}
@Overridepublicvoidparse(byte[] bytes, intstart) {
length = Utils.read2Number(bytes, start + 1);
value = newString(bytes, start + 3, length);
}
@OverridepublicStringtoString() {
return"Utf8{" +
"attributeLength=" + length +
", value='" + value + '\'' +
'}';
}
}

CONSTANT_Integer

classINTEGERextendsConstantItem {
intvalue;
protectedINTEGER() {
super(3);
}
@OverrideprotectedintcontentSize() {
return4/*u4 值*/;
}
@Overridepublicvoidparse(byte[] bytes, intstart) {
value = Utils.read4Number(bytes, start + 1);
}
@OverridepublicStringtoString() {
return"Integer{" +
"value=" + value +
'}';
}
}

CONSTANT_Float

classFLOATextendsConstantItem {
floatvalue;
FLOAT() {
super(4);
}
@OverrideprotectedintcontentSize() {
return4/* 同 INTEGER 的注释 */;
}
@Overridepublicvoidparse(byte[] bytes, intstart) {
value = Utils.read4Number(bytes, start + 1);
}
@OverridepublicStringtoString() {
return"Float{" +
"value=" + value +
'}';
}
}

CONSTANT_Long

classLONGextendsConstantItem {
longvalue;
LONG() {
super(5);
}
@OverrideprotectedintcontentSize() {
return8/* u8 值*/;
}
@Overridepublicvoidparse(byte[] bytes, intstart) {
value = Utils.read8Number(bytes, start + 1);
}
@OverridepublicStringtoString() {
return"Long{" +
"value=" + value +
'}';
}
}

CONSTANT_Double

classDOUBLEextendsConstantItem {
DOUBLE() {
super(6);
}
doublevalue;
@OverrideprotectedintcontentSize() {
return8/*u8 值*/;
}
@Overridepublicvoidparse(byte[] bytes, intstart) {
value = Utils.read8Number(bytes, start + 1);
}
@OverridepublicStringtoString() {
return"Double{" +
"value=" + value +
'}';
}
}

CONSTANT_Class

存储指向类的全限定名在常量池中的索引 index

class CLASS extends ConstantItem {
CLASS() {
super(7);
}
int index;
@Override
protected int contentSize() {
return 2 /*u2 常量池索引*/;
}
@Override
public void parse(byte[] bytes, int start) {
index = Utils.read2Number(bytes, start + 1);
}
@Override
public String toString() {
return "Class{" +
"index=" + index +
'}';
}
}

CONSTANT_String

存储指向 Constant_UTF8 的索引 index

classSTRINGextendsConstantItem {
STRING() {
super(8);
}
intindex; //u2@OverrideprotectedintcontentSize() {
return2/*u2 常量池索引*/;
}
@Overridepublicvoidparse(byte[] bytes, intstart) {
index = Utils.read2Number(bytes, start + 1);
}
@OverridepublicStringtoString() {
return"String{" +
"index=" + index +
'}';
}
}

CONSTANT_Fieldref

  • classInfoIndex 声明字段的类的信息,指向 CONSTANT_Class
  • nameAndTypeIndex 字段的信息,指向 CONSTANT_NameAndType 类型的索引
class FIELD_REF extends ConstantItem {
int classInfoIndex, nameAndTypeIndex;
FIELD_REF() {
super(9);
}
@Override
protected int contentSize() {
return 2/*u2 类信息常量池索引*/ + 2/*u2 名字和类型常量池索引*/;
}
@Override
public 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 +
'}';
}
}

CONSTANT_Methodref

  • classInfoIndex 声明方法的类的信息,指向 CONSTANT_Class
  • nameAndTypeIndex 方法的信息,指向 CONSTANT_NameAndType 类型的索引
class METHOD_REF extends ConstantItem {
int classInfoIndex, nameAndTypeIndex;
METHOD_REF() {
super(10);
}
@Override
protected int contentSize() {
return 4 /*同 FIELD_REF*/;
}
@Override
public 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 +
'}';
}
}

CONSTANT_InterfaceMethodref

  • classInfoIndex 声明接口的类的信息,指向 CONSTANT_Class
  • nameAndTypeIndex 接口的信息,指向 CONSTANT_NameAndType 类型的索引
class Interface_Method_Ref extends ConstantItem {
int classInfoIndex, nameAndTypeIndex;
Interface_Method_Ref() {
super(11);
}
@Override
protected int contentSize() {
return 4/*同FIELD_REF*/;
}
@Override
public 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 +
'}';
}
}

CONSTANT_NameAndType

  • nameIndex 指向方法或字段的名称在常量池中的索引
  • descriptorIndex 指向方法或字段的描述符在常量池中的索引
class NAME_AND_TYPE extends ConstantItem {
int nameIndex, descriptorIndex; //u2
NAME_AND_TYPE() {
super(12);
}
@Override
protected int contentSize() {
return 2/*u2 名称在常量池的索引*/ + 2/*u2 描述符在常量池的索引*/;
}
@Override
public 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 +
'}';
}
}

CONSTANT_MethodHandle

详细信息参考 https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.8

  • referenceKind 方法句柄的类型,代表字节码被执行时的行为. ? 不太懂这个... 还没有遇到出现的情况
  • referenceIndex
classMethod_HandleextendsConstantItem {
intreferenceKind; //u1intreferenceIndex; //u2Method_Handle() {
super(15);
}
@OverrideprotectedintcontentSize() {
return1/**/ + 2/**/;
}
@Overridepublicvoidparse(byte[] bytes, intstart) {
referenceKind = Utils.readUnsignedByte(bytes, start + 1);
referenceIndex = Utils.read2Number(bytes, start + 2);
}
@OverridepublicStringtoString() {
return"MethodHandle{" +
"referenceKind=" + referenceKind +
", referenceIndex=" + referenceIndex +
'}';
}
}

CONSTANT_MethodType

  • descriptorIndex 指向常量池中 UTF8 类型的索引,表示方法的描述符
classMethod_TypeextendsConstantItem {
intdescriptorIndex; //u2Method_Type() {
super(16);
}
@OverrideprotectedintcontentSize() {
return2;
}
@Overridepublicvoidparse(byte[] bytes, intstart) {
descriptorIndex = Utils.read2Number(bytes, start + 1);
}
@OverridepublicStringtoString() {
return"MethodType{" +
"descriptorIndex=" + descriptorIndex +
'}';
}
}

CONSTANT_InvokeDynamic

https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.10

与 Java 的动态方法调用有关。

class Invoke_Dynamic extends ConstantItem {
int bootstrapAttrIndex, nameAndTypeIndex;
Invoke_Dynamic() {
super(18);
}
@Override
protected int contentSize() {
return 4;
}
@Override
public 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 +
'}';
}
}
//endregion

解析访问标志

一个字段或方法或类的访问标志都是使用一个 u2 类型的数字表示,通过位运算 | 赋予,通过 &运算判断是否拥有某种访问标志。

classAccessFlagsextendsSection {
privatestaticfinalintPUBLIC = 0x0001; // 0000 0000 0000 0001privatestaticfinalintFINAL = 0x0010; // 0000 0000 0001 0000privatestaticfinalintSUPER = 0x0020; // 0000 0000 0010 0000privatestaticfinalintINTERFACE = 0x0200; // 0000 0010 0000 0000privatestaticfinalintABSTRACT = 0x0400; // 0000 0100 0000 0000privatestaticfinalintSYNTHETIC = 0x1000; // 0001 0000 0000 0000privatestaticfinalintANNOTATION = 0x2000;// 0010 0000 0000 0000privatestaticfinalintENUM = 0x4000; // 0100 0000 0000 0000privatestaticfinalintPRIVATE = 0x0002;
privateintaccessFlags; //u2publicAccessFlags(intstart, byte[] bytes) {
super(start, bytes);
}
@Overrideintsize() {
return2;
}
@Overridepublicvoidparse() {
accessFlags = Utils.read2Number(bytes, start);
System.out.println("AccessFlags: " + printAccess(accessFlags));
}
publicstaticStringprintAccess(intaccess) {
ArrayList<String> accessFlags = newArrayList<>();
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");
}
if ((access & PRIVATE) == PRIVATE) {
accessFlags.add("private");
}
StringBuildersb = newStringBuilder();
accessFlags.forEach(s -> sb.append(s).append(","));
returnsb.toString();
}
}

解析类信息

类自身和其父类都存储在 class_info 结构中,classInfoIndex 指向常量池中 Constant_Class 类型的常量

/** * 类索引 * 用于解析自身类和父类在常量池的索引 */classClassIndexextendsSection {
privateintclassInfoIndex;
publicClassIndex(intstart, byte[] bytes) {
super(start, bytes);
}
@Overrideintsize() {
return2;
}
@Overridepublicvoidparse() {
classInfoIndex = Utils.read2Number(bytes, start);
}
@OverridepublicStringtoString() {
CLASSclasz = (CLASS) BytecodeParser.constantItemHashMap.get(classInfoIndex);
UTF8utf8 = (UTF8) BytecodeParser.constantItemHashMap.get(clasz.index);
return"ClassIndex{" +
"classInfoIndex=" + classInfoIndex +
" -> " + clasz.index + " -> " + utf8.value +
'}';
}
}

解析接口

类实现的所有接口在常量池的 Constant_class 类型索引

classInterfacesextendsSection {
intinterfaceCount; //u2int[] indexs; // u2[interfaceCount]publicInterfaces(intstart, byte[] bytes) {
super(start, bytes);
}
@Overrideintsize() {
returninterfaceCount * 2 + 2;
}
@Overridepublicvoidparse() {
interfaceCount = Utils.read2Number(bytes, start);
intoffset = 2;
indexs = newint[interfaceCount];
for (shorti = 0; i < interfaceCount; i++) {
intindex = Utils.read2Number(bytes, start + offset);
indexs[i] = index;
}
}
@OverridepublicStringtoString() {
return"Interfaces{" +
"interfaceCount=" + interfaceCount +
", indexs=" + Arrays.toString(indexs) +
'}';
}
}

解析方法和字段

/** * <pre> * field_info { * u2 access_flags; * u2 name_index; * u2 descriptor_index; * u2 attributes_count; * attribute_info attributes[attributes_count]; * } * </pre> */classFieldOrMethodextendsSection {
privateintinfoSize = 0;
intcount; //u2staticclassEntity {
intaccessFlag; //u2intnameIndex; //u2intdescriptorIndex; //u2intattributesCount; //u2privateArrayList<AttributeInfo> mAttributeInfos = newArrayList<>();
publicintsize() {
intinfoSize = 0;
for (AttributeInfoinfo : mAttributeInfos) {
infoSize += info.size();
}
return8 + infoSize;
}
publicvoidparse(byte[] bytes, intoffset) {
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 (inti = 0; i < attributesCount; i++) {
AttributeInfoattributeInfo = newAttributeInfo();
attributeInfo.parse(bytes, offset);
mAttributeInfos.add(attributeInfo);
offset += attributeInfo.size();
}
}
staticfinalintPUBLIC = 0x0001;
staticfinalintPRIVATE = 0x0002;
staticfinalintPROTECTED = 0x0004;
staticfinalintSTATIC = 0x0008;
staticfinalintFINAL = 0x0010;
// field specialstaticfinalintVOLATILE = 0x0040;
staticfinalintTRANSIENT = 0x0080;
staticfinalintSYNTHETIC = 0x1000;
staticfinalintENUM = 0x4000;
// method specialstaticfinalintSYNCHRONIZED = 0x0020;
staticfinalintBRIDGE = 0x0040;
staticfinalintVARARGS = 0x0080;
staticfinalintNATIVE = 0x0100;
staticfinalintABSTRACT = 0x0400;
staticfinalintSTRICTFP = 0x0500;
privatestaticStringaccessFlagReadable(intaccess) {
StringBuildersb = newStringBuilder();
sb.append("[");
if ((access & PUBLIC) == PUBLIC) sb.append("Public,");
if ((access & PRIVATE) == PRIVATE) sb.append("Private,");
if ((access & PROTECTED) == PROTECTED) sb.append("Protected,");
if ((access & STATIC) == STATIC) sb.append("Static,");
if ((access & FINAL) == FINAL) sb.append("Final,");
if ((access & VOLATILE) == VOLATILE) sb.append("Volatile,");
if ((access & TRANSIENT) == TRANSIENT) sb.append("Transient,");
if ((access & SYNTHETIC) == SYNTHETIC) sb.append("Synthetic,");
if ((access & ENUM) == ENUM) sb.append("Enum,");
if ((access & SYNCHRONIZED) == SYNCHRONIZED) sb.append(", Synchronized");
if ((access & BRIDGE) == BRIDGE) sb.append(",Bridge");
if ((access & VARARGS) == VARARGS) sb.append(",Varargs");
if ((access & NATIVE) == NATIVE) sb.append(",Native");
if ((access & ABSTRACT) == ABSTRACT) sb.append(",Abstract");
if ((access & STRICTFP) == STRICTFP) sb.append(",Strictfp");
sb.append("]");
returnsb.toString();
}
@OverridepublicStringtoString() {
return"Entity{" +
"accessFlag=" + accessFlagReadable(accessFlag) +
", nameIndex=" + nameIndex +
", name=" + ((UTF8) BytecodeParser.constantItemHashMap.get(nameIndex)).value +
", descriptorIndex=" + descriptorIndex +
", attributesCount=" + attributesCount +
", mAttributeInfos=" + mAttributeInfos +
'}';
}
}
privatefinalStringname;
privatefinalArrayList<Entity> mEntities = newArrayList<>();
publicFieldOrMethod(Stringname, intstart, byte[] bytes) {
super(start, bytes);
this.name = name;
}
@Overrideintsize() {
returninfoSize + 2;
}
@Overridepublicvoidparse() {
intoffset = start;
count = Utils.read2Number(bytes, offset);
offset += 2;
for (inti = 0; i < count; i++) {
Entityentity = newEntity();
entity.parse(bytes, offset);
mEntities.add(entity);
infoSize += entity.size();
offset += entity.size();
}
}
@OverridepublicStringtoString() {
return"FieldOrMethod{" +
"count=" + count +
", name='" + name + '\'' +
", mEntities=" + mEntities +
'}';
}
}

解析属性表

字段、方法、类都能拥有自己的属性表。只是某些属性只会出现在字段上(比如 volatile)或方法上(比如 synchronized)。

u2 attribute_name_index;
u4 attribute_length;

attribute_name_indexattribute_length 是每个属性都有的两个字段,所以提出来由父类实现解析。

/**
* <pre>
* attribute_info {
* u2 attribute_name_index;
* u4 attribute_length;
* u1 info[attribute_length];
* }
* </pre>
*/
class AttributeInfo implements Parsable {
private int nameIndex; //u2
private int attributeLength; //u4
private Info mInfo;
@Override
public void parse(byte[] bytes, int offset) {
nameIndex = Utils.read2Number(bytes, offset);
offset += 2;
attributeLength = Utils.read4Number(bytes, offset);
offset += 4;
// 根据属性名称找到匹配的属性
ConstantItem constantItem = BytecodeParser.constantItemHashMap.get(nameIndex);
UTF8 utf8 = (UTF8) constantItem;
String infoName = utf8.value;
mInfo = Info.getMatchInfo(infoName);
if (mInfo == null) {
System.err.println("Not found matching Attributes: " + infoName);
return;
}
mInfo.parse(bytes, offset);
}
public int size() {
return 2 + 4 + attributeLength;
}
@Override
public String toString() {
return "AttributeInfo{" +
"nameIndex=" + nameIndex +
", attributeLength=" + attributeLength +
", mInfo=" + mInfo +
'}';
}
}
abstract class Info implements Parsable {
public int size() {
return contentSize();
}
abstract protected int contentSize();
abstract public void parseInner(byte[] bytes, int offset);
@Override
public void parse(byte[] bytes, int offset) {
parseInner(bytes, offset);
}
@Nullable
public static Info getMatchInfo(String name) {
switch (name) {
case "Code":
return new CodeInfo();
case "ConstantValue":
return new ConstantValue();
case "Exceptions":
return new Exceptions();
case "LineNumberTable":
return new LineNumberTable();
case "LocalVariableTable":
return new LocalVariableTable();
case "LocalVariableTypeTable":
return new LocalVariableTypeTable();
case "SourceFile":
return new SourceFile();
case "InnerClasses":
return new InnerClasses();
case "Deprecated":
return new Deprecated();
case "Synthetic":
return new Synthetic();
case "StackMapTable":
// TODO StackMapTable 待实现
return null;
case "Signature":
return new Signature();
default:
return null;
}
}
}

Code 属性

//region Info/** * <pre> * Code_attribute { * u2 attribute_name_index; * u4 attribute_length; * u2 max_stack; * u2 max_locals; * u4 code_length; * u1 code[code_length]; * u2 exception_table_length; * { u2 start_pc; * u2 end_pc; * u2 handler_pc; * u2 catch_type; * } exception_table[exception_table_length]; * u2 attributes_count; * attribute_info attributes[attributes_count]; * } * </pre> */classCodeInfoextendsInfo {
classExceptionTableimplementsParsable {
intstartPc; //u2intendPc; //u2inthandlePc; // u2intcatchType; //u2publicintsize() {
return2 + 2 + 2 + 2;
}
@Overridepublicvoidparse(byte[] bytes, intoffset) {
startPc = Utils.read2Number(bytes, offset);
offset += 2;
endPc = Utils.read2Number(bytes, offset);
offset += 2;
handlePc = Utils.read2Number(bytes, offset);
offset += 2;
catchType = Utils.read2Number(bytes, offset);
}
@OverridepublicStringtoString() {
return"ExceptionTable{" +
"startPc=" + startPc +
", endPc=" + endPc +
", handlePc=" + handlePc +
", catchType=" + catchType +
'}';
}
}
intmaxStack; //u2intmaxLocals; //u2intcodeLength; //u4int[] code; // u1[codeLength]intexceptionTableLength; //u2ExceptionTable[] exceptionTable;
intattributeCount; //u2AttributeInfo[] attributes;
privateintattributesSize;
@OverridepublicintcontentSize() {
returnattributesSize + 2 + 2 + 4 + codeLength + exceptionTableLength;
}
@OverridepublicvoidparseInner(byte[] bytes, intoffset) {
maxStack = Utils.read2Number(bytes, offset);
offset += 2;
maxLocals = Utils.read2Number(bytes, offset);
offset += 2;
codeLength = Utils.read4Number(bytes, offset);
offset += 4;
code = newint[codeLength];
for (inti = 0; i < codeLength; i++) {
code[i] = Utils.readUnsignedByte(bytes, offset);
offset += 1;
}
exceptionTableLength = Utils.read2Number(bytes, offset);
offset += 2;
exceptionTable = newExceptionTable[exceptionTableLength];
for (inti = 0; i < exceptionTableLength; i++) {
exceptionTable[i] = newExceptionTable();
exceptionTable[i].parse(bytes, offset);
offset += exceptionTable[i].size();
}
attributeCount = Utils.read2Number(bytes, offset);
offset += 2;
attributes = newAttributeInfo[attributeCount];
for (inti = 0; i < attributeCount; i++) {
attributes[i] = newAttributeInfo();
attributes[i].parse(bytes, offset);
offset += attributes[i].size();
attributesSize += attributes[i].size();
}
}
publicStringtoString() {
return"CodeInfo{" +
"maxStack=" + maxStack +
", maxLocals=" + maxLocals +
", codeLength=" + codeLength +
", code=" + Arrays.toString(code) +
", exceptionTableLength=" + exceptionTableLength +
", exceptionTable=" + Arrays.toString(exceptionTable) +
", attributeCount=" + attributeCount +
", attributes=" + Arrays.toString(attributes) +
'}';
}
}

常量属性

classConstantValueextendsInfo {
intconstantValueIndex; //u2@OverridepublicvoidparseInner(byte[] bytes, intoffset) {
constantValueIndex = Utils.read2Number(bytes, offset + 2);
}
@OverridepublicintcontentSize() {
return2;
}
@OverridepublicStringtoString() {
return"ConstantValue{" +
"constantValueIndex=" + constantValueIndex +
'}';
}
}

异常属性

/** * <pre> * Exceptions_attribute { * u2 attribute_name_index; * u4 attribute_length; * u2 number_of_exceptions; * u2 exception_index_table[number_of_exceptions]; * } * </pre> */classExceptionsextendsInfo {
intnumberOfExceptions; //u2int[] exceptionIndexTable; //u2[numberOfExceptions]@OverridepublicintcontentSize() {
return2;
}
@OverridepublicvoidparseInner(byte[] bytes, intoffset) {
numberOfExceptions = Utils.read2Number(bytes, offset);
offset += 2;
exceptionIndexTable = newint[numberOfExceptions];
for (inti = 0; i < numberOfExceptions; i++) {
exceptionIndexTable[i] = Utils.read2Number(bytes, offset);
offset += 2;
}
}
@OverridepublicStringtoString() {
return"Exceptions{" +
"numberOfExceptions=" + numberOfExceptions +
", exceptionIndexTable=" + Arrays.toString(exceptionIndexTable) +
'}';
}
}

字节码与源码行号对应属性

/** * <pre> * LineNumberTable_attribute { * u2 attribute_name_index; * u4 attribute_length; * u2 line_number_table_length; * { u2 start_pc; * u2 line_number; * } line_number_table[line_number_table_length]; * } * </pre> */classLineNumberTableextendsInfo {
classLineNumberInfoimplementsParsable {
intstartPc; //u2intlineNumber; //u2publicstaticfinalintsize = 4;
@Overridepublicvoidparse(byte[] bytes, intoffset) {
startPc = Utils.read2Number(bytes, offset);
offset += 2;
lineNumber = Utils.read2Number(bytes, offset);
}
@OverridepublicStringtoString() {
return"LineNumberInfo{" +
"startPc=" + startPc +
", lineNumber=" + lineNumber +
'}';
}
}
intlineNumberTableLength; //u2privateLineNumberInfo[] mLineNumberInfos;
@OverrideprotectedintcontentSize() {
returnmLineNumberInfos.length * LineNumberInfo.size + 2;
}
@OverridepublicvoidparseInner(byte[] bytes, intoffset) {
lineNumberTableLength = Utils.read2Number(bytes, offset);
offset += 2;
mLineNumberInfos = newLineNumberInfo[lineNumberTableLength];
for (inti = 0; i < lineNumberTableLength; i++) {
mLineNumberInfos[i] = newLineNumberInfo();
mLineNumberInfos[i].parse(bytes, offset);
offset += LineNumberInfo.size;
}
}
@OverridepublicStringtoString() {
return"LineNumberTable{" +
"lineNumberTableLength=" + lineNumberTableLength +
", mLineNumberInfos=" + Arrays.toString(mLineNumberInfos) +
'}';
}
}

局部变量属性

/** * <pre> * LocalVariableTable_attribute { * u2 attribute_name_index; * u4 attribute_length; * u2 local_variable_table_length; * { u2 start_pc; * u2 length; * u2 name_index; * u2 descriptor_index; * u2 index; * } local_variable_table[local_variable_table_length]; * } * </pre> */classLocalVariableTableextendsInfo {
classLocalVairableTableItemimplementsParsable {
intstartPc;
intlength;
intnameIndex;
intdescriptorIndex;
intindex;
publicstaticfinalintsize = 10;
@Overridepublicvoidparse(byte[] bytes, intoffset) {
startPc = Utils.read2Number(bytes, offset);
length = Utils.read2Number(bytes, offset + 2);
nameIndex = Utils.read2Number(bytes, offset + 2);
descriptorIndex = Utils.read2Number(bytes, offset + 4);
index = Utils.read2Number(bytes, offset + 6);
}
@OverridepublicStringtoString() {
return"LocalVairableTableItem{" +
"startPc=" + startPc +
", length=" + length +
", nameIndex=" + nameIndex +
", descriptorIndex=" + descriptorIndex +
", index=" + index +
'}';
}
}
intlocalVariableTableLength; //u2privateLocalVairableTableItem[] items;
@OverrideprotectedintcontentSize() {
returnlocalVariableTableLength * LocalVairableTableItem.size + 2;
}
@OverridepublicvoidparseInner(byte[] bytes, intoffset) {
localVariableTableLength = Utils.read2Number(bytes, offset);
offset += 2;
items = newLocalVairableTableItem[localVariableTableLength];
for (inti = 0; i < localVariableTableLength; i++) {
items[i] = newLocalVairableTableItem();
items[i].parse(bytes, offset);
offset += LocalVairableTableItem.size;
}
}
@OverridepublicStringtoString() {
return"LocalVariableTable{" +
"localVariableTableLength=" + localVariableTableLength +
", items=" + Arrays.toString(items) +
'}';
}
}

源代码文件属性

/** * <pre> * SourceFile_attribute { * u2 attribute_name_index; * u4 attribute_length; * u2 sourcefile_index; * } * </pre> */classSourceFileextendsInfo {
intsourceFileIndex; //u2@OverrideprotectedintcontentSize() {
return2;
}
@OverridepublicvoidparseInner(byte[] bytes, intoffset) {
sourceFileIndex = Utils.read2Number(bytes, offset);
}
@OverridepublicStringtoString() {
return"SourceFile{" +
"sourceFileIndex=" + sourceFileIndex + " -> " + ((UTF8) BytecodeParser.constantItemHashMap.get(sourceFileIndex)).value +
'}';
}
}

内部类属性

/** * <pre> * InnerClasses_attribute { * u2 attribute_name_index; * u4 attribute_length; * u2 number_of_classes; * { u2 inner_class_info_index; * u2 outer_class_info_index; * u2 inner_name_index; * u2 inner_class_access_flags; * } classes[number_of_classes]; * } * </pre> */classInnerClassesextendsInfo {
classClassesimplementsParsable {
intinnerClassInfoIndex, outerClassInfoIndex, innerNameInex, innerClassAccessFlags; //u2publicstaticfinalintsize = 8;
@Overridepublicvoidparse(byte[] bytes, intoffset) {
innerClassInfoIndex = Utils.read2Number(bytes, offset);
offset += 2;
outerClassInfoIndex = Utils.read2Number(bytes, offset);
offset += 2;
innerNameInex = Utils.read2Number(bytes, offset);
offset += 2;
innerClassAccessFlags = Utils.read2Number(bytes, offset);
}
@OverridepublicStringtoString() {
return"Classes{" +
"innerClassInfoIndex=" + innerClassInfoIndex +
", outerClassInfoIndex=" + outerClassInfoIndex +
", innerNameInex=" + innerNameInex + " -> " + ((UTF8) BytecodeParser.constantItemHashMap.get(innerNameInex)).value +
", innerClassAccessFlags=" + innerClassAccessFlags + " -> " + AccessFlags.printAccess(innerClassAccessFlags) +
'}';
}
}
intnumberOfClasses; //u2privateClasses[] mClasses;
@OverrideprotectedintcontentSize() {
returnnumberOfClasses * Classes.size + 2;
}
@OverridepublicvoidparseInner(byte[] bytes, intoffset) {
numberOfClasses = Utils.read2Number(bytes, offset);
offset += 2;
mClasses = newClasses[numberOfClasses];
for (inti = 0; i < numberOfClasses; i++) {
mClasses[i] = newClasses();
mClasses[i].parse(bytes, offset);
offset += Classes.size;
}
}
@OverridepublicStringtoString() {
return"InnerClasses{" +
"numberOfClasses=" + numberOfClasses +
", mClasses=" + Arrays.toString(mClasses) +
'}';
}
}

泛型签名属性

/** * <pre> * Signature_attribute { * u2 attribute_name_index; * u4 attribute_length; * u2 signature_index; * } * </pre> */classSignatureextendsInfo {
intsignatureIndex; //u2@OverrideprotectedintcontentSize() {
return2;
}
@OverridepublicvoidparseInner(byte[] bytes, intoffset) {
signatureIndex = Utils.read2Number(bytes, offset);
}
@OverridepublicStringtoString() {
ConstantItemconstantItem = BytecodeParser.constantItemHashMap.get(signatureIndex);
Stringsignature = constantItem.toString();
if (constantIteminstanceofUTF8) {
signature = ((UTF8) constantItem).value;
} elseif (constantIteminstanceofMETHOD_REF) {
signature = constantItem.toString();
} elseif (constantIteminstanceofSTRING) {
signature = ((UTF8) BytecodeParser.constantItemHashMap.get(((STRING) constantItem).index)).value;
}
return"Signature{" +
"signatureIndex=" + signatureIndex + " -> " + signature +
'}';
}
}

StackMapTable 属性

StackMapTable 用于优化类型检查效率的。https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.4

/** * https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.4 * <pre> * StackMapTable_attribute { * u2 attribute_name_index; * u4 attribute_length; * u2 number_of_entries; * stack_map_frame entries[number_of_entries]; * } * * union stack_map_frame { * same_frame; * same_locals_1_stack_item_frame; * same_locals_1_stack_item_frame_extended; * chop_frame; * same_frame_extended; * append_frame; * full_frame; * } * </pre> */classStackMapTableextendsInfo {
classStackMapFrame {
/** * <pre> * same_frame { * u1 frame_type = SAME; // 0-63 * } * </pre> */classSameFrame {
intframe_type; //u1
}
/** * <pre> * same_locals_1_stack_item_frame { * u1 frame_type = SAME_LOCALS_1_STACK_ITEM; // 64-127 * verification_type_info stack[1]; * } * </pre> */classSameLocals1StackItemFrame {
}
classSameLocals1StackItemFrameExtended {
}
classChopFrame {
}
classSameFrameExtended {
}
classAppendFrame {
}
classFullFrame {
}
}
intnumberOfEntries; //u2privateStackMapFrame[] mStackMapFrames;
@OverrideprotectedintcontentSize() {
return0;
}
@OverridepublicvoidparseInner(byte[] bytes, intoffset) {
}
}

Synthetic 编译器合成属性

/** * <pre> * Synthetic_attribute { * u2 attribute_name_index; * u4 attribute_length; //always zero * } * </pre> */classSyntheticextendsInfo {
@OverrideprotectedintcontentSize() {
return0;
}
@OverridepublicvoidparseInner(byte[] bytes, intoffset) {
}
}

Deprecated 属性

/** * <pre> * Deprecated_attribute { * u2 attribute_name_index; * u4 attribute_length; * } * </pre> */classDeprecatedextendsInfo {
@OverrideprotectedintcontentSize() {
return0;
}
@OverridepublicvoidparseInner(byte[] bytes, intoffset) {
}
}

LocalVariableTypeTable

局部变量类型属性

/** * <pre> * LocalVariableTypeTable_attribute { * u2 attribute_name_index; * u4 attribute_length; * u2 local_variable_type_table_length; * { u2 start_pc; * u2 length; * u2 name_index; * u2 signature_index; * u2 index; * } local_variable_type_table[local_variable_type_table_length]; * } * </pre> */classLocalVariableTypeTableextendsInfo {
classLocal_variable_type_tableimplementsParsable {
intstart_pc;
intlength;
intname_index;
intsignature_index;
intindex;
publicstaticfinalintsize = 10;
@Overridepublicvoidparse(byte[] bytes, intoffset) {
start_pc = Utils.read2Number(bytes, offset);
length = Utils.read2Number(bytes, offset + 2);
name_index = Utils.read2Number(bytes, offset + 4);
signature_index = Utils.read2Number(bytes, offset + 6);
index = Utils.read2Number(bytes, offset + 8);
}
@OverridepublicStringtoString() {
return"Local_variable_type_table{" +
"start_pc=" + start_pc +
", length=" + length +
", name_index=" + name_index +
", signature_index=" + signature_index +
", index=" + index +
'}';
}
}
intlvtt_length; //u2Local_variable_type_table[] mTables;
@OverrideprotectedintcontentSize() {
returnlvtt_length * Local_variable_type_table.size + 2;
}
@OverridepublicvoidparseInner(byte[] bytes, intoffset) {
lvtt_length = Utils.read2Number(bytes, offset);
offset += 2;
mTables = newLocal_variable_type_table[lvtt_length];
for (inti = 0; i < lvtt_length; i++) {
mTables[i] = newLocal_variable_type_table();
mTables[i].parse(bytes, offset);
offset += Local_variable_type_table.size;
}
}
@OverridepublicStringtoString() {
return"LocalVariableTypeTable{" +
"lvtt_length=" + lvtt_length +
", mTables=" + Arrays.toString(mTables) +
'}';
}
}
//endregion

从字节中获取数字的工具类

由于 Java 的所有数字类型都是 signed 类型,就会导致 unsigned 的数到了 Java 中可能越界溢出。所以统一使用 Java 的 int 代表 unsigned byte

classUtils {
/** * 获取占4字节的数 */staticintread4Number(byte[] bytes, intoffset) {
return ((bytes[offset] & 0xFF) << 24) | ((bytes[offset + 1] & 0xFF) << 16) | ((bytes[offset + 2] & 0xFF) << 8) | ((bytes[offset + 3] & 0xFF));
}
/** * 获取占2字节的数, 为了避免 java 中只有 signed short 越界出现显示了负数, 所以返回 int */staticintread2Number(byte[] bytes, intoffset) {
return ((bytes[offset] & 0xFF) << 8) | (bytes[offset + 1] & 0xFF);
}
staticintreadUnsignedByte(byte[] bytes, intoffset) {
return (bytes[offset] & 0xFF);
}
/** * 获得占8字节的数 */staticlongread8Number(byte[] bytes, intoffset) {
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));
}
}

About

A java program for parse JVM bytecode.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages