org.aion.avm.utilities.analyze.ClassFileInfoBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javaee-rt Show documentation
Show all versions of javaee-rt Show documentation
An Execution Environment for Java SCOREs
package org.aion.avm.utilities.analyze;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ClassFileInfoBuilder {
public static ClassFileInfo getClassFileInfo(byte[] classFile) {
try {
return internalClassFileInfo(classFile);
} catch (Throwable t) {
return null;
}
}
public static ClassFileInfo getDirectClassFileInfo(byte[] classFile) {
return internalClassFileInfo(classFile);
}
private static ClassFileInfo internalClassFileInfo(byte[] classFile) {
// https://docs.oracle.com/javase/specs/jvms/se10/html/jvms-4.html
Map constantTypeCount = new HashMap<>();
int totalUtf8Length = 0;
int codeIndex = -1;
ByteReader reader = new ByteReader(classFile);
// magic
reader.readU4();
//minorVersion
reader.readU2();
// majorVersion
reader.readU2();
int constantPoolCount = reader.readU2() - 1;
for (int i = 0; i < constantPoolCount; i++) {
int tag = reader.readU1();
ConstantType constantType = ConstantType.forTag(tag);
try {
switch (constantType) {
case CONSTANT_CLASS:
case CONSTANT_METHOD_TYPE:
case CONSTANT_STRING:
reader.readU2();
break;
case CONSTANT_DOUBLE:
case CONSTANT_LONG:
reader.readU4();
reader.readU4();
// the next usable item in the pool is located at index n+2
i++;
break;
case CONSTANT_FIELDREF:
case CONSTANT_METHODREF:
case CONSTANT_NAME_AND_TYPE:
case CONSTANT_INVOKE_DYNAMIC:
case CONSTANT_INTERFACE_METHODREF:
reader.readU2();
reader.readU2();
break;
case CONSTANT_INTEGER:
case CONSTANT_FLOAT:
reader.readU4();
break;
case CONSTANT_UTF8:
int length = reader.readU2();
totalUtf8Length += length;
byte[] raw = reader.readNBytes(length);
// We need to read the buffer to advance, but we are also looking for "Code".
if ("Code".equals(new String(raw))) {
codeIndex = i;
}
break;
case CONSTANT_METHOD_HANDLE:
reader.readU1();
reader.readU2();
break;
}
} catch (Exception e) {
throw new AssertionError("Could not find constant pool tag " + tag);
}
constantTypeCount.put(constantType.name, constantTypeCount.getOrDefault(constantType.name, 0) + 1);
}
int constantPoolByteSize = reader.position();
//access_flags
reader.readU2();
//this_class
reader.readU2();
//super_class
reader.readU2();
//interfaces_count
int interfaceCount = reader.readU2();
for (int i = 0; i < interfaceCount; ++i) {
//interfaces[interfaces_count]
reader.readU2();
}
//fields_count
int fieldCount = reader.readU2();
int instanceFieldCount = 0;
for (int i = 0; i < fieldCount; ++i) {
//fields[fields_count]
boolean isInstance = readFieldInfo(reader);
if (isInstance) {
instanceFieldCount += 1;
}
}
//methods_count
int methodCount = reader.readU2();
List definedMethods = new ArrayList<>();
for (int i = 0; i < methodCount; ++i) {
//methods[methods_count]
// Note that constant pool entries are 1-indexed, so add 1 to the code index as that is how it will be referenced.
MethodCode method = readMethodInfo(reader, codeIndex + 1);
// It is possible that we will get a method without any code section (declared but not defined).
if (null != method) {
definedMethods.add(method);
}
}
//attributes_count
int attributeCount = reader.readU2();
for (int i = 0; i < attributeCount; ++i) {
//attributes[attributes_count]
readAttributeInfo(reader, -1);
}
return new ClassFileInfo(classFile.length, constantPoolCount, constantTypeCount, totalUtf8Length, constantPoolByteSize, instanceFieldCount, definedMethods);
}
private static boolean readFieldInfo(ByteReader reader) {
// access_flags.
int flags = reader.readU2();
// name_index.
reader.readU2();
// descriptor_index.
reader.readU2();
// attributes_count.
int attributeCount = reader.readU2();
for (int i = 0; i < attributeCount; ++i) {
readAttributeInfo(reader, -1);
}
// STATIC is 0x0008.
boolean isStatic = (0x0008 == (flags | 0x0008));
return !isStatic;
}
private static MethodCode readMethodInfo(ByteReader reader, int codeIndex) {
MethodCode implementedMethod = null;;
// access_flags.
reader.readU2();
// name_index.
reader.readU2();
// descriptor_index.
reader.readU2();
// attributes_count.
int attributeCount = reader.readU2();
for (int i = 0; i < attributeCount; ++i) {
MethodCode code = readAttributeInfo(reader, codeIndex);
if (null != code) {
if (null != implementedMethod) {
throw new IllegalArgumentException("Multiple code attributes found for the same method");
}
implementedMethod = code;
}
}
return implementedMethod;
}
private static MethodCode readAttributeInfo(ByteReader reader, int codeAttributeNameIndex) {
// return null or MethodCode if this is a code attribute.
MethodCode code = null;
// attribute_name_index.
int attributeNameIndex = reader.readU2();
// attribute_length.
int attributeLength = reader.readU4();
int start = reader.position();
if (codeAttributeNameIndex == attributeNameIndex) {
// Section 4.7.3 "Code_attribute".
int max_stack = reader.readU2();
int max_locals = reader.readU2();
int code_length = reader.readU4();
//u1 code[code_length];
reader.readNBytes(code_length);
int exception_table_length = reader.readU2();
for (int i = 0; i < exception_table_length; ++i) {
//start_pc
reader.readU2();
//end_pc
reader.readU2();
//handler_pc
reader.readU2();
//catch_type
reader.readU2();
}
// attributes_count.
int attributeCount = reader.readU2();
for (int i = 0; i < attributeCount; ++i) {
readAttributeInfo(reader, -1);
}
code = new MethodCode(max_stack, max_locals, code_length, exception_table_length);
/*
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];
}
*/
} else {
// Skip the info.
reader.readNBytes(attributeLength);
}
int end = reader.position();
if ((end - start) != attributeLength) {
throw new IllegalArgumentException("Declared attribute length and walked attribute length differ");
}
return code;
}
public static class ClassFileInfo {
public final int classFileLength;
public final int constantPoolEntryCount;
public final Map constantTypeCount;
public final int totalUtf8ByteLength;
public final int totalConstantPoolByteSize;
public final int instanceFieldCount;
public final List definedMethods;
public ClassFileInfo(int classFileLength, int constantPoolEntryCount, Map constantTypeCount, int totalUtf8ByteLength, int totalConstantPoolByteSize, int instanceFieldCount, List definedMethods) {
this.classFileLength = classFileLength;
this.constantPoolEntryCount = constantPoolEntryCount;
this.constantTypeCount = Collections.unmodifiableMap(constantTypeCount);
this.totalUtf8ByteLength = totalUtf8ByteLength;
this.totalConstantPoolByteSize = totalConstantPoolByteSize;
this.instanceFieldCount = instanceFieldCount;
this.definedMethods = Collections.unmodifiableList(definedMethods);
}
}
public static class MethodCode {
public final int maxStack;
public final int maxLocals;
public final int codeLength;
public final int exceptionTableSize;
public MethodCode(int maxStack, int maxLocals, int codeLength, int exceptionTableSize) {
this.maxStack = maxStack;
this.maxLocals = maxLocals;
this.codeLength = codeLength;
this.exceptionTableSize = exceptionTableSize;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy