GT_2757 fixed java stream decompile bug

This commit is contained in:
James 2019-05-13 16:14:02 -04:00
parent 96cb3f4d37
commit e3ae5a0370
69 changed files with 3100 additions and 1997 deletions

View File

@ -26,15 +26,15 @@ import ghidra.util.xml.SpecXmlUtils;
*
*/
public abstract class ConstantPool {
public static final int PRIMITIVE = 0; // Constant -value- of datatype -type-
public static final int STRING_LITERAL = 1; // Constant reference to string in -token-
public static final int CLASS_REFERENCE = 2; // Reference to (system level) class object
public static final int POINTER_METHOD = 3; // Pointer to a method, name in -token-, signature in -type-
public static final int POINTER_FIELD = 4; // Pointer to a field, name in -token-, datatype in -type-
public static final int ARRAY_LENGTH = 5; // Integer length, -token- is language specific indicator, -type- is integral type
public static final int INSTANCE_OF = 6; // boolean value, -token- is language specific indicator, -type- is boolean type
public static final int CHECK_CAST = 7; // Pointer to object, new name in -token-, new datatype in -type-
public static final int PRIMITIVE = 0; // Constant -value- of datatype -type-
public static final int STRING_LITERAL = 1; // Constant reference to string in -token-
public static final int CLASS_REFERENCE = 2; // Reference to (system level) class object
public static final int POINTER_METHOD = 3; // Pointer to a method, name in -token-, signature in -type-
public static final int POINTER_FIELD = 4; // Pointer to a field, name in -token-, datatype in -type-
public static final int ARRAY_LENGTH = 5; // Integer length, -token- is language specific indicator, -type- is integral type
public static final int INSTANCE_OF = 6; // boolean value, -token- is language specific indicator, -type- is boolean type
public static final int CHECK_CAST = 7; // Pointer to object, new name in -token-, new datatype in -type-
public static class Record {
public int tag; // The type of the record
public String token; // Name or token associated with object
@ -43,31 +43,41 @@ public abstract class ConstantPool {
public DataType type;
public boolean hasThisPtr = false;
public boolean isConstructor = false;
public StringBuilder build(long ref,PcodeDataTypeManager dtmanage) {
public StringBuilder build(long ref, PcodeDataTypeManager dtmanage) {
StringBuilder buf = new StringBuilder();
buf.append("<cpoolrec");
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "ref", ref);
if (tag == STRING_LITERAL)
if (tag == STRING_LITERAL) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "string");
else if (tag == CLASS_REFERENCE)
}
else if (tag == CLASS_REFERENCE) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "classref");
else if (tag == POINTER_METHOD)
}
else if (tag == POINTER_METHOD) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "method");
else if (tag == POINTER_FIELD)
}
else if (tag == POINTER_FIELD) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "field");
else if (tag == ARRAY_LENGTH)
}
else if (tag == ARRAY_LENGTH) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "arraylength");
else if (tag == INSTANCE_OF)
}
else if (tag == INSTANCE_OF) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "instanceof");
else if (tag == CHECK_CAST)
}
else if (tag == CHECK_CAST) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "checkcast");
else
}
else {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "primitive");
if (hasThisPtr)
}
if (hasThisPtr) {
SpecXmlUtils.encodeBooleanAttribute(buf, "hasthis", true);
if (isConstructor)
}
if (isConstructor) {
SpecXmlUtils.encodeBooleanAttribute(buf, "constructor", true);
}
buf.append(">\n");
if (tag == PRIMITIVE) {
buf.append("<value>");

View File

@ -99,15 +99,7 @@
<input name="cpool_index_ldc2_w"/>
</pcode>
</callotherfixup>
<callotherfixup targetop="lookupswitchCallOther">
<pcode dynamic="true">
<input name="default"/>
<input name="numPairs"/>
<input name ="padding"/>
</pcode>
</callotherfixup>
<callotherfixup targetop="multianewarrayCallOther">
<pcode dynamic="true">
<input name="cpool_index_multianewarray"/>

View File

@ -66,7 +66,6 @@ define pcodeop invokeinterfaceCallOther;
define pcodeop invokespecialCallOther;
define pcodeop invokestaticCallOther;
define pcodeop invokevirtualCallOther;
define pcodeop lookupswitchCallOther;
define pcodeop multianewarrayCallOther;
define pcodeop putStaticCallOther;
define pcodeop putFieldCallOther;
@ -418,8 +417,8 @@ Default:"default" addr is defaultbyte1; defaultbyte2; defaultbyte3; defaultbyte4
:checkcast index is (in_table_switch=0 & in_lookup_switch=0 & op=0xc0); indexbyte1; indexbyte2 [ index = indexbyte1<<8 | indexbyte2; ]
{
_object: $(SIZE) = *:$(SIZE) SP;
throwExceptionOp(_object);
#_object: $(SIZE) = *:$(SIZE) SP;
#throwExceptionOp(_object);
#_res:1 = cpool(_object,index,$(CPOOL_CHECKCAST));
#throwExceptionOp(_res);
@ -428,9 +427,12 @@ Default:"default" addr is defaultbyte1; defaultbyte2; defaultbyte3; defaultbyte4
#_ref: $(SIZE) = cpool(0:4,index,$(CPOOL_CHECKCAST));
#checkcastOp(_object,_ref);
#_object:$(SIZE) = 0;
#pop(_object);
#_res:1 = cpool(_object,index,$(CPOOL_INSTANCEOF));
_object:$(SIZE) = 0;
pop(_object);
_object = cpool(_object,index,$(CPOOL_CHECKCAST));
push(_object);
#_res:1 = cpool(_object,index,$(CPOOL_CHECKCAST));
#_result:$(SIZE) = zext(_res);
#push(_result);
}

View File

@ -31,6 +31,7 @@ import ghidra.javaclass.format.attributes.CodeAttribute;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
import ghidra.program.model.address.*;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.lang.LanguageCompilerSpecPair;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Program;
@ -43,6 +44,8 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
private static final String JAVA_NAME = "Java Class File";
private Register alignmentReg;
public static final long CODE_OFFSET = 0x10000L;
public static final String CONSTANT_POOL = "constantPool";
@Override
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
@ -61,22 +64,24 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
return loadSpecs;
}
private boolean checkClass(ByteProvider provider) {
private boolean checkClass(ByteProvider provider) throws IOException {
BinaryReader reader = new BinaryReader(provider, false);
ClassFileJava classFile;
int magic = reader.peekNextInt();
//if it doesn't begin with the 0xCAFEBABE it's not a class file
if (magic != JavaClassConstants.MAGIC) {
return false;
}
//attempt to parse the header, if successful count it as a class file.
try {
classFile = new ClassFileJava(reader);
new ClassFileJava(reader);
}
catch (IOException e) {
return false;
} catch (RuntimeException re) {
}
catch (RuntimeException re) {
return false;
}
int magic = classFile.getMagic();
if (magic == 0xCAFEBABE) {
return true;
}
return false;
return true;
}
@Override
@ -117,7 +122,7 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
throws LockException, MemoryConflictException, AddressOverflowException,
CancelledException, DuplicateNameException, IOException {
AddressFactory af = program.getAddressFactory();
AddressSpace space = af.getAddressSpace("constantPool");
AddressSpace space = af.getAddressSpace(CONSTANT_POOL);
Memory memory = program.getMemory();
alignmentReg = program.getRegister("alignmentPad");
@ -130,28 +135,27 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
memory.createInitializedBlock("_" + provider.getName() + "_", address,
provider.getInputStream(0), provider.length(), monitor, false);
createMethodLookupMemoryBlock( program, monitor );
createMethodLookupMemoryBlock(program, monitor);
createMethodMemoryBlocks(program, provider, classFile, monitor);
}
private void createMethodLookupMemoryBlock(Program program, TaskMonitor monitor) {
Address address = toAddr( program, JavaClassUtil.LOOKUP_ADDRESS );
Address address = toAddr(program, JavaClassUtil.LOOKUP_ADDRESS);
MemoryBlock block = null;
Memory memory = program.getMemory();
try {
block = memory.createInitializedBlock( "method_lookup", address, JavaClassUtil.METHOD_INDEX_SIZE, (byte) 0xff, monitor, false );
block = memory.createInitializedBlock("method_lookup", address,
JavaClassUtil.METHOD_INDEX_SIZE, (byte) 0xff, monitor, false);
}
catch (LockException | DuplicateNameException | MemoryConflictException
| AddressOverflowException | CancelledException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
block.setRead( true );
block.setWrite( false );
block.setExecute( false );
block.setRead(true);
block.setWrite(false);
block.setExecute(false);
}
@ -164,12 +168,11 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
monitor.setProgress(0);
monitor.setMaximum(methods.length);
long codeOffset = 0x10000;
Address start = toAddr(program, codeOffset);
Address start = toAddr(program, CODE_OFFSET);
try {
//program.setImageBase(start, true);
//for (MethodInfoJava method : methods) {
for (int i = 0, max = methods.length; i < max; ++i){
for (int i = 0, max = methods.length; i < max; ++i) {
MethodInfoJava method = methods[i];
monitor.incrementProgress(1);
CodeAttribute code = method.getCodeAttribute();
@ -180,18 +183,19 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
long offset = code.getCodeOffset();
Memory memory = program.getMemory();
short nameIndex = method.getNameIndex();
short descriptorIndex = method.getDescriptorIndex();
ConstantPoolUtf8Info methodNameInfo = (ConstantPoolUtf8Info) constantPool[nameIndex];
int nameIndex = method.getNameIndex();
int descriptorIndex = method.getDescriptorIndex();
ConstantPoolUtf8Info methodNameInfo =
(ConstantPoolUtf8Info) constantPool[nameIndex];
ConstantPoolUtf8Info methodDescriptorInfo =
(ConstantPoolUtf8Info) constantPool[descriptorIndex];
(ConstantPoolUtf8Info) constantPool[descriptorIndex];
String methodName = methodNameInfo.getString() + methodDescriptorInfo.getString();
MemoryBlock memoryBlock =
memory.createInitializedBlock(methodName, start,
provider.getInputStream(offset), length, monitor, false);
Address methodIndexAddress = JavaClassUtil.toLookupAddress( program, i );
program.getMemory( ).setInt( methodIndexAddress, (int) start.getOffset() );
MemoryBlock memoryBlock = memory.createInitializedBlock(methodName, start,
provider.getInputStream(offset), length, monitor, false);
Address methodIndexAddress = JavaClassUtil.toLookupAddress(program, i);
program.getMemory().setInt(methodIndexAddress, (int) start.getOffset());
program.getListing().createData(methodIndexAddress, PointerDataType.dataType);
setAlignmentInfo(program,
new AddressSet(memoryBlock.getStart(), memoryBlock.getEnd()));
@ -200,10 +204,9 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
start = start.add(1);
}
}
} catch (Exception e1) {
}
catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
@ -214,9 +217,8 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
int alignmentValue = 3;
while (addressIterator.hasNext()) {
Address address = addressIterator.next();
SetRegisterCmd cmd =
new SetRegisterCmd(alignmentReg, address, address,
BigInteger.valueOf(alignmentValue));
SetRegisterCmd cmd = new SetRegisterCmd(alignmentReg, address, address,
BigInteger.valueOf(alignmentValue));
cmd.applyTo(program);
if (alignmentValue == 0) {
alignmentValue = 3;

View File

@ -32,24 +32,24 @@ public class ConstantPoolJava extends ConstantPool {
private DataTypeManager dtManager = null;
//the following constants must agree with the definitions in JVM.slaspec
public static final String CPOOL_ANEWARRAY = "0";
public static final String CPOOL_CHECKCAST = "1";
public static final String CPOOL_GETFIELD = "2";
public static final String CPOOL_GETSTATIC = "3";
public static final String CPOOL_LDC = "4"; //also used for ldc_w
public static final String CPOOL_LDC2_W = "5";
public static final String CPOOL_INSTANCEOF = "6";
public static final String CPOOL_INVOKEDYNAMIC = "7";
public static final String CPOOL_ANEWARRAY = "0";
public static final String CPOOL_CHECKCAST = "1";
public static final String CPOOL_GETFIELD = "2";
public static final String CPOOL_GETSTATIC = "3";
public static final String CPOOL_LDC = "4"; //also used for ldc_w
public static final String CPOOL_LDC2_W = "5";
public static final String CPOOL_INSTANCEOF = "6";
public static final String CPOOL_INVOKEDYNAMIC = "7";
public static final String CPOOL_INVOKEINTERFACE = "8";
public static final String CPOOL_INVOKESPECIAL = "9";
public static final String CPOOL_INVOKESTATIC = "10";
public static final String CPOOL_INVOKEVIRTUAL = "11";
public static final String CPOOL_MULTIANEWARRAY = "12";
public static final String CPOOL_NEW = "13";
public static final String CPOOL_NEWARRAY = "14";
public static final String CPOOL_PUTSTATIC = "15";
public static final String CPOOL_PUTFIELD = "16";
public static final String CPOOL_ARRAYLENGTH = "17";
public static final String CPOOL_INVOKESPECIAL = "9";
public static final String CPOOL_INVOKESTATIC = "10";
public static final String CPOOL_INVOKEVIRTUAL = "11";
public static final String CPOOL_MULTIANEWARRAY = "12";
public static final String CPOOL_NEW = "13";
public static final String CPOOL_NEWARRAY = "14";
public static final String CPOOL_PUTSTATIC = "15";
public static final String CPOOL_PUTFIELD = "16";
public static final String CPOOL_ARRAYLENGTH = "17";
public ConstantPoolJava(Program program) throws IOException {
ClassFileAnalysisState analysisState = ClassFileAnalysisState.getState(program);
@ -58,43 +58,68 @@ public class ConstantPoolJava extends ConstantPool {
dtManager = program.getDataTypeManager();
}
private void fillinMethod(int name_and_type_index, Record res,JavaInvocationType methodType) {
ConstantPoolNameAndTypeInfo methodNameAndType = (ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index];
private void fillinMethod(int index, int name_and_type_index, Record res,
JavaInvocationType methodType) {
ConstantPoolNameAndTypeInfo methodNameAndType =
(ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index];
int name_index = methodNameAndType.getNameIndex();
res.tag = ConstantPool.POINTER_METHOD;
res.token = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
if (methodType.equals(JavaInvocationType.INVOKE_STATIC)) {
AbstractConstantPoolReferenceInfo poolRef =
(AbstractConstantPoolReferenceInfo) constantPool[index];
ConstantPoolClassInfo classInfo =
(ConstantPoolClassInfo) constantPool[poolRef.getClassIndex()];
int classNameIndex = classInfo.getNameIndex();
String fullyQualifiedName =
((ConstantPoolUtf8Info) constantPool[classNameIndex]).getString();
String className = getClassName(fullyQualifiedName);
res.token =
className + "." + ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
}
else {
res.token = ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
}
int descriptor_index = methodNameAndType.getDescriptorIndex();
ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
String descriptor = descriptorInfo.getString();
FunctionDefinitionDataType funcDef = new FunctionDefinitionDataType(res.token);
res.type = new PointerDataType(funcDef);
DataType returnType = DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor, dtManager);
String uniqueifier = Integer.toHexString(index);
FunctionDefinitionDataType funcDef =
new FunctionDefinitionDataType(uniqueifier + "_" + res.token);
DataType returnType =
DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor, dtManager);
funcDef.setReturnType(returnType);
List<DataType> params = DescriptorDecoder.getDataTypeList(descriptor, dtManager);
ParameterDefinitionImpl[] paramDefs;
//invokestatic and invokedynamic don't have a this pointer on the stack
if (methodType.equals(JavaInvocationType.INVOKE_STATIC) || methodType.equals(JavaInvocationType.INVOKE_DYNAMIC)){
if (methodType.equals(JavaInvocationType.INVOKE_STATIC) ||
methodType.equals(JavaInvocationType.INVOKE_DYNAMIC)) {
paramDefs = new ParameterDefinitionImpl[params.size()];
for (int i = 0, max = params.size(); i < max; ++i){
ParameterDefinitionImpl currentParam = new ParameterDefinitionImpl("", params.get(i), null);
paramDefs[i]= currentParam;
for (int i = 0, max = params.size(); i < max; ++i) {
ParameterDefinitionImpl currentParam =
new ParameterDefinitionImpl("", params.get(i), null);
paramDefs[i] = currentParam;
}
res.hasThisPtr = false;
}
//invokeinterface, invokespecial, and invokevirtual do have a this pointer
else {
paramDefs = new ParameterDefinitionImpl[params.size() + 1];
ParameterDefinitionImpl thisParam = new ParameterDefinitionImpl("objectRef", new Pointer32DataType(DataType.VOID), null);
ParameterDefinitionImpl thisParam = new ParameterDefinitionImpl("objectRef",
new Pointer32DataType(DataType.VOID), null);
paramDefs[0] = thisParam;
for (int i = 1, max = params.size(); i <= max; ++i){
ParameterDefinitionImpl currentParam = new ParameterDefinitionImpl("", params.get(i-1), null);
paramDefs[i]= currentParam;
for (int i = 1, max = params.size(); i <= max; ++i) {
ParameterDefinitionImpl currentParam =
new ParameterDefinitionImpl("", params.get(i - 1), null);
paramDefs[i] = currentParam;
}
res.hasThisPtr = true;
}
funcDef.setArguments(paramDefs);
res.type = new PointerDataType(funcDef);
}
//ref array does not include the first element passed to the cpool operator.
@ -109,38 +134,33 @@ public class ConstantPoolJava extends ConstantPool {
* type of the elements of the new array. We use the cpool operator to
* look up the string token corresponding to the primitive type.
*/
if (op.equals(CPOOL_NEWARRAY)){
if (op.equals(CPOOL_NEWARRAY)) {
res.tag = ConstantPool.POINTER_METHOD;
res.token = ArrayMethods.getPrimitiveArrayToken((int)ref[0]);
res.token = ArrayMethods.getPrimitiveArrayToken((int) ref[0]);
DataType elementType = ArrayMethods.getArrayBaseType((int) ref[0], dtManager);
res.type = dtManager.getPointer(elementType);
return res;
}
/*arraylength instruction does not reference the constant pool */
if (op.equals(CPOOL_ARRAYLENGTH)){
if (op.equals(CPOOL_ARRAYLENGTH)) {
res.tag = ConstantPool.ARRAY_LENGTH;
res.token = "length";
res.type = new PointerDataType(DWordDataType.dataType);
res.type = IntegerDataType.dataType;
return res;
}
AbstractConstantPoolInfoJava poolRef = constantPool[(int)ref[0]];
short name_and_type_index;
ConstantPoolNameAndTypeInfo fieldNameAndType;
short descriptor_index;
ConstantPoolUtf8Info descriptorInfo;
String descriptor;
StringBuilder sb = null;
String[] parts = null;
switch(op){
AbstractConstantPoolInfoJava poolRef = constantPool[(int) ref[0]];
int name_and_type_index;
switch (op) {
case CPOOL_ANEWARRAY:
case CPOOL_NEW:
res.tag = ConstantPool.CLASS_REFERENCE;
int name_index = ((ConstantPoolClassInfo)poolRef).getNameIndex();
String fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
parts = fullyQualifiedName.split("/");
res.token = parts[parts.length-1];
sb = new StringBuilder();
int name_index = ((ConstantPoolClassInfo) poolRef).getNameIndex();
String fullyQualifiedName =
((ConstantPoolUtf8Info) constantPool[name_index]).getString();
String[] parts = fullyQualifiedName.split("/");
res.token = parts[parts.length - 1];
StringBuilder sb = new StringBuilder();
for (String part : parts) {
sb.append(CategoryPath.DELIMITER_CHAR);
sb.append(part);
@ -148,12 +168,13 @@ public class ConstantPoolJava extends ConstantPool {
DataTypePath dataPath = new DataTypePath(sb.toString(), res.token);
res.type = new PointerDataType(dtManager.getDataType(dataPath));
break;
//TODO
case CPOOL_CHECKCAST:
res.tag = ConstantPool.CHECK_CAST;
res.token = "checkcast";
setTypeNameInfo(poolRef,res);
break;
setTypeNameInfo(poolRef, res);
res.tag = ConstantPool.CHECK_CAST;
PointerDataType pointerType = (PointerDataType) res.type;
String typeName = pointerType.getDataType().getDisplayName();
res.token = "checkcast(" + typeName + ")";
break;
case CPOOL_INSTANCEOF:
res.tag = ConstantPool.INSTANCE_OF;
res.token = "instanceof";
@ -161,154 +182,159 @@ public class ConstantPoolJava extends ConstantPool {
break;
case CPOOL_GETFIELD:
case CPOOL_PUTFIELD:
name_and_type_index = ((ConstantPoolFieldReferenceInfo)poolRef).getNameAndTypeIndex();
fieldNameAndType = (ConstantPoolNameAndTypeInfo)constantPool[name_and_type_index];
name_index = fieldNameAndType.getNameIndex();
res.tag = ConstantPool.POINTER_FIELD;
res.token = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
descriptor_index = fieldNameAndType.getDescriptorIndex();
descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
descriptor = descriptorInfo.getString();
DataType type = DescriptorDecoder.getDataTypeOfDescriptor(descriptor, dtManager);
res.type = new PointerDataType(type);
break;
//for references to static fields, we want the class name to be part of the token
case CPOOL_GETSTATIC:
case CPOOL_PUTSTATIC:
name_and_type_index = ((ConstantPoolFieldReferenceInfo)poolRef).getNameAndTypeIndex();
int class_index = ((ConstantPoolFieldReferenceInfo)poolRef).getClassIndex();
fieldNameAndType = (ConstantPoolNameAndTypeInfo)constantPool[name_and_type_index];
name_index = fieldNameAndType.getNameIndex();
ConstantPoolClassInfo classInfo = (ConstantPoolClassInfo)constantPool[class_index];
int classNameIndex = classInfo.getNameIndex();
fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[classNameIndex]).getString();
res.tag = ConstantPool.POINTER_FIELD;
String className = getClassName(fullyQualifiedName);
res.token = className + "." + ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
descriptor_index = fieldNameAndType.getDescriptorIndex();
descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
descriptor = descriptorInfo.getString();
type = DescriptorDecoder.getDataTypeOfDescriptor(descriptor, dtManager);
res.type = new PointerDataType(type);
//res.type = type;
handlePutAndGetOps(poolRef, res, op);
break;
case CPOOL_INVOKEDYNAMIC:
name_and_type_index = ((ConstantPoolInvokeDynamicInfo)poolRef).getNameAndTypeIndex();
fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_DYNAMIC);
name_and_type_index =
((ConstantPoolInvokeDynamicInfo) poolRef).getNameAndTypeIndex();
fillinMethod((int) ref[0], name_and_type_index, res,
JavaInvocationType.INVOKE_DYNAMIC);
break;
case CPOOL_INVOKEINTERFACE:
name_and_type_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getNameAndTypeIndex();
fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_INTERFACE);
name_and_type_index =
((ConstantPoolInterfaceMethodReferenceInfo) poolRef).getNameAndTypeIndex();
fillinMethod((int) ref[0], name_and_type_index, res,
JavaInvocationType.INVOKE_INTERFACE);
break;
case CPOOL_INVOKESPECIAL:
if (poolRef instanceof ConstantPoolMethodReferenceInfo) {
name_and_type_index = ((ConstantPoolMethodReferenceInfo)poolRef).getNameAndTypeIndex();
}
else{
name_and_type_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getNameAndTypeIndex();
}
fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_SPECIAL);
AbstractConstantPoolReferenceInfo refInfo =
(AbstractConstantPoolReferenceInfo) poolRef;
name_and_type_index = refInfo.getNameAndTypeIndex();
fillinMethod((int) ref[0], name_and_type_index, res,
JavaInvocationType.INVOKE_SPECIAL);
break;
case CPOOL_INVOKESTATIC:
if (poolRef instanceof ConstantPoolMethodReferenceInfo) {
name_and_type_index = ((ConstantPoolMethodReferenceInfo)poolRef).getNameAndTypeIndex();
class_index = ((ConstantPoolMethodReferenceInfo)poolRef).getClassIndex();
}
else{
name_and_type_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getNameAndTypeIndex();
class_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getClassIndex();
}
classInfo = (ConstantPoolClassInfo)constantPool[class_index];
classNameIndex = classInfo.getNameIndex();
fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[classNameIndex]).getString();
className = getClassName(fullyQualifiedName);
fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_STATIC);
res.token = className + "." + res.token;
refInfo = (AbstractConstantPoolReferenceInfo) poolRef;
name_and_type_index = refInfo.getNameAndTypeIndex();
fillinMethod((int) ref[0], name_and_type_index, res,
JavaInvocationType.INVOKE_STATIC);
break;
case CPOOL_INVOKEVIRTUAL:
name_and_type_index = ((ConstantPoolMethodReferenceInfo)poolRef).getNameAndTypeIndex();
fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_VIRTUAL);
name_and_type_index =
((ConstantPoolMethodReferenceInfo) poolRef).getNameAndTypeIndex();
fillinMethod((int) ref[0], name_and_type_index, res,
JavaInvocationType.INVOKE_VIRTUAL);
break;
//in this case, the constant pool entry can be a reference to:
//int, float, string literal, or a symbolic reference to a class,
//method type, or method handle
//in this case, the constant pool entry can be a reference to:
//int, float, string literal, or a symbolic reference to a class,
//method type, or method handle
case CPOOL_LDC:
if (poolRef instanceof ConstantPoolIntegerInfo) {
res.tag = ConstantPool.PRIMITIVE;
res.token = "int";
res.value = ((ConstantPoolIntegerInfo)poolRef).getValue();
res.value = ((ConstantPoolIntegerInfo) poolRef).getValue();
res.type = IntegerDataType.dataType;
}
else if (poolRef instanceof ConstantPoolFloatInfo) {
res.tag = ConstantPool.PRIMITIVE;
res.token = "float";
res.value = ((ConstantPoolFloatInfo)poolRef).getRawBytes() & 0xffffffffL;
res.value = ((ConstantPoolFloatInfo) poolRef).getRawBytes() & 0xffffffffL;
res.type = FloatDataType.dataType;
}
else if (poolRef instanceof ConstantPoolStringInfo) {
int string_index = ((ConstantPoolStringInfo)poolRef).getStringIndex();
int string_index = ((ConstantPoolStringInfo) poolRef).getStringIndex();
res.tag = ConstantPool.STRING_LITERAL;
res.byteData = ((ConstantPoolUtf8Info) constantPool[string_index]).getBytes();
res.type = DescriptorDecoder.getReferenceTypeOfDescriptor("java/lang/String", dtManager, false);
res.type = DescriptorDecoder.getReferenceTypeOfDescriptor("java/lang/String",
dtManager, false);
}
else if (poolRef instanceof ConstantPoolClassInfo){
else if (poolRef instanceof ConstantPoolClassInfo) {
res.tag = ConstantPool.CLASS_REFERENCE;
name_index = ((ConstantPoolClassInfo)poolRef).getNameIndex();
fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
className = getClassName(fullyQualifiedName);
res.token = className + ".class";
res.type = DescriptorDecoder.getReferenceTypeOfDescriptor(fullyQualifiedName, dtManager, false);
name_index = ((ConstantPoolClassInfo) poolRef).getNameIndex();
fullyQualifiedName =
((ConstantPoolUtf8Info) constantPool[name_index]).getString();
String className = getClassName(fullyQualifiedName);
res.token = className + ".class";
res.type = DescriptorDecoder.getReferenceTypeOfDescriptor(fullyQualifiedName,
dtManager, false);
}
//standard java compilers don't seem to emit the following two
else if (poolRef instanceof ConstantPoolMethodTypeInfo){
else if (poolRef instanceof ConstantPoolMethodTypeInfo) {
res.tag = ConstantPool.POINTER_METHOD;
name_index = ((ConstantPoolMethodTypeInfo)poolRef).getDescriptorIndex();
res.token = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
name_index = ((ConstantPoolMethodTypeInfo) poolRef).getDescriptorIndex();
res.token = ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
res.type = dtManager.getPointer(DWordDataType.dataType);
}
//TODO set the token?
else if (poolRef instanceof ConstantPoolMethodHandleInfo){
else if (poolRef instanceof ConstantPoolMethodHandleInfo) {
res.tag = ConstantPool.POINTER_METHOD;
res.type = dtManager.getPointer(DWordDataType.dataType);
}
break;
//must be a constant of type long or double
//according to JVM spec
//must be a constant of type long or double
//according to JVM spec
case CPOOL_LDC2_W:
if (poolRef instanceof ConstantPoolLongInfo) {
res.tag = ConstantPool.PRIMITIVE;
res.token = "long";
res.value = ((ConstantPoolLongInfo)poolRef).getValue();
res.value = ((ConstantPoolLongInfo) poolRef).getValue();
res.type = LongDataType.dataType;
}
else {
res.tag = ConstantPool.PRIMITIVE;
res.token = "double";
res.value = ((ConstantPoolDoubleInfo)poolRef).getRawBytes();
res.value = ((ConstantPoolDoubleInfo) poolRef).getRawBytes();
res.type = DoubleDataType.dataType;
}
break;
case CPOOL_MULTIANEWARRAY:
res.tag = ConstantPool.POINTER_METHOD;
res.tag = ConstantPool.CLASS_REFERENCE;
res.type = new PointerDataType(DataType.VOID);
int nameIndex = ((ConstantPoolClassInfo) poolRef).getNameIndex();
ConstantPoolUtf8Info utf8Info = (ConstantPoolUtf8Info) constantPool[nameIndex];
String classNameWithSemicolon = utf8Info.getString();
res.token = DescriptorDecoder.getTypeNameFromDescriptor(classNameWithSemicolon, false, false);
res.token = DescriptorDecoder.getTypeNameFromDescriptor(classNameWithSemicolon,
false, false);
default:
break;
}
return res;
}
private void handlePutAndGetOps(AbstractConstantPoolInfoJava poolRef, Record res, String op) {
int name_and_type_index = ((ConstantPoolFieldReferenceInfo) poolRef).getNameAndTypeIndex();
ConstantPoolNameAndTypeInfo fieldNameAndType =
(ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index];
int name_index = fieldNameAndType.getNameIndex();
switch (op) {
case CPOOL_GETFIELD:
case CPOOL_PUTFIELD:
res.token = ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
break;
case CPOOL_GETSTATIC:
case CPOOL_PUTSTATIC:
int class_index = ((ConstantPoolFieldReferenceInfo) poolRef).getClassIndex();
ConstantPoolClassInfo classInfo = (ConstantPoolClassInfo) constantPool[class_index];
int classNameIndex = classInfo.getNameIndex();
String fullyQualifiedName =
((ConstantPoolUtf8Info) constantPool[classNameIndex]).getString();
String className = getClassName(fullyQualifiedName);
res.token =
className + "." + ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
break;
default:
throw new IllegalArgumentException("Invalid op: " + op);
}
res.tag = ConstantPool.POINTER_FIELD;
int descriptor_index = fieldNameAndType.getDescriptorIndex();
ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
String descriptor = descriptorInfo.getString();
DataType type = DescriptorDecoder.getDataTypeOfDescriptor(descriptor, dtManager);
res.type = new PointerDataType(type);
}
private void setTypeNameInfo(AbstractConstantPoolInfoJava poolRef, Record res) {
int name_index = ((ConstantPoolClassInfo)poolRef).getNameIndex();
String fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
int name_index = ((ConstantPoolClassInfo) poolRef).getNameIndex();
String fullyQualifiedName = ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
String[] parts = null;
StringBuilder sb = null;
if (fullyQualifiedName.startsWith("[")){
if (fullyQualifiedName.startsWith("[")) {
//TODO: how to get instanceof X to display, where X is an array type?
//need to decide how to handle multidimensional arrays
//remove the brackets
@ -318,7 +344,7 @@ public class ConstantPoolJava extends ConstantPool {
for (String part : parts) {
sb.append(CategoryPath.DELIMITER_CHAR);
sb.append(part);
}
}
}
else {
parts = fullyQualifiedName.split("/");
@ -328,17 +354,17 @@ public class ConstantPoolJava extends ConstantPool {
sb.append(part);
}
}
DataTypePath dataPath = new DataTypePath(sb.toString(), parts[parts.length-1]);
DataTypePath dataPath = new DataTypePath(sb.toString(), parts[parts.length - 1]);
res.type = new PointerDataType(dtManager.getDataType(dataPath));
}
private String getClassName(String fullyQualifiedName){
private String getClassName(String fullyQualifiedName) {
int lastSlash = fullyQualifiedName.lastIndexOf("/");
return fullyQualifiedName.substring(lastSlash+1, fullyQualifiedName.length());
return fullyQualifiedName.substring(lastSlash + 1, fullyQualifiedName.length());
}
public AbstractConstantPoolInfoJava[] getConstantPool(){
public AbstractConstantPoolInfoJava[] getConstantPool() {
return constantPool;
}

View File

@ -31,7 +31,7 @@ public class InjectInvokeDynamic extends InjectPayloadJava {
InjectContext injectContext = getInjectContext(program, context);
AbstractConstantPoolInfoJava[] constantPool = getConstantPool(program);
int constantPoolIndex = (int) injectContext.inputlist.get(0).getOffset();
String pcodeText = InvokeMethods.getPcodeForInvoke(constantPoolIndex, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
String pcodeText = InvokeMethods.getPcodeForInvokeDynamic(constantPoolIndex, constantPool);
return pcodeText;
}

View File

@ -1,43 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.pcodeInject;
import java.io.IOException;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.program.model.lang.InjectContext;
import ghidra.program.model.listing.Program;
public class InjectLookupSwitch extends InjectPayloadJava {
public InjectLookupSwitch(String sourceName, SleighLanguage language) {
super(sourceName, language);
}
@Override
public String getPcodeText(Program program, String context) {
InjectContext injectContext = getInjectContext(program, context);
String pcodeText = null;
try {
pcodeText = SwitchMethods.getPcodeForLookupSwitch(injectContext, program);
} catch (IOException e) {
e.printStackTrace();
pcodeText = "SP = SP;\n";
}
return pcodeText;
}
}

View File

@ -38,7 +38,7 @@ public class InvokeMethods {
static final String PARAM_SPACE = "parameterSpace";
//private constructor to enforce noninstantiability
private InvokeMethods(){
private InvokeMethods() {
throw new AssertionError();
}
@ -50,24 +50,28 @@ public class InvokeMethods {
* @param type - the JavaInvocationType of the invocation
* @return - the pcode as a string
*/
public static String getPcodeForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) {
public static String getPcodeForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool,
JavaInvocationType type) {
StringBuilder pCode = new StringBuilder();
String descriptor = DescriptorDecoder.getDescriptorForInvoke(offset, constantPool, type);
List<JavaComputationalCategory> categories = DescriptorDecoder.getParameterCategories(descriptor);
boolean includeThisPointer = type.equals(JavaInvocationType.INVOKE_VIRTUAL) || type.equals(JavaInvocationType.INVOKE_SPECIAL) || type.equals(JavaInvocationType.INVOKE_INTERFACE);
String descriptor = DescriptorDecoder.getDescriptorForInvoke(offset, constantPool, type);
List<JavaComputationalCategory> categories =
DescriptorDecoder.getParameterCategories(descriptor);
boolean includeThisPointer = type.equals(JavaInvocationType.INVOKE_VIRTUAL) ||
type.equals(JavaInvocationType.INVOKE_SPECIAL) ||
type.equals(JavaInvocationType.INVOKE_INTERFACE);
int stackPurge = DescriptorDecoder.getStackPurge(descriptor);
if (includeThisPointer){
if (includeThisPointer) {
stackPurge += 4;
}
emitPcodeToMoveParams(pCode, categories, includeThisPointer, stackPurge);
emitPcodeToResolveMethodReference(pCode, offset, constantPool, type);
PcodeTextEmitter.emitIndirectCall(pCode, CALL_TARGET);
JavaComputationalCategory retType = DescriptorDecoder.getReturnCategoryOfMethodDescriptor(descriptor);
switch (retType){
JavaComputationalCategory retType =
DescriptorDecoder.getReturnCategoryOfMethodDescriptor(descriptor);
switch (retType) {
case CAT_1:
PcodeTextEmitter.emitPushCat1Value(pCode, CAT_1_RETURN);
break;
@ -80,6 +84,42 @@ public class InvokeMethods {
return pCode.toString();
}
/**
* Emits the pcode for an invoke instruction.
* @param offset - the index of the constant pool element containing a symbolic reference
* to a method or a call site specifier.
* @param constantPool - the constant pool
* @return - the pcode as a string
*/
public static String getPcodeForInvokeDynamic(int offset,
AbstractConstantPoolInfoJava[] constantPool) {
StringBuilder pCode = new StringBuilder();
String invokeDynamicDescriptor = DescriptorDecoder.getDescriptorForInvoke(offset,
constantPool, JavaInvocationType.INVOKE_DYNAMIC);
List<JavaComputationalCategory> categories =
DescriptorDecoder.getParameterCategories(invokeDynamicDescriptor);
int stackPurge = DescriptorDecoder.getStackPurge(invokeDynamicDescriptor);
emitPcodeToMoveParams(pCode, categories, false, stackPurge);
emitPcodeToResolveMethodReference(pCode, offset, constantPool,
JavaInvocationType.INVOKE_DYNAMIC);
PcodeTextEmitter.emitIndirectCall(pCode, CALL_TARGET);
JavaComputationalCategory retType =
DescriptorDecoder.getReturnCategoryOfMethodDescriptor(invokeDynamicDescriptor);
switch (retType) {
case CAT_1:
PcodeTextEmitter.emitPushCat1Value(pCode, CAT_1_RETURN);
break;
case CAT_2:
PcodeTextEmitter.emitPushCat2Value(pCode, CAT_2_RETURN);
break;
default:
break;
}
return pCode.toString();
}
/**
* Emits pcode to move the parameters from the stack to the space parameterSpace
@ -89,21 +129,26 @@ public class InvokeMethods {
* @param categories - the list of computational categories on the top of the stack
* @param includeThisPointer - true if the first element on the stack is an implicit this parameter
*/
static void emitPcodeToMoveParams(StringBuilder pCode, List<JavaComputationalCategory> categories, boolean includeThisPointer, int totalSize){
static void emitPcodeToMoveParams(StringBuilder pCode,
List<JavaComputationalCategory> categories, boolean includeThisPointer, int totalSize) {
//pop the parameters off of the stack
for (int i = categories.size() - 1; i >= 0; --i){
switch (categories.get(i)){
for (int i = categories.size() - 1; i >= 0; --i) {
switch (categories.get(i)) {
case CAT_1:
PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER + Integer.toString(i));
totalSize -= 4;
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize) + ":4", PARAMETER + Integer.toString(i));
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4,
Integer.toString(totalSize) + ":4", PARAMETER + Integer.toString(i));
break;
case CAT_2:
PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER + Integer.toString(i));
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize-8) + ":4", PARAMETER + Integer.toString(i));
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4,
Integer.toString(totalSize - 8) + ":4", PARAMETER + Integer.toString(i));
PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER_PART2 + Integer.toString(i));
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize-4) + ":4", PARAMETER_PART2 + Integer.toString(i));
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4,
Integer.toString(totalSize - 4) + ":4",
PARAMETER_PART2 + Integer.toString(i));
totalSize -= 8;
break;
default:
@ -111,15 +156,15 @@ public class InvokeMethods {
}
}
//pop off the this pointer if there is one
if (includeThisPointer){
if (includeThisPointer) {
PcodeTextEmitter.emitPopCat1Value(pCode, THIS);
totalSize -= 4;
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize) + ":4", THIS);
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4,
Integer.toString(totalSize) + ":4", THIS);
}
}
/**
* Emits pcode to assign the result of a cpool op to the call_target register for an invocation.
* @param pCode - the pcode buffer
@ -127,25 +172,37 @@ public class InvokeMethods {
* @param constantPool - the constant pool
* @param type - the type of the invocation
*/
static void emitPcodeToResolveMethodReference(StringBuilder pCode, int offset, AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type){
switch (type){
static void emitPcodeToResolveMethodReference(StringBuilder pCode, int offset,
AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) {
switch (type) {
case INVOKE_DYNAMIC:
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset),
ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
break;
case INVOKE_INTERFACE:
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKEINTERFACE);
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset),
ConstantPoolJava.CPOOL_INVOKEINTERFACE);
break;
case INVOKE_SPECIAL:
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKESPECIAL);
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset),
ConstantPoolJava.CPOOL_INVOKESPECIAL);
break;
case INVOKE_STATIC:
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKESTATIC);
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset),
ConstantPoolJava.CPOOL_INVOKESTATIC);
break;
case INVOKE_VIRTUAL:
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset),
ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
break;
default:
throw new IllegalArgumentException("Unimplemented JavaMethodType: " + type.toString());
throw new IllegalArgumentException(
"Unimplemented JavaMethodType: " + type.toString());
}
}
}

View File

@ -79,18 +79,7 @@ import ghidra.program.model.listing.Program;
* (Use/add to PcodeTextEmitter.java to actually emit pcode text)
* See ConstantPoolJava.java for examples of the use of the CPOOL pcode op.
*
* TODO:
* 1) For the lookupswitch op, the disassembly is correct but the decompilation is not.
* There are several possible ways of modeling the instruction in pcode - either using
* injection (SwitchMethods.java) or pcode (JVM.slaspec). In all cases, there seems to
* be an issue with getting the decompiler to follow pointers to the various switch clauses.
* The file LookupSwitchHex.java in the resource directory contains a class file with
* 4 methods with switch statements. Currently the first method is modeled using a
* pcode loop and the last three are modeled using pcode injection (which is possible because
* there are actually 4 separate lookupswitch instructions, the only difference is the amount
* of padding bytes).
*
* possible improvements:
* possible improvements:
*
* 2) incorporate exceptions.
* 6) decide how to display the information used in an invokedynamic instruction
@ -121,7 +110,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
public static final String LDC = "ldcCallOther";
public static final String LDC2_W = "ldc2_wCallOther";
public static final String LDC_W = "ldc_wCallOther";
public static final String LOOKUP_SWITCH = "lookupswitchCallOther";
public static final String MULTIANEWARRAY = "multianewarrayCallOther";
public static final String PUTFIELD = "putFieldCallOther";
@ -149,7 +137,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
implementedOps.add(LDC);
implementedOps.add(LDC2_W);
implementedOps.add(LDC_W);
implementedOps.add(LOOKUP_SWITCH);
implementedOps.add(MULTIANEWARRAY);
implementedOps.add(PUTFIELD);
implementedOps.add(PUTSTATIC);
@ -170,8 +157,9 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
@Override
protected InjectPayloadSleigh allocateInject(String sourceName, String name, int tp) {
InjectPayloadJava payload = null;
if (tp != InjectPayload.CALLOTHERFIXUP_TYPE)
if (tp != InjectPayload.CALLOTHERFIXUP_TYPE) {
return super.allocateInject(sourceName, name, tp);
}
switch (name) {
case GETFIELD:
payload = new InjectGetField(sourceName, language);
@ -199,9 +187,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
case LDC_W:
payload = new InjectLdc(sourceName, language);
break;
case LOOKUP_SWITCH:
payload = new InjectLookupSwitch(sourceName, language);
break;
case MULTIANEWARRAY:
payload = new InjectMultiANewArray(sourceName, language);
break;

View File

@ -15,7 +15,6 @@
*/
package ghidra.app.util.pcodeInject;
/**
*
* This is a utility class containing methods to emit pcode for decompile callbacks occurring during analysis of
@ -27,22 +26,22 @@ package ghidra.app.util.pcodeInject;
*/
public class PcodeTextEmitter {
static final String RAM = "ram";
static final String RAM = "ram";
//private constructor to enforce noninstantiability
private PcodeTextEmitter(){
private PcodeTextEmitter() {
throw new AssertionError();
}
/**
* Emits pcode to push a value of computational category 1 onto the stack.
* @param pCode - StringBuilder to hold pcode.
* @param valueName - name of varnode to push.
*/
public static void emitPushCat1Value(StringBuilder pCode, String valueName){
public static void emitPushCat1Value(StringBuilder pCode, String valueName) {
pCode.append("SP = SP - 4;\n*:4 SP = ");
pCode.append(valueName);
pCode.append(";\n");
pCode.append(";\n");
}
/**
@ -50,10 +49,10 @@ public class PcodeTextEmitter {
* @param pCode - StringBuilder to hold pcode.
* @param valueName - name of varnode to push.
*/
public static void emitPushCat2Value(StringBuilder pCode, String valueName){
public static void emitPushCat2Value(StringBuilder pCode, String valueName) {
pCode.append("SP = SP - 8;\n*:8 SP = ");
pCode.append(valueName);
pCode.append(";\n");
pCode.append(";\n");
}
/**
@ -61,9 +60,9 @@ public class PcodeTextEmitter {
* @param pCode - StringBuilder to hold pcode.
* @param destName - name of destination varnode.
*/
public static void emitPopCat2Value(StringBuilder pCode, String destName){
public static void emitPopCat2Value(StringBuilder pCode, String destName) {
pCode.append(destName);
pCode.append(":8 = *:8 SP;\nSP = SP + 8;\n");
pCode.append(":8 = *:8 SP;\nSP = SP + 8;\n");
}
/**
@ -71,9 +70,9 @@ public class PcodeTextEmitter {
* @param pCode - StringBuilder to hold pcode.
* @param destName - name of destination varnode.
*/
public static void emitPopCat1Value(StringBuilder pCode, String destName){
public static void emitPopCat1Value(StringBuilder pCode, String destName) {
pCode.append(destName);
pCode.append(":4 = *:4 SP;\nSP = SP + 4;\n");
pCode.append(":4 = *:4 SP;\nSP = SP + 4;\n");
}
/**
@ -83,56 +82,55 @@ public class PcodeTextEmitter {
* @param pcodeop - name of pcodeop
* @param args - zero or more arguments for the pcodeop
*/
public static void emitAssignVarnodeFromPcodeOpCall(StringBuilder pCode, String varnodeName, int size, String pcodeop, String... args){
public static void emitAssignVarnodeFromPcodeOpCall(StringBuilder pCode, String varnodeName,
int size, String pcodeop, String... args) {
pCode.append(varnodeName);
pCode.append(":");
pCode.append(":");
pCode.append(Integer.toString(size));
pCode.append(" = ");
pCode.append(" = ");
pCode.append(pcodeop);
pCode.append("(");
for (int i = 0, numArgs = args.length; i < numArgs; ++i){
for (int i = 0, numArgs = args.length; i < numArgs; ++i) {
pCode.append(args[i]);
if (i < numArgs - 1){
if (i < numArgs - 1) {
pCode.append(",");
}
}
pCode.append(");\n");
}
/**
* Emits pcode to call a void black-box pcodeop
* @param pCode StringBuilder to hold the pcode
* @param pcodeop - name of pcodeop
* @param args - zero or more arguments for the pcodeop
*/
public static void emitVoidPcodeOpCall(StringBuilder pCode, String pcodeop, String... args){
public static void emitVoidPcodeOpCall(StringBuilder pCode, String pcodeop, String... args) {
pCode.append(pcodeop);
pCode.append("(");
for (int i = 0, numArgs = args.length; i < numArgs; ++i){
for (int i = 0, numArgs = args.length; i < numArgs; ++i) {
pCode.append(args[i]);
if (i < numArgs - 1){
if (i < numArgs - 1) {
pCode.append(",");
}
}
pCode.append(");\n");
}
/**
* Appends the pcode to assign an integer constant to a register
* @param pCode
* @param constantPool
* @param index
*/
public static void emitAssignConstantToRegister(StringBuilder pCode, String register, int constant){
public static void emitAssignConstantToRegister(StringBuilder pCode, String register,
int constant) {
pCode.append(register);
pCode.append(" = 0x");
pCode.append(Integer.toHexString(constant));
pCode.append(";\n");
}
/**
* Appends the pcode to assign a register to the result of a pcode op call with arguments args
* @param pCode
@ -140,32 +138,42 @@ public class PcodeTextEmitter {
* @param pcodeop
* @param args
*/
public static void emitAssignRegisterFromPcodeOpCall(StringBuilder pCode, String register, String pcodeop, String... args){
public static void emitAssignRegisterFromPcodeOpCall(StringBuilder pCode, String register,
String pcodeop, String... args) {
pCode.append(register);
pCode.append(" = ");
pCode.append(pcodeop);
pCode.append("(");
for (int i = 0, numArgs = args.length; i < numArgs; ++i){
for (int i = 0, numArgs = args.length; i < numArgs; ++i) {
pCode.append(args[i]);
if (i < numArgs - 1){
if (i < numArgs - 1) {
pCode.append(",");
}
}
pCode.append(");\n");
}
/**
* Appends the pcode to emit a label definition.
* @param pCode
* @param caseName
*/
public static void emitLabelDefinition(StringBuilder pCode, String caseName){
public static void emitLabelDefinition(StringBuilder pCode, String caseName) {
pCode.append("<");
pCode.append(caseName);
pCode.append(">\n");
}
public static void emitWriteToMemory(StringBuilder pCode, String space, int size, String offset, String value){
/**
* Appends the pcode to write to a value at an offset of a memory space
* @param pCode buffer to append pcode
* @param space name of space
* @param size size of write
* @param offset offset in space
* @param value value to write
*/
public static void emitWriteToMemory(StringBuilder pCode, String space, int size, String offset,
String value) {
pCode.append("*[");
pCode.append(space);
pCode.append("]:");
@ -177,19 +185,25 @@ public class PcodeTextEmitter {
pCode.append(";\n");
}
public static void emitIndirectCall(StringBuilder pCode, String target){
/**
* Appends the pcode to emit an indirect call
* @param pCode buffer to append to
* @param target varnode to call indirectly
*/
public static void emitIndirectCall(StringBuilder pCode, String target) {
pCode.append("call [");
pCode.append(target);
pCode.append("];\n");
}
public static void emitAddToStackPointer(StringBuilder pCode, int amount){
pCode.append("SP = SP + ");
pCode.append(Integer.toString(amount));
pCode.append(";\n");
}
public static void emitSignExtension(StringBuilder pCode, String dest, int size, String src){
/**
* Appends the pcode to sign-extend the value src into dest
* @param pCode buffer to append to
* @param dest target varnode
* @param size size of target varnode
* @param src size of source varnode
*/
public static void emitSignExtension(StringBuilder pCode, String dest, int size, String src) {
pCode.append(dest);
pCode.append(":");
pCode.append(Integer.toString(size));
@ -197,8 +211,15 @@ public class PcodeTextEmitter {
pCode.append(src);
pCode.append(");\n");
}
public static void emitZeroExtension(StringBuilder pCode, String dest, int size, String src){
/**
* Appends the pcode to zero-extend the value src into dest
* @param pCode buffer to append to
* @param dest target varnode
* @param size size of target varnode
* @param src size of source varnode
*/
public static void emitZeroExtension(StringBuilder pCode, String dest, int size, String src) {
pCode.append(dest);
pCode.append(":");
pCode.append(Integer.toString(size));
@ -206,8 +227,15 @@ public class PcodeTextEmitter {
pCode.append(src);
pCode.append(");\n");
}
public static void emitTruncate(StringBuilder pCode, String dest, int size, String src){
/**
* Appends the pcode truncate src into dest
* @param pCode buffer to append to
* @param dest target varnode
* @param size size of target varnode
* @param src size of source varnode
*/
public static void emitTruncate(StringBuilder pCode, String dest, int size, String src) {
pCode.append(dest);
pCode.append(" = ");
pCode.append(src);
@ -215,6 +243,25 @@ public class PcodeTextEmitter {
pCode.append(Integer.toString(size));
pCode.append(";\n");
}
/**
* Appends the pcode to assign a varnode from a dereference of another varnode
* @param pCode buffer to append to
* @param lhs target varnode
* @param size size of pointed-to value
* @param rhs varnode to dereference
*/
public static void emitAssignVarnodeFromDereference(StringBuilder pCode, String lhs, int size,
String rhs) {
pCode.append(lhs);
pCode.append(":");
pCode.append(Integer.toString(size));
pCode.append(" = ");
pCode.append("*:");
pCode.append(Integer.toString(size));
pCode.append(" ");
pCode.append(rhs);
pCode.append(";\n");
}
}

View File

@ -16,10 +16,7 @@
package ghidra.app.util.pcodeInject;
import ghidra.javaclass.format.DescriptorDecoder;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
import ghidra.javaclass.format.constantpool.ConstantPoolFieldReferenceInfo;
import ghidra.javaclass.format.constantpool.ConstantPoolNameAndTypeInfo;
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
import ghidra.javaclass.format.constantpool.*;
/**
*
@ -37,14 +34,15 @@ import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
public class ReferenceMethods {
static final String VALUE = "value";
static final String TEMP = "temp";
static final String TEMP_1 = "temp_1";
static final String TEMP_2 = "temp_2";
static final String NEW_VALUE = "newValue";
static final String OBJECT_REF = "objectRef";
static final String FIELD_OFFSET = "fieldOffset";
static final String STATIC_OFFSET = "staticOffset";
//private constructor to enforce noninstantiability
private ReferenceMethods(){
private ReferenceMethods() {
throw new AssertionError();
}
@ -54,44 +52,63 @@ public class ReferenceMethods {
* @param constantPool - the constant pool of the class file
* @return - the pcode string
*/
public static String getPcodeForGetStatic(int index, AbstractConstantPoolInfoJava[] constantPool) {
public static String getPcodeForGetStatic(int index,
AbstractConstantPoolInfoJava[] constantPool) {
StringBuilder pCode = new StringBuilder();
//determine the computational category and push a value of the correct size onto the operand stack
String descriptor = getDescriptorForFieldRef(constantPool, index);
switch (descriptor.charAt(0)){
switch (descriptor.charAt(0)) {
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP);
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
break;
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1);
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break;
case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP);
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1);
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break;
case DescriptorDecoder.BASE_TYPE_CHAR: //char
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP);
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1);
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break;
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP);
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
break;
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1);
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break;
case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension
case DescriptorDecoder.BASE_TYPE_FLOAT: //float
case DescriptorDecoder.BASE_TYPE_INT: //int
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 4,
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 4, TEMP_1);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break;
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
case DescriptorDecoder.BASE_TYPE_LONG: //long
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 8, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitPushCat2Value(pCode,VALUE);
break;
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 8,
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 8, TEMP_1);
PcodeTextEmitter.emitPushCat2Value(pCode, VALUE);
break;
default:
throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
}
@ -104,49 +121,68 @@ public class ReferenceMethods {
* @param constantPool - the constant pool of the class file
* @return - the pcode string
*/
public static String getPcodeForPutStatic(int index, AbstractConstantPoolInfoJava[] constantPool){
public static String getPcodeForPutStatic(int index,
AbstractConstantPoolInfoJava[] constantPool) {
StringBuilder pCode = new StringBuilder();
String descriptor = getDescriptorForFieldRef(constantPool, index);
switch (descriptor.charAt(0)){
switch (descriptor.charAt(0)) {
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET, TEMP);
break;
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET,
TEMP_1);
break;
case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET, TEMP);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET,
TEMP_1);
break;
case DescriptorDecoder.BASE_TYPE_CHAR: //char
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET, TEMP);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET,
TEMP_1);
break;
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET, TEMP);
break;
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET,
TEMP_1);
break;
case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension
case DescriptorDecoder.BASE_TYPE_FLOAT: //float
case DescriptorDecoder.BASE_TYPE_INT: //int
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, STATIC_OFFSET, NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, STATIC_OFFSET,
NEW_VALUE);
break;
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
case DescriptorDecoder.BASE_TYPE_LONG: //long
PcodeTextEmitter.emitPopCat2Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, STATIC_OFFSET, NEW_VALUE);
break;
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, STATIC_OFFSET,
NEW_VALUE);
break;
default:
throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
}
@ -159,50 +195,69 @@ public class ReferenceMethods {
* @param constantPool
* @return - the pcode string
*/
public static String getPcodeForGetField(int index, AbstractConstantPoolInfoJava[] constantPool) {
public static String getPcodeForGetField(int index,
AbstractConstantPoolInfoJava[] constantPool) {
StringBuilder pCode = new StringBuilder();
String descriptor = getDescriptorForFieldRef(constantPool, index);
switch (descriptor.charAt(0)){
switch (descriptor.charAt(0)) {
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP);
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
break;
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1);
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break;
case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP);
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1);
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break;
case DescriptorDecoder.BASE_TYPE_CHAR: //char
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP);
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1);
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break;
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP);
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1);
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break;
case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension
case DescriptorDecoder.BASE_TYPE_FLOAT: //float
case DescriptorDecoder.BASE_TYPE_INT: //int
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 4,
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 4, TEMP_1);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break;
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
case DescriptorDecoder.BASE_TYPE_LONG: //long
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 8, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitPushCat2Value(pCode,VALUE);
break;
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 8,
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 8, TEMP_1);
PcodeTextEmitter.emitPushCat2Value(pCode, VALUE);
break;
default:
throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
}
@ -215,64 +270,81 @@ public class ReferenceMethods {
* @param constantPool - the constant pool
* @return - the pcode
*/
public static String getPcodeForPutField(int index, AbstractConstantPoolInfoJava[] constantPool) {
public static String getPcodeForPutField(int index,
AbstractConstantPoolInfoJava[] constantPool) {
StringBuilder pCode = new StringBuilder();
//determine the computational category and push a value of the correct size onto the operand stack
String descriptor = getDescriptorForFieldRef(constantPool, index);
switch (descriptor.charAt(0)){
switch (descriptor.charAt(0)) {
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET, TEMP);
break;
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET,
TEMP_1);
break;
case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET, TEMP);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET,
TEMP_1);
break;
case DescriptorDecoder.BASE_TYPE_CHAR: //char
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET, TEMP);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET,
TEMP_1);
break;
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET, TEMP);
break;
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET,
TEMP_1);
break;
case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension
case DescriptorDecoder.BASE_TYPE_FLOAT: //float
case DescriptorDecoder.BASE_TYPE_INT: //int
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, FIELD_OFFSET, NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, FIELD_OFFSET,
NEW_VALUE);
break;
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
case DescriptorDecoder.BASE_TYPE_LONG: //long
PcodeTextEmitter.emitPopCat2Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, FIELD_OFFSET, NEW_VALUE);
break;
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, FIELD_OFFSET,
NEW_VALUE);
break;
default:
throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
}
return pCode.toString();
/*JavaComputationalCategory category = DescriptorDecoder.getComputationalCategoryOfDescriptor(descriptor);
switch (category){
case CAT_1:
@ -295,21 +367,21 @@ public class ReferenceMethods {
return pCode.toString();*/
}
/**
* Returns the descriptor of a field reference in the constant pool
* @param constantPool
* @param index
* @return
*/
static String getDescriptorForFieldRef(AbstractConstantPoolInfoJava[] constantPool, int index){
ConstantPoolFieldReferenceInfo fieldRef = (ConstantPoolFieldReferenceInfo) constantPool[index];
static String getDescriptorForFieldRef(AbstractConstantPoolInfoJava[] constantPool, int index) {
ConstantPoolFieldReferenceInfo fieldRef =
(ConstantPoolFieldReferenceInfo) constantPool[index];
int nameAndTypeIndex = fieldRef.getNameAndTypeIndex();
ConstantPoolNameAndTypeInfo nameAndTypeInfo = (ConstantPoolNameAndTypeInfo) constantPool[nameAndTypeIndex];
ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
return descriptorInfo.getString();
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
(ConstantPoolNameAndTypeInfo) constantPool[nameAndTypeIndex];
ConstantPoolUtf8Info descriptorInfo =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
return descriptorInfo.getString();
}
}

View File

@ -1,67 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.pcodeInject;
/**
*
* This is a utility class for generating pcode for the lookupswitch operation.
*
* This class is evolving and may eventually be replaced.
*
*/
import java.io.IOException;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.MemoryByteProvider;
import ghidra.program.model.lang.InjectContext;
import ghidra.program.model.listing.Program;
public class SwitchMethods {
static final String KEY = "key";
static final String SWITCH_TARGET = "switch_target";
public static String getPcodeForLookupSwitch(InjectContext injectContext, Program program) throws IOException {
StringBuilder pCode = new StringBuilder();
int defaultAddr = (int) injectContext.inputlist.get(0).getOffset();
int numPairs = (int) injectContext.inputlist.get(1).getOffset();
int padding = (int) injectContext.inputlist.get(2).getOffset();
PcodeTextEmitter.emitPopCat1Value(pCode, KEY);
int target = (int) (injectContext.baseAddr.getOffset() + defaultAddr);
PcodeTextEmitter.emitAssignConstantToRegister(pCode, SWITCH_TARGET, target);
ByteProvider provider = new MemoryByteProvider(program.getMemory(),injectContext.baseAddr);
byte[] bytes = provider.readBytes(1 + padding + 8, 8 * numPairs);
for (int i = 0, length = bytes.length ; i < length; i += 8){
int match = ((bytes[i] << 24) & 0xff000000) | ((bytes[i+1] << 16) & 0xff0000) | ((bytes[i+2] <<8) & 0xff00) | (bytes[i+3] & 0xff);
int offset = ((bytes[i+4] << 24) & 0xff000000) | ((bytes[i+5] << 16) & 0xff0000) | ((bytes[i+6] <<8) & 0xff00) | (bytes[i+7] & 0xff);
target = (int) (injectContext.baseAddr.getOffset() + offset);
pCode.append("if (key != " + match +") goto <test"+i+">;\n");
pCode.append(SWITCH_TARGET);
pCode.append(" = inst_start + " +offset+ ";\n");
//uncomment this to have the decompiler display multiple switch(address) statements
//pCode.append("goto [switch_target];\n");
PcodeTextEmitter.emitLabelDefinition(pCode, "test"+i);
}
pCode.append("SP=SP;\n");
provider.close();
return pCode.toString();
}
}

View File

@ -17,15 +17,22 @@ package ghidra.javaclass.analyzers;
import java.util.*;
import org.apache.commons.lang3.StringUtils;
import ghidra.app.cmd.comments.SetCommentCmd;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.cmd.label.AddLabelCmd;
import ghidra.app.cmd.refs.AssociateSymbolCmd;
import ghidra.app.plugin.core.analysis.AnalysisWorker;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.services.AnalysisPriority;
import ghidra.app.services.AnalyzerType;
import ghidra.app.util.bin.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.JavaLoader;
import ghidra.framework.cmd.CompoundCmd;
import ghidra.framework.options.Options;
import ghidra.javaclass.flags.MethodsInfoAccessFlags;
import ghidra.javaclass.format.*;
import ghidra.javaclass.format.attributes.*;
import ghidra.javaclass.format.constantpool.*;
@ -37,10 +44,9 @@ import ghidra.program.model.listing.*;
import ghidra.program.model.listing.Function.FunctionUpdateType;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.RefType;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
import ghidra.program.model.symbol.*;
import ghidra.util.Msg;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker {
@ -108,7 +114,7 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
TaskMonitor monitor) throws Exception {
Address address =
program.getAddressFactory().getAddressSpace("constantPool").getMinAddress();
program.getAddressFactory().getAddressSpace(JavaLoader.CONSTANT_POOL).getMinAddress();
ByteProvider provider = new MemoryByteProvider(program.getMemory(), address);
BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian());
@ -130,7 +136,7 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
markupFields(program, classFile, monitor);
markupMethods(program, classFile, monitor);
disassembleMethods(program, classFile, monitor);
labelOperands(program, classFile);
processInstructions(program, constantPoolData, classFile, monitor);
recordJavaVersionInfo(program, classFile);
BasicCompilerSpec.enableJavaLanguageDecompilation(program);
return true;
@ -157,10 +163,10 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
/**
* Create datatypes for all classes mentioned in the constant pool
* @param program
* @param classFile
* @param monitor
* @param messageLog
* @param program program file
* @param classFile ClassFileJava associated with {@code program}
* @param monitor for canceling analysis
* @param messageLog for logging messages
*/
private void createProgramDataTypes(Program program, ClassFileJava classFile,
TaskMonitor monitor, MessageLog messageLog) {
@ -264,7 +270,19 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
javaVersion = "1.8";
break;
case 53:
javaVersion = "1.9";
javaVersion = "9";
break;
case 54:
javaVersion = "10";
break;
case 55:
javaVersion = "11";
break;
case 56:
javaVersion = "12";
break;
case 57:
javaVersion = "13";
break;
default:
javaVersion = "Unknown";
@ -294,7 +312,7 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
AbstractConstantPoolInfoJava[] constantPool, Map<Integer, Integer> indexMap) {
AbstractAttributeInfo[] attributes = classFile.getAttributes();
for (AbstractAttributeInfo attribute : attributes) {
short nameIndex = attribute.getAttributeNameIndex();
int nameIndex = attribute.getAttributeNameIndex();
AbstractConstantPoolInfoJava poolEntry = classFile.getConstantPool()[nameIndex];
if (poolEntry instanceof ConstantPoolUtf8Info) {
String name = ((ConstantPoolUtf8Info) poolEntry).getString();
@ -388,24 +406,179 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
return indexMap;
}
private void labelOperands(Program program, ClassFileJava classFile) {
InstructionIterator instructionIt =
program.getListing().getInstructions(toAddr(program, 0x10000), true);
while (instructionIt.hasNext()) {
Instruction instruction = instructionIt.next();
private void processInstructions(Program program, Data constantPoolData,
ClassFileJava classFile, TaskMonitor monitor) throws CancelledException {
Scalar opValue = instruction.getScalar(0);
if (opValue == null) {
InstructionIterator instructionIt =
program.getListing().getInstructions(toAddr(program, JavaLoader.CODE_OFFSET), true);
AbstractConstantPoolInfoJava[] constantPool = classFile.getConstantPool();
Map<Integer, Integer> indexMap = getIndexMap(constantPool);
BootstrapMethods[] bootstrapMethods =
getBootStrapMethodAttribute(classFile, constantPool, indexMap);
for (Instruction instruction : instructionIt) {
monitor.checkCanceled();
if (!hasConstantPoolReference(instruction.getMnemonicString())) {
continue;
}
AbstractConstantPoolInfoJava[] constantPool = classFile.getConstantPool();
int index = (int) (opValue.getValue() & 0xFFFFFFFF);
String opMarkup = getOperandMarkup(program, constantPool, index);
instruction.setComment(CodeUnit.EOL_COMMENT, opMarkup);
if (instruction.getMnemonicString().equals("invokedynamic")) {
addInvokeDynamicComments(program, constantPool, indexMap, bootstrapMethods,
instruction);
}
int index = (int) (instruction.getScalar(0).getValue() & 0xFFFFFFFF);
Data referredData = constantPoolData.getComponent(indexMap.get(index));
instruction.addOperandReference(0, referredData.getAddress(), RefType.DATA,
SourceType.ANALYSIS);
CompoundCmd cmd = new CompoundCmd("Add constant pool reference");
String constantPoolLabel = "CPOOL[" + index + "]";
cmd.add(
new AddLabelCmd(referredData.getAddress(), constantPoolLabel, SourceType.ANALYSIS));
Reference ref = instruction.getOperandReferences(0)[0];
cmd.add(new AssociateSymbolCmd(ref, constantPoolLabel));
cmd.applyTo(program);
}
}
private void addInvokeDynamicComments(Program program,
AbstractConstantPoolInfoJava[] constantPool, Map<Integer, Integer> indexMap,
BootstrapMethods[] bootstrapMethods, Instruction instruction) {
StringBuffer sb = new StringBuffer("Bootstrap Method: \n");
Address addr = instruction.getAddress();
int index = (int) (instruction.getScalar(0).getValue() & 0xFFFFFFFF);
ConstantPoolInvokeDynamicInfo dynamicInfo =
(ConstantPoolInvokeDynamicInfo) constantPool[index];
int bootstrapIndex = dynamicInfo.getBootstrapMethodAttrIndex();
appendMethodHandleInfo(sb, constantPool,
bootstrapMethods[bootstrapIndex].getBootstrapMethodsReference());
sb.append("\n");
int argNum = 0;
for (int i = 0; i < bootstrapMethods[bootstrapIndex].getNumberOfBootstrapArguments(); i++) {
sb.append(" static arg " + argNum++ + ": ");
appendLoadableInfo(sb, constantPool,
bootstrapMethods[bootstrapIndex].getBootstrapArgumentsEntry(i));
if (argNum < bootstrapMethods[bootstrapIndex].getNumberOfBootstrapArguments()) {
sb.append("\n");
}
}
program.getListing().setComment(addr, CodeUnit.PLATE_COMMENT, sb.toString());
}
private void appendMethodHandleInfo(StringBuffer sb,
AbstractConstantPoolInfoJava[] constantPool, int argIndex) {
ConstantPoolMethodHandleInfo methodHandle =
(ConstantPoolMethodHandleInfo) constantPool[argIndex];
AbstractConstantPoolInfoJava handleRef = constantPool[methodHandle.getReferenceIndex()];
if (handleRef instanceof ConstantPoolFieldReferenceInfo) {
ConstantPoolFieldReferenceInfo fieldRef = (ConstantPoolFieldReferenceInfo) handleRef;
ConstantPoolClassInfo classInfo =
(ConstantPoolClassInfo) constantPool[fieldRef.getClassIndex()];
ConstantPoolUtf8Info utf8 =
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
sb.append(utf8.getString());
sb.append(".");
ConstantPoolNameAndTypeInfo ntInfo =
(ConstantPoolNameAndTypeInfo) constantPool[fieldRef.getNameAndTypeIndex()];
utf8 = (ConstantPoolUtf8Info) constantPool[ntInfo.getNameIndex()];
sb.append(utf8.getString());
}
if (handleRef instanceof ConstantPoolMethodReferenceInfo) {
ConstantPoolMethodReferenceInfo methodRef = (ConstantPoolMethodReferenceInfo) handleRef;
ConstantPoolClassInfo classRef =
(ConstantPoolClassInfo) constantPool[methodRef.getClassIndex()];
ConstantPoolUtf8Info utf8 =
(ConstantPoolUtf8Info) constantPool[classRef.getNameIndex()];
sb.append(utf8.getString() + ".");
ConstantPoolNameAndTypeInfo nameAndType =
(ConstantPoolNameAndTypeInfo) constantPool[methodRef.getNameAndTypeIndex()];
utf8 = (ConstantPoolUtf8Info) constantPool[nameAndType.getNameIndex()];
sb.append(utf8.getString());
}
if (handleRef instanceof ConstantPoolInterfaceMethodReferenceInfo) {
ConstantPoolInterfaceMethodReferenceInfo mrInfo =
(ConstantPoolInterfaceMethodReferenceInfo) handleRef;
ConstantPoolClassInfo classRef =
(ConstantPoolClassInfo) constantPool[mrInfo.getClassIndex()];
ConstantPoolUtf8Info utf8 =
(ConstantPoolUtf8Info) constantPool[classRef.getNameIndex()];
sb.append(utf8.getString() + ".");
ConstantPoolNameAndTypeInfo nameAndType =
(ConstantPoolNameAndTypeInfo) constantPool[mrInfo.getNameAndTypeIndex()];
utf8 = (ConstantPoolUtf8Info) constantPool[nameAndType.getNameIndex()];
sb.append(utf8.getString());
}
}
private void appendLoadableInfo(StringBuffer sb, AbstractConstantPoolInfoJava[] constantPool,
int argIndex) {
AbstractConstantPoolInfoJava cpoolInfo = constantPool[argIndex];
if (cpoolInfo instanceof ConstantPoolIntegerInfo) {
ConstantPoolIntegerInfo intInfo = (ConstantPoolIntegerInfo) cpoolInfo;
sb.append(intInfo.getValue());
return;
}
if (cpoolInfo instanceof ConstantPoolFloatInfo) {
ConstantPoolFloatInfo floatInfo = (ConstantPoolFloatInfo) cpoolInfo;
sb.append(floatInfo.getValue());
return;
}
if (cpoolInfo instanceof ConstantPoolLongInfo) {
ConstantPoolLongInfo longInfo = (ConstantPoolLongInfo) cpoolInfo;
sb.append(longInfo.getValue());
return;
}
if (cpoolInfo instanceof ConstantPoolDoubleInfo) {
ConstantPoolDoubleInfo doubleInfo = (ConstantPoolDoubleInfo) cpoolInfo;
sb.append(doubleInfo.getValue());
return;
}
if (cpoolInfo instanceof ConstantPoolClassInfo) {
ConstantPoolClassInfo classInfo = (ConstantPoolClassInfo) cpoolInfo;
ConstantPoolUtf8Info className =
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
sb.append(className.getString());
return;
}
if (cpoolInfo instanceof ConstantPoolStringInfo) {
ConstantPoolStringInfo stringInfo = (ConstantPoolStringInfo) cpoolInfo;
ConstantPoolUtf8Info utf8 =
(ConstantPoolUtf8Info) constantPool[stringInfo.getStringIndex()];
sb.append("\"");
sb.append(utf8.getString());
sb.append("\"");
return;
}
if (cpoolInfo instanceof ConstantPoolMethodHandleInfo) {
appendMethodHandleInfo(sb, constantPool, argIndex);
return;
}
if (cpoolInfo instanceof ConstantPoolMethodTypeInfo) {
ConstantPoolMethodTypeInfo mtInfo = (ConstantPoolMethodTypeInfo) cpoolInfo;
ConstantPoolUtf8Info descriptor =
(ConstantPoolUtf8Info) constantPool[mtInfo.getDescriptorIndex()];
sb.append(descriptor.getString());
return;
}
if (cpoolInfo instanceof ConstantPoolDynamicInfo) {
ConstantPoolDynamicInfo dynamicInfo = (ConstantPoolDynamicInfo) cpoolInfo;
ConstantPoolNameAndTypeInfo ntInfo =
(ConstantPoolNameAndTypeInfo) constantPool[dynamicInfo.getNameAndTypeIndex()];
ConstantPoolUtf8Info name = (ConstantPoolUtf8Info) constantPool[ntInfo.getNameIndex()];
sb.append(name.getString());
return;
}
Msg.showWarn(this, null, "Unsupported Constant Pool Type", cpoolInfo.getClass().getName());
return;
}
private void markupFields(Program program, ClassFileJava classFile, TaskMonitor monitor) {
AbstractConstantPoolInfoJava[] constantPool = classFile.getConstantPool();
@ -479,290 +652,6 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
}
}
private String getOperandMarkup(Program program, AbstractConstantPoolInfoJava[] constantPool,
int index) {
if (index >= constantPool.length || index < 0) {
// TODO: < 0 can happen with if<cond> branches backwards. Goto's should be handled.
return "";
}
AbstractConstantPoolInfoJava constantPoolInfo = constantPool[index];
String opMarkup = "";
//
// if (monitor.isCancelled()) {
// break;
// }
if (constantPoolInfo != null) {
switch (constantPoolInfo.getTag()) {
case ConstantPoolTagsJava.CONSTANT_Class: {
ConstantPoolClassInfo info = (ConstantPoolClassInfo) constantPoolInfo;
ConstantPoolUtf8Info utf8 =
(ConstantPoolUtf8Info) constantPool[info.getNameIndex()];
opMarkup = utf8.getString().replaceAll("/", ".");
break;
}
case ConstantPoolTagsJava.CONSTANT_Double: {
ConstantPoolDoubleInfo info = (ConstantPoolDoubleInfo) constantPoolInfo;
double value = info.getValue();
opMarkup = Double.toString(value);
break;
}
case ConstantPoolTagsJava.CONSTANT_Fieldref: {
ConstantPoolFieldReferenceInfo info =
(ConstantPoolFieldReferenceInfo) constantPoolInfo;
ConstantPoolClassInfo classInfo =
(ConstantPoolClassInfo) constantPool[info.getClassIndex()];
ConstantPoolUtf8Info className =
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
(ConstantPoolNameAndTypeInfo) constantPool[info.getNameAndTypeIndex()];
ConstantPoolUtf8Info fieldName =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getNameIndex()];
ConstantPoolUtf8Info fieldDescriptor =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
opMarkup = className.getString().replaceAll("/", ".") + "." +
fieldName.getString() + " : " + DescriptorDecoder.getTypeNameFromDescriptor(
fieldDescriptor.getString(), true, true);
break;
}
case ConstantPoolTagsJava.CONSTANT_Float: {
ConstantPoolFloatInfo info = (ConstantPoolFloatInfo) constantPoolInfo;
float value = info.getValue();
opMarkup = Float.toString(value);
break;
}
case ConstantPoolTagsJava.CONSTANT_Integer: {
ConstantPoolIntegerInfo info = (ConstantPoolIntegerInfo) constantPoolInfo;
int value = info.getValue();
opMarkup = Integer.toString(value);
break;
}
case ConstantPoolTagsJava.CONSTANT_InterfaceMethodref: {
ConstantPoolInterfaceMethodReferenceInfo info =
(ConstantPoolInterfaceMethodReferenceInfo) constantPoolInfo;
ConstantPoolClassInfo classInfo =
(ConstantPoolClassInfo) constantPool[info.getClassIndex()];
ConstantPoolUtf8Info className =
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
(ConstantPoolNameAndTypeInfo) constantPool[info.getNameAndTypeIndex()];
ConstantPoolUtf8Info interfaceName =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getNameIndex()];
ConstantPoolUtf8Info interfaceDescriptor =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
String descriptor = interfaceDescriptor.getString();
String params = getParameters(descriptor);
String returnType =
DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor,
program.getDataTypeManager()).getName();
opMarkup = className.getString().replaceAll("/", ".") + "." +
interfaceName.getString() + params + " : " + returnType;
break;
}
case ConstantPoolTagsJava.CONSTANT_InvokeDynamic: {
ConstantPoolInvokeDynamicInfo info =
(ConstantPoolInvokeDynamicInfo) constantPoolInfo;
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
(ConstantPoolNameAndTypeInfo) constantPool[info.getNameAndTypeIndex()];
ConstantPoolUtf8Info name =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getNameIndex()];
opMarkup = name.getString();
break;
}
case ConstantPoolTagsJava.CONSTANT_Long: {
ConstantPoolLongInfo info = (ConstantPoolLongInfo) constantPoolInfo;
long value = info.getValue();
opMarkup = Long.toString(value);
break;
}
case ConstantPoolTagsJava.CONSTANT_MethodHandle: {
ConstantPoolMethodHandleInfo info =
(ConstantPoolMethodHandleInfo) constantPoolInfo;
if (info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_getField ||
info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_getStatic ||
info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_putField ||
info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_putStatic) {
ConstantPoolFieldReferenceInfo field =
(ConstantPoolFieldReferenceInfo) constantPool[info.getReferenceIndex()];
ConstantPoolClassInfo classInfo =
(ConstantPoolClassInfo) constantPool[field.getClassIndex()];
ConstantPoolUtf8Info className =
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
(ConstantPoolNameAndTypeInfo) constantPool[field.getNameAndTypeIndex()];
ConstantPoolUtf8Info fieldName =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getNameIndex()];
ConstantPoolUtf8Info fieldInfo =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
String descriptor = fieldInfo.getString();
String params = getParameters(descriptor);
String returnType =
DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor,
program.getDataTypeManager()).getName();
opMarkup = className.getString().replaceAll("/", ".") + "." +
fieldName.getString() + params + " : " + returnType;
}
else if (info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_invokeVirtual ||
info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_invokeStatic ||
info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_invokeSpecial ||
info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_newInvokeSpecial) {
ConstantPoolMethodReferenceInfo method =
(ConstantPoolMethodReferenceInfo) constantPool[info.getReferenceIndex()];
ConstantPoolClassInfo classInfo =
(ConstantPoolClassInfo) constantPool[method.getClassIndex()];
ConstantPoolUtf8Info className =
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
(ConstantPoolNameAndTypeInfo) constantPool[method.getNameAndTypeIndex()];
ConstantPoolUtf8Info methodName =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getNameIndex()];
ConstantPoolUtf8Info methodInfo =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
String descriptor = methodInfo.getString();
String params = getParameters(descriptor);
String returnType =
DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor,
program.getDataTypeManager()).getName();
opMarkup = className.getString().replaceAll("/", ".") + "." +
methodName.getString() + params + " : " + returnType;
}
else if (info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_invokeInterface) {
ConstantPoolInterfaceMethodReferenceInfo interfaceMethod =
(ConstantPoolInterfaceMethodReferenceInfo) constantPool[info.getReferenceIndex()];
ConstantPoolClassInfo classInfo =
(ConstantPoolClassInfo) constantPool[interfaceMethod.getClassIndex()];
ConstantPoolUtf8Info className =
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
(ConstantPoolNameAndTypeInfo) constantPool[interfaceMethod.getNameAndTypeIndex()];
ConstantPoolUtf8Info interfaceMethodName =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getNameIndex()];
ConstantPoolUtf8Info interfaceMethodInfo =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
String descriptor = interfaceMethodInfo.getString();
String params = getParameters(descriptor);
String returnType =
DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor,
program.getDataTypeManager()).getName();
opMarkup = className.getString().replaceAll("/", ".") + "." +
interfaceMethodName.getString() + params + " : " + returnType;
}
break;
}
case ConstantPoolTagsJava.CONSTANT_Methodref: {
ConstantPoolMethodReferenceInfo info =
(ConstantPoolMethodReferenceInfo) constantPoolInfo;
ConstantPoolClassInfo classInfo =
(ConstantPoolClassInfo) constantPool[info.getClassIndex()];
ConstantPoolUtf8Info className =
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
(ConstantPoolNameAndTypeInfo) constantPool[info.getNameAndTypeIndex()];
ConstantPoolUtf8Info methodName =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getNameIndex()];
ConstantPoolUtf8Info methodDescriptor =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
ConstantPoolUtf8Info methodInfo =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
String descriptor = methodInfo.getString();
String params = getParameters(descriptor);
String returnType =
DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor,
program.getDataTypeManager()).getName();
if (methodName.getString().equals("<init>")) {
opMarkup = className.getString() + params;
}
else {
opMarkup = className.getString().replaceAll("/", ".") + "." +
methodName.getString() + params + " : " + returnType;
}
break;
}
case ConstantPoolTagsJava.CONSTANT_MethodType: {
ConstantPoolMethodTypeInfo info = (ConstantPoolMethodTypeInfo) constantPoolInfo;
ConstantPoolUtf8Info methodType =
(ConstantPoolUtf8Info) constantPool[info.getDescriptorIndex()];
opMarkup = methodType.getString();
break;
}
case ConstantPoolTagsJava.CONSTANT_NameAndType: {
ConstantPoolNameAndTypeInfo info =
(ConstantPoolNameAndTypeInfo) constantPoolInfo;
ConstantPoolUtf8Info fieldName =
(ConstantPoolUtf8Info) constantPool[info.getNameIndex()];
ConstantPoolUtf8Info fieldDescriptor =
(ConstantPoolUtf8Info) constantPool[info.getDescriptorIndex()];
opMarkup = fieldName.getString();
break;
}
case ConstantPoolTagsJava.CONSTANT_String: {
ConstantPoolStringInfo info = (ConstantPoolStringInfo) constantPoolInfo;
ConstantPoolUtf8Info utf8 =
(ConstantPoolUtf8Info) constantPool[info.getStringIndex()];
opMarkup = utf8.toString();
break;
}
case ConstantPoolTagsJava.CONSTANT_Utf8: {
ConstantPoolUtf8Info utf8 = (ConstantPoolUtf8Info) constantPoolInfo;
opMarkup = utf8.getString();
break;
}
}
}
return opMarkup;
}
private String getParameters(String descriptor) {
List<String> paramTypeNames = DescriptorDecoder.getTypeNameList(descriptor, true, true);
StringBuilder sb = new StringBuilder();
sb.append("(");
//don't append the last element of the list, which is the return type
for (int i = 0, max = paramTypeNames.size() - 1; i < max; ++i) {
sb.append(paramTypeNames.get(i));
if (i < max - 1) {
sb.append(", ");
}
}
sb.append(")");
return sb.toString();
}
@Override
public String getWorkerName() {
return getName();
@ -780,11 +669,11 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
* Sets the name, return type, and parameter types of a method using the information in the constant pool.
* Also overrides the signatures on all method invocations made within the method body.
* @param function - the function (method)
* @param methodDescriptor - the name of the memory block containing the function's code. It is assumed that blockName
* is the concatenation of the method name and the descriptor
* @param constantPool
* @throws DuplicateNameException
* @throws InvalidInputException
* @param methodInfo information about the method from the constant pool
* @param classFile class file containing the method
* @param dtManager data type manager for program
* @throws DuplicateNameException if there are duplicate name issues with function or parameter names
* @throws InvalidInputException if a function or parameter name is invalid
*/
private void setFunctionInfo(Function function, MethodInfoJava methodInfo,
ClassFileJava classFile, DataTypeManager dtManager)
@ -833,5 +722,60 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
}
function.replaceParameters(params, FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true,
SourceType.ANALYSIS);
createAccessFlagComments(function, methodInfo, classFile);
}
private void createAccessFlagComments(Function function, MethodInfoJava methodInfo,
ClassFileJava classFile) {
int flags = methodInfo.getAccessFlags();
StringBuffer sb = new StringBuffer();
for (MethodsInfoAccessFlags f : MethodsInfoAccessFlags.values()) {
if ((flags & f.getValue()) != 0) {
sb.append(" " + f.name() + "\n");
}
}
if (!StringUtils.isEmpty(sb)) {
sb.insert(0, "Flags:\n");
}
sb.append("\n");
sb.append(methodInfo.getMethodSignature(classFile));
Listing listing = function.getProgram().getListing();
Address entryPoint = function.getEntryPoint();
listing.setComment(entryPoint, CodeUnit.PLATE_COMMENT, sb.toString());
}
private boolean hasConstantPoolReference(String mnemonic) {
switch (mnemonic) {
case ("anewarray"):
case ("checkcast"):
case ("getfield"):
case ("getstatic"):
case ("instanceof"):
case ("invokedynamic"):
case ("invokeinterface"):
case ("invokespecial"):
case ("invokestatic"):
case ("invokevirtual"):
case ("multianewarray"):
case ("ldc"):
case ("ldc_w"):
case ("ldc2_w"):
case ("new"):
case ("putfield"):
case ("putstatic"):
return true;
default:
return false;
}
}
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,23 +15,33 @@
*/
package ghidra.javaclass.flags;
public final class ClassFileFlags {
public enum ClassFileFlags {
/** Declared public; may be accessed from outside its package. */
public final static short ACC_PUBLIC = 0x0001;
ACC_PUBLIC(0x0001),
/** Declared final; no subclasses allowed. */
public final static short ACC_FINAL = 0x0010;
ACC_FINAL(0x0010),
/** Treat superclass methods specially when invoked by the invokespecial instruction. */
public final static short ACC_SUPER = 0x0020;
ACC_SUPER(0x0020),
/** Is an interface, not a class. */
public final static short ACC_INTERFACE = 0x0200;
ACC_INTERFACE(0x0200),
/** Declared abstract; must not be instantiated. */
public final static short ACC_ABSTRACT = 0x0400;
ACC_ABSTRACT(0x0400),
/** Declared synthetic; not present in the source code. */
public final static short ACC_SYNTHETIC = 0x1000;
ACC_SYNTHETIC(0x1000),
/** Declared as an annotation type. */
public final static short ACC_ANNOTATION = 0x2000;
ACC_ANNOTATION(0x2000),
/** Declared as an enum type. */
public final static short ACC_ENUM = 0x4000;
ACC_ENUM(0x4000);
private int value;
private ClassFileFlags(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,25 +15,33 @@
*/
package ghidra.javaclass.flags;
final class FieldInfoAccessFlags {
public enum FieldInfoAccessFlags {
/** Declared public; may be accessed from outside its package. */
public final short ACC_PUBLIC = 0x0001;
ACC_PUBLIC(0x0001),
/** Declared private; usable only within the defining class. */
public final short ACC_PRIVATE = 0x0002;
ACC_PRIVATE(0x0002),
/** Declared protected; may be accessed within subclasses. */
public final short ACC_PROTECTED = 0x0004;
ACC_PROTECTED(0x0004),
/** Declared static. */
public final short ACC_STATIC = 0x0008;
ACC_STATIC(0x0008),
/** Declared final; never directly assigned to after object construction (JLS ?17.5). */
public final short ACC_FINAL = 0x0010;
ACC_FINAL(0x0010),
/** Declared volatile; cannot be cached. */
public final short ACC_VOLATILE = 0x0040;
ACC_VOLATILE(0x00400),
/** Declared transient; not written or read by a persistent object manager. */
public final short ACC_TRANSIENT = 0x0080;
ACC_TRANSIENT(0x0080),
/** Declared synthetic; not present in the source code. */
public final short ACC_SYNTHETIC = 0x1000;
ACC_SYNTHETIC(0x1000),
/** Declared as an element of an enum. */
public final short ACC_ENUM = 0x4000;
ACC_ENUM(0x4000);
private int value;
private FieldInfoAccessFlags(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}

View File

@ -15,31 +15,81 @@
*/
package ghidra.javaclass.flags;
public final class MethodsInfoAccessFlags {
public enum MethodsInfoAccessFlags {
/** Declared public; may be accessed from outside its package. */
public final static short ACC_PUBLIC = 0x0001;
ACC_PUBLIC(0x0001),
/** Declared private; accessible only within the defining class. */
public final static short ACC_PRIVATE = 0x0002;
ACC_PRIVATE(0x0002),
/** Declared protected; may be accessed within subclasses. */
public final static short ACC_PROTECTED = 0x0004;
ACC_PROTECTED(0x0004),
/** Declared static. */
public final static short ACC_STATIC = 0x0008;
ACC_STATIC(0x0008),
/** Declared final; must not be overridden (5.4.5). */
public final static short ACC_FINAL = 0x0010;
ACC_FINAL(0x0010),
/** Declared synchronized; invocation is wrapped by a monitor use. */
public final static short ACC_SYNCHRONIZED = 0x0020;
ACC_SYNCHRONIZED(0x0020),
/** A bridge method, generated by the compiler. */
public final static short ACC_BRIDGE = 0x0040;
ACC_BRIDGE(0x0040),
/** Declared with variable number of arguments. */
public final static short ACC_VARARGS = 0x0080;
ACC_VARARGS(0x0080),
/** Declared native; implemented in a language other than Java. */
public final static short ACC_NATIVE = 0x0100;
ACC_NATIVE(0x0100),
/** Declared abstract; no implementation is provided. */
public final static short ACC_ABSTRACT = 0x0400;
ACC_ABSTRACT(0x0400),
/** Declared strictfp; floating-point mode is FP-strict. */
public final static short ACC_STRICT = 0x0800;
ACC_STRICT(0x0800),
/** Declared synthetic; not present in the source code. */
public final static short ACC_SYNTHETIC = 0x1000;
ACC_SYNTHETIC(0x1000);
private final int value;
private MethodsInfoAccessFlags(int value) {
this.value = value;
}
public int getValue() {
return value;
}
/**
* Return a text representation for a given set of access flags.
* Here are some examples:
* <DL>
* <DD><CODE>"public static final"</CODE>,</DD>
* <DD><CODE>"package private"</CODE>, or</DD>
* <DD><CODE>"protected transient"</CODE>.</DD>
* </DL>
* Note: only access flags that map to Java modifier keywords are returned.
* @param access the mask of flags denoting access permission.
* @return a text representation of the access flags.
*/
public static String toString(int access) {
StringBuffer stringBuffer = new StringBuffer();
if ((access & ACC_PUBLIC.value) == ACC_PUBLIC.value) {
stringBuffer.append("public ");
}
if ((access & ACC_PRIVATE.value) == ACC_PRIVATE.value) {
stringBuffer.append("private ");
}
if ((access & ACC_PROTECTED.value) == ACC_PROTECTED.value) {
stringBuffer.append("protected ");
}
if ((access & ACC_STATIC.value) == ACC_STATIC.value) {
stringBuffer.append("static ");
}
if ((access & ACC_FINAL.value) == ACC_FINAL.value) {
stringBuffer.append("final ");
}
if ((access & ACC_SYNCHRONIZED.value) == ACC_SYNCHRONIZED.value) {
stringBuffer.append("synchronized ");
}
if ((access & ACC_NATIVE.value) == ACC_NATIVE.value) {
stringBuffer.append("native ");
}
if ((access & ACC_ABSTRACT.value) == ACC_ABSTRACT.value) {
stringBuffer.append("abstract ");
}
return stringBuffer.toString().trim();
}
}

View File

@ -1,165 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.javaclass.format;
/**
* A utility class defining access flags and access utility methods.
* Access flags are as defined by the Java Virtual Machine Specification
* Second Edition, tables 4.1, 4.4, 4.5 and 4.7.
*/
public abstract class AccessFlagsJava {
/** Declared public, may be accessed from outside its package. */
public static final int PUBLIC = 0x0001;
/** Declared private, usable only within the defining class. */
public static final int PRIVATE = 0x0002;
/** Declared protected, may be accessed within subclasses. */
public static final int PROTECTED = 0x0004;
/** Declared static. */
public static final int STATIC = 0x0008;
/**
* Declared final. For classes this means no subclassing allowed.
* For fields it means no further assignment allowed after initialization.
* For methods it means that the method cannot be overridden.
*/
public static final int FINAL = 0x0010;
/** Declared synchronized; invocation is wrapped in a monitor lock. */
public static final int SYNCHRONIZED = 0x0020;
/**
* Treat superclass methods specially when invoked by the
* <i>invokespecial</i> instruction. This access only applies to
* classes, and shares the same value as SYNCHRONIZED.
*/
public static final int SUPER = 0x0020;
/** Declared volatile; cannot be cached. */
public static final int VOLATILE = 0x0040;
/** A bridge method, generated by the compiler. */
public static final int BRIDGE = 0x0040;
/**
* Declared transient; not written or read by a persistent object
* manager
*/
public static final int TRANSIENT = 0x0080;
/** Declared with a variable number of arguments. */
public static final int VARARGS = 0x0080;
/** Declared native; implemented in a language other than Java. */
public static final int NATIVE = 0x0100;
/** Is an interface, not a class. */
public static final int INTERFACE = 0x0200;
/** Declared abstract; must not be instantiated. */
public static final int ABSTRACT = 0x0400;
/** Declared strictfp; floating point mode is FP-strict. */
public static final int STRICT = 0x0800;
/** Declared synthetic, not present in the source file. */
public static final int SYNTHETIC = 0x1000;
/** Declared as an annotation type. */
public static final int ANNOTATION = 0x2000;
/**
* For classes, declared as an enum type. For fields, declared as
* an element of an enum.
*/
public static final int ENUM = 0x4000;
/**
* Return a text representation for a given set of access flags.
* Here are some examples:
* <DL>
* <DD><CODE>"public static final"</CODE>,</DD>
* <DD><CODE>"package private"</CODE>, or</DD>
* <DD><CODE>"protected transient"</CODE>.</DD>
* </DL>
* Note: only access flags that map to Java modifier keywords are returned.
* @param access the mask of flags denoting access permission.
* @return a text representation of the access flags.
*/
public static String toString( int access, boolean isClass ) {
StringBuffer stringBuffer = new StringBuffer();
if ( ( access & PUBLIC ) == PUBLIC ) {
stringBuffer.append( "public " );
}
if ( ( access & PRIVATE ) == PRIVATE ) {
stringBuffer.append( "private " );
}
if ( ( access & PROTECTED ) == PROTECTED ) {
stringBuffer.append( "protected " );
}
if ( ( access & STATIC ) == STATIC ) {
stringBuffer.append( "static " );
}
if ( ( access & FINAL ) == FINAL ) {
stringBuffer.append( "final " );
}
if ( !isClass && ( access & SYNCHRONIZED ) == SYNCHRONIZED ) {
stringBuffer.append( "synchronized " );
}
if ( ( access & VOLATILE ) == VOLATILE ) {
stringBuffer.append( "volatile ");
}
if ( ( access & TRANSIENT ) == TRANSIENT ) {
stringBuffer.append( "transient " );
}
if ( ( access & NATIVE) == NATIVE ) {
stringBuffer.append( "native " );
}
if ( ( access & ABSTRACT ) == ABSTRACT && ( access & INTERFACE ) == 0) {//interfaces are always abstract, so drop the abstract keyword
stringBuffer.append( "abstract " );
}
// trim trailing space
return stringBuffer.toString();
}
public static boolean isStatic( int access ) {
return ( ( access & STATIC ) == STATIC );
}
public static final boolean isPublic( int access ) {
return ( ( access & PUBLIC ) == PUBLIC );
}
public static final boolean isProtected( int access ) {
return ( ( access & PROTECTED ) == PROTECTED );
}
public static final boolean isPackagePrivate( int access ) {
return ( ( access & ( PUBLIC | PRIVATE | PROTECTED ) ) == 0 );
}
public static final boolean isPrivate( int access ) {
return ( ( access & PRIVATE ) == PRIVATE );
}
public static final boolean isInterface( int access ) {
return ( ( access & INTERFACE ) == INTERFACE );
}
}

View File

@ -15,22 +15,16 @@
*/
package ghidra.javaclass.format;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.javaclass.format.attributes.AbstractAttributeInfo;
import ghidra.javaclass.format.attributes.AttributeFactory;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
import ghidra.javaclass.format.constantpool.ConstantPoolDoubleInfo;
import ghidra.javaclass.format.constantpool.ConstantPoolFactory;
import ghidra.javaclass.format.constantpool.ConstantPoolLongInfo;
import ghidra.program.model.data.ArrayDataType;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.javaclass.format.constantpool.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -85,9 +79,9 @@ public class ClassFileJava implements StructConverter {
minorVersion = reader.readNextShort();
majorVersion = reader.readNextShort();
constantPoolCount = reader.readNextShort();
constantPool = new AbstractConstantPoolInfoJava[constantPoolCount];
constantPool = new AbstractConstantPoolInfoJava[getConstantPoolCount()];
//NOTE: start at index 1 per JVM specification!!!
for (int i = 1; i < constantPoolCount; i++) {
for (int i = 1; i < getConstantPoolCount(); i++) {
constantPool[i] = ConstantPoolFactory.get(reader);
//From section 4.4.5 of JVM specification:
@ -97,7 +91,7 @@ public class ClassFileJava implements StructConverter {
///located at index n+2. The constant_pool index n+1 must be valid but is considered
//unusable.
if (constantPool[i] instanceof ConstantPoolLongInfo ||
constantPool[i] instanceof ConstantPoolDoubleInfo) {
constantPool[i] instanceof ConstantPoolDoubleInfo) {
++i;
}
}
@ -105,20 +99,20 @@ public class ClassFileJava implements StructConverter {
thisClass = reader.readNextShort();
superClass = reader.readNextShort();
interfacesCount = reader.readNextShort();
interfaces = reader.readNextShortArray(interfacesCount);
interfaces = reader.readNextShortArray(getInterfacesCount());
fieldsCount = reader.readNextShort();
fields = new FieldInfoJava[fieldsCount];
for (int i = 0; i < fieldsCount; i++) {
fields = new FieldInfoJava[getFieldsCount()];
for (int i = 0; i < getFieldsCount(); i++) {
fields[i] = new FieldInfoJava(reader, this);
}
methodsCount = reader.readNextShort();
methods = new MethodInfoJava[methodsCount];
for (int i = 0; i < methodsCount; i++) {
methods = new MethodInfoJava[getMethodsCount()];
for (int i = 0; i < getMethodsCount(); i++) {
methods[i] = new MethodInfoJava(reader, this);
}
attributesCount = reader.readNextShort();
attributes = new AbstractAttributeInfo[attributesCount];
for (int i = 0; i < attributesCount; i++) {
attributes = new AbstractAttributeInfo[getAttributesCount()];
for (int i = 0; i < getAttributesCount(); i++) {
attributes[i] = AttributeFactory.get(reader, getConstantPool());
}
}
@ -173,8 +167,8 @@ public class ClassFileJava implements StructConverter {
* exception for constants of type long and double noted in ?4.4.5.
* @return the number of entries in the constant_pool table plus one
*/
public short getConstantPoolCount() {
return constantPoolCount;
public int getConstantPoolCount() {
return constantPoolCount & 0xffff;
}
/**
@ -207,8 +201,8 @@ public class ClassFileJava implements StructConverter {
* defined by this class file.
* @return a valid index into the constant_pool table to a CONSTANT_Class_info
*/
public short getThisClass() {
return thisClass;
public int getThisClass() {
return thisClass & 0xffff;
}
/**
@ -228,8 +222,8 @@ public class ClassFileJava implements StructConverter {
* must be a CONSTANT_Class_info structure representing the class Object.
* @return a valid index into the constant_pool table to a CONSTANT_Class_info
*/
public short getSuperClass() {
return superClass;
public int getSuperClass() {
return superClass & 0xffff;
}
/**
@ -237,8 +231,8 @@ public class ClassFileJava implements StructConverter {
* superinterfaces of this class or interface type.
* @return the number of direct superinterfaces of this class
*/
public short getInterfacesCount() {
return interfacesCount;
public int getInterfacesCount() {
return interfacesCount & 0xffff;
}
/**
@ -248,10 +242,11 @@ public class ClassFileJava implements StructConverter {
* CONSTANT_Class_info (?4.4.1) structure representing an interface that is a
* direct superinterface of this class or interface type, in the left-to-right order
* given in the source for the type.
* @return an array of interfaces
* @param i entry
* @return interface index
*/
public short[] getInterfaces() {
return interfaces;
public int getInterfacesEntry(int i) {
return interfaces[i] & 0xffff;
}
/**
@ -261,8 +256,8 @@ public class ClassFileJava implements StructConverter {
* interface type.
* @return the number of field_info structures in the fields table
*/
public short getFieldsCount() {
return fieldsCount;
public int getFieldsCount() {
return fieldsCount & 0xffff;
}
/**
@ -282,8 +277,8 @@ public class ClassFileJava implements StructConverter {
* structures in the methods table.
* @return the number of method_info structures in the methods table
*/
public short getMethodsCount() {
return methodsCount;
public int getMethodsCount() {
return methodsCount & 0xffff;
}
/**
@ -309,8 +304,8 @@ public class ClassFileJava implements StructConverter {
* in the attributes table of this class.
* @return the number of attributes in the attributes table
*/
public short getAttributesCount() {
return attributesCount;
public int getAttributesCount() {
return attributesCount & 0xffff;
}
/**
@ -370,14 +365,14 @@ public class ClassFileJava implements StructConverter {
structure.add(WORD, "super_class", null);
structure.add(WORD, "interfaces_count", null);
if (interfacesCount > 0) {
DataType array = new ArrayDataType(WORD, interfacesCount, WORD.getLength());
if (getInterfacesCount() > 0) {
DataType array = new ArrayDataType(WORD, getInterfacesCount(), WORD.getLength());
structure.add(array, "interfaces", null);
}
structure.add(WORD, "field_count", null);
if (fieldsCount > 0) {
if (getFieldsCount() > 0) {
Structure fieldStruct = new StructureDataType("fields", 0);
for (int i = 0; i < fields.length; ++i) {
fieldStruct.add(fields[i].toDataType(), "field_" + i, null);
@ -387,7 +382,7 @@ public class ClassFileJava implements StructConverter {
structure.add(WORD, "method_count", null);
if (methodsCount > 0) {
if (getMethodsCount() > 0) {
Structure methodsStruct = new StructureDataType("methods", 0);
for (int i = 0; i < methods.length; ++i) {
methodsStruct.add(methods[i].toDataType(), "methods_" + i, null);
@ -396,7 +391,7 @@ public class ClassFileJava implements StructConverter {
}
structure.add(WORD, "attributes_count", null);
if (attributesCount > 0){
if (getAttributesCount() > 0) {
Structure attributesStruct = new StructureDataType("attributes", 0);
for (int i = 0; i < attributes.length; ++i) {
attributesStruct.add(attributes[i].toDataType(), "attributes_" + i, null);

View File

@ -19,12 +19,7 @@ import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.pcodeInject.*;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
import ghidra.javaclass.format.constantpool.ConstantPoolInterfaceMethodReferenceInfo;
import ghidra.javaclass.format.constantpool.ConstantPoolInvokeDynamicInfo;
import ghidra.javaclass.format.constantpool.ConstantPoolMethodReferenceInfo;
import ghidra.javaclass.format.constantpool.ConstantPoolNameAndTypeInfo;
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
import ghidra.javaclass.format.constantpool.*;
import ghidra.program.model.data.*;
/**
@ -34,7 +29,6 @@ import ghidra.program.model.data.*;
*
*/
public class DescriptorDecoder {
public final static byte BASE_TYPE_BYTE = 'B';
@ -53,9 +47,8 @@ public class DescriptorDecoder {
public final static byte BASE_TYPE_ENUM = 'e';
public final static byte BASE_TYPE_ANNOTATION = '@';
//private constructor to enforce noninstantiability
private DescriptorDecoder(){
private DescriptorDecoder() {
throw new AssertionError();
}
@ -65,11 +58,11 @@ public class DescriptorDecoder {
* @param methodDescriptor
* @return
*/
public static int getStackPurge(String methodDescriptor){
public static int getStackPurge(String methodDescriptor) {
int stackPurge = 0;
List<JavaComputationalCategory> categories = getParameterCategories(methodDescriptor);
for (JavaComputationalCategory cat : categories){
switch (cat){
for (JavaComputationalCategory cat : categories) {
switch (cat) {
case CAT_1:
stackPurge += PcodeInjectLibraryJava.REFERENCE_SIZE;
break;
@ -83,31 +76,41 @@ public class DescriptorDecoder {
return stackPurge;
}
/**
* Returns the computational category of the return type of a method descriptor.
* @param methodDescriptor
* @return
*/
public static JavaComputationalCategory getReturnCategoryOfMethodDescriptor(String methodDescriptor){
public static JavaComputationalCategory getReturnCategoryOfMethodDescriptor(
String methodDescriptor) {
int closeParenIndex = methodDescriptor.indexOf(")");
if (closeParenIndex == -1){
if (closeParenIndex == -1) {
throw new IllegalArgumentException("Invalid method descriptor: " + methodDescriptor);
}
String returnDescriptor = methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
String returnDescriptor =
methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
return DescriptorDecoder.getComputationalCategoryOfDescriptor(returnDescriptor);
}
public static DataType getReturnTypeOfMethodDescriptor(String methodDescriptor, DataTypeManager dtManager){
/**
* Given a method descriptor, returns the data type of the return value of the corresponding
* method
* @param methodDescriptor descriptor of method
* @param dtManager data type manger for containing program
* @return data type of return value of method
*/
public static DataType getReturnTypeOfMethodDescriptor(String methodDescriptor,
DataTypeManager dtManager) {
int closeParenIndex = methodDescriptor.indexOf(")");
if (closeParenIndex == -1){
if (closeParenIndex == -1) {
throw new IllegalArgumentException("Invalid method descriptor: " + methodDescriptor);
}
String returnDescriptor = methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
if (returnDescriptor.startsWith("[")){
String returnDescriptor =
methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
if (returnDescriptor.startsWith("[")) {
return getPointerType(returnDescriptor, dtManager);
}
return DescriptorDecoder.getDataTypeOfDescriptor(returnDescriptor, dtManager);
return DescriptorDecoder.getDataTypeOfDescriptor(returnDescriptor, dtManager);
}
/**
@ -115,11 +118,12 @@ public class DescriptorDecoder {
* @param descriptor
* @return
*/
public static JavaComputationalCategory getComputationalCategoryOfDescriptor(String descriptor){
public static JavaComputationalCategory getComputationalCategoryOfDescriptor(
String descriptor) {
//all references to objects start with "L"
//all references to arrays start with "["
//all other descriptors are just one letter.
switch (descriptor.charAt(0)){
switch (descriptor.charAt(0)) {
case BASE_TYPE_BYTE: //signed byte
case BASE_TYPE_CHAR: //char
case BASE_TYPE_FLOAT: //float
@ -144,7 +148,8 @@ public class DescriptorDecoder {
* @param methodDescriptor
* @return
*/
public static List<String> getTypeNameList(String methodDescriptor, boolean fullyQualifiedName, boolean replaceSlash) {
public static List<String> getTypeNameList(String methodDescriptor, boolean fullyQualifiedName,
boolean replaceSlash) {
ArrayList<String> typeNames = new ArrayList<>();
int closeParenIndex = methodDescriptor.indexOf(")");
String argString = methodDescriptor.substring(1, closeParenIndex);
@ -152,79 +157,85 @@ public class DescriptorDecoder {
int currentPosition = 0;
int len = argString.length();
while (currentPosition < len){
while (currentPosition < len) {
String currentParam = argString.substring(currentPosition, currentPosition + 1);
if (currentParam.equals("[")){
if (currentParam.equals("[")) {
int initialBracket = currentPosition;
while (argString.charAt(currentPosition) == '['){
while (argString.charAt(currentPosition) == '[') {
currentPosition++;
}
//advance past the base type of the array
if (argString.charAt(currentPosition) == 'L'){
if (argString.charAt(currentPosition) == 'L') {
int semiColonIndex = argString.indexOf(";", currentPosition);
currentPosition = semiColonIndex + 1;
}
else{
else {
currentPosition++;
}
currentParamTypeName = getTypeNameFromDescriptor(argString.substring(initialBracket,currentPosition), fullyQualifiedName, replaceSlash);
currentParamTypeName =
getTypeNameFromDescriptor(argString.substring(initialBracket, currentPosition),
fullyQualifiedName, replaceSlash);
typeNames.add(currentParamTypeName);
continue;
}
}
//advance to next type in argString
//if it's a reference, it starts with L and ends with a ;
//otherwise you only need to advance one character
switch(currentParam){
switch (currentParam) {
case "L":
int semiColonIndex = argString.indexOf(";", currentPosition);
currentParamTypeName = getTypeNameFromDescriptor(argString.substring(currentPosition,semiColonIndex+1), fullyQualifiedName, replaceSlash);
currentParamTypeName = getTypeNameFromDescriptor(
argString.substring(currentPosition, semiColonIndex + 1),
fullyQualifiedName, replaceSlash);
currentPosition = semiColonIndex + 1; //advance past ;
break;
default:
currentParamTypeName = getTypeNameFromDescriptor(currentParam, fullyQualifiedName, replaceSlash);
currentPosition++;
currentParamTypeName =
getTypeNameFromDescriptor(currentParam, fullyQualifiedName, replaceSlash);
currentPosition++;
}
typeNames.add(currentParamTypeName);
}
//now add the the name of the return type
String returnType = methodDescriptor.substring(closeParenIndex+1, methodDescriptor.length());
String returnType =
methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
typeNames.add(getTypeNameFromDescriptor(returnType, fullyQualifiedName, replaceSlash));
return typeNames;
}
/**
* Returns the type name for a parameter descriptor
* @param descriptor
* @return
*/
public static String getTypeNameFromDescriptor(String descriptor, boolean fullyQualifiedName, boolean replaceSlash){
if (descriptor.startsWith("L")){
public static String getTypeNameFromDescriptor(String descriptor, boolean fullyQualifiedName,
boolean replaceSlash) {
if (descriptor.startsWith("L")) {
//leave off the initial L and the final ;
String name = descriptor.substring(1, descriptor.length()-1);
if (fullyQualifiedName){
if (replaceSlash){
return name.replace("/", ".");
String name = descriptor.substring(1, descriptor.length() - 1);
if (fullyQualifiedName) {
if (replaceSlash) {
return name.replace("/", ".");
}
return name;
}
int lastSlash = name.lastIndexOf("/");
//lastSlash+1 so the slash is not included in the name
return name.substring(lastSlash+1, name.length());
return name.substring(lastSlash + 1, name.length());
}
if (descriptor.startsWith("[")){
if (descriptor.startsWith("[")) {
int dimension = descriptor.lastIndexOf("[") + 1;
String baseType = getTypeNameFromDescriptor(descriptor.replace("[", ""), fullyQualifiedName, replaceSlash);
String baseType = getTypeNameFromDescriptor(descriptor.replace("[", ""),
fullyQualifiedName, replaceSlash);
StringBuilder sb = new StringBuilder(baseType);
for (int i = 0; i < dimension; ++i){
for (int i = 0; i < dimension; ++i) {
sb.append("[]");
}
return sb.toString();
}
switch (descriptor.charAt(0)){
switch (descriptor.charAt(0)) {
case BASE_TYPE_BYTE: //signed byte
return "byte";
case BASE_TYPE_CHAR: //char
@ -248,17 +259,18 @@ public class DescriptorDecoder {
}
}
public static DataType getReferenceTypeOfDescriptor(String descriptor, DataTypeManager dtManager, boolean includesLandSemi){
if (includesLandSemi){
descriptor = descriptor.substring(1, descriptor.length()-1);
public static DataType getReferenceTypeOfDescriptor(String descriptor,
DataTypeManager dtManager, boolean includesLandSemi) {
if (includesLandSemi) {
descriptor = descriptor.substring(1, descriptor.length() - 1);
}
String[] parts = descriptor.split("/");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < parts.length; i++){
for (String part : parts) {
sb.append(CategoryPath.DELIMITER_CHAR);
sb.append(parts[i]);
sb.append(part);
}
DataTypePath dataPath = new DataTypePath(sb.toString(), parts[parts.length-1]);
DataTypePath dataPath = new DataTypePath(sb.toString(), parts[parts.length - 1]);
DataType referencedType = dtManager.getDataType(dataPath);
return new PointerDataType(referencedType);
}
@ -268,44 +280,50 @@ public class DescriptorDecoder {
* @param descriptor
* @return
*/
public static DataType getDataTypeOfDescriptor(String descriptor, DataTypeManager dtManager){
public static DataType getDataTypeOfDescriptor(String descriptor, DataTypeManager dtManager) {
//all references to objects start with "L"
//all references to arrays start with "["
//all other descriptors are just one letter.
if (descriptor.startsWith("[")){
if (descriptor.startsWith("[")) {
return getPointerType(descriptor, dtManager);
}
switch (descriptor.charAt(0)){
case BASE_TYPE_BYTE:
switch (descriptor.charAt(0)) {
case BASE_TYPE_BYTE:
return SignedByteDataType.dataType;
case BASE_TYPE_CHAR:
case BASE_TYPE_CHAR:
return CharDataType.dataType;
case BASE_TYPE_INT:
case BASE_TYPE_INT:
return IntegerDataType.dataType;
case BASE_TYPE_SHORT:
return ShortDataType.dataType;
case BASE_TYPE_BOOLEAN:
case BASE_TYPE_BOOLEAN:
return BooleanDataType.dataType;
case BASE_TYPE_FLOAT:
case BASE_TYPE_FLOAT:
return FloatDataType.dataType;
case BASE_TYPE_REFERENCE: //object reference
return getReferenceTypeOfDescriptor(descriptor, dtManager, true);
case BASE_TYPE_DOUBLE:
case BASE_TYPE_DOUBLE:
return DoubleDataType.dataType;
case BASE_TYPE_LONG:
case BASE_TYPE_LONG:
return LongDataType.dataType;
case BASE_TYPE_VOID: //void (only for return types)
return DataType.VOID;
default:
throw new IllegalArgumentException("Invalid computational category: " + descriptor);
throw new IllegalArgumentException("Invalid type descriptor: " + descriptor);
}
}
public static DataType getPointerType(String descriptor, DataTypeManager dtManager){
/**
* Returns the data type of a pointer to the type represented by descriptor
* @param descriptor description of base type
* @param dtManager data type manager of program
* @return pointer data type
*/
public static DataType getPointerType(String descriptor, DataTypeManager dtManager) {
int lastBracket = descriptor.lastIndexOf("[");
String baseTypeOfArray = descriptor.substring(lastBracket+1, lastBracket+2);
String baseTypeOfArray = descriptor.substring(lastBracket + 1, lastBracket + 2);
DataType baseType = null;
switch (baseTypeOfArray.charAt(0)){
switch (baseTypeOfArray.charAt(0)) {
case BASE_TYPE_BYTE:
baseType = ArrayMethods.getArrayBaseType(JavaClassConstants.T_BYTE, dtManager);
break;
@ -334,7 +352,8 @@ public class DescriptorDecoder {
return dtManager.getPointer(DWordDataType.dataType);
default:
throw new IllegalArgumentException("Invalid array base type category: " + baseTypeOfArray);
throw new IllegalArgumentException(
"Invalid array base type category: " + baseTypeOfArray);
}
return dtManager.getPointer(baseType);
}
@ -345,17 +364,18 @@ public class DescriptorDecoder {
* @param methodDescriptor
* @return
*/
public static List<JavaComputationalCategory> getParameterCategories(String methodDescriptor){
public static List<JavaComputationalCategory> getParameterCategories(String methodDescriptor) {
ArrayList<JavaComputationalCategory> categories = new ArrayList<>();
int closeParenIndex = methodDescriptor.indexOf(")");
String argString = methodDescriptor.substring(1, closeParenIndex);
int currentPosition = 0;
int len = argString.length();
while (currentPosition < len){
while (currentPosition < len) {
String currentParam = argString.substring(currentPosition, currentPosition + 1);
JavaComputationalCategory category = DescriptorDecoder.getComputationalCategoryOfDescriptor(currentParam);
JavaComputationalCategory category =
DescriptorDecoder.getComputationalCategoryOfDescriptor(currentParam);
switch (category){
switch (category) {
case CAT_1:
categories.add(JavaComputationalCategory.CAT_1);
break;
@ -370,22 +390,22 @@ public class DescriptorDecoder {
//if it's a reference, it starts with L and ends with a ;
//if it's an array, it has one "[" for each dimension, then the type (which might be a reference)
//otherwise you only need to advance one character
switch(currentParam){
switch (currentParam) {
case "L":
int semiColonIndex = argString.indexOf(";", currentPosition);
currentPosition = semiColonIndex + 1; //advance past ;
break;
case "[":
//advance past all the ['s
while (argString.charAt(currentPosition) == '['){
while (argString.charAt(currentPosition) == '[') {
currentPosition++;
}
//advance past the base type of the array
if (argString.charAt(currentPosition) == 'L'){
if (argString.charAt(currentPosition) == 'L') {
semiColonIndex = argString.indexOf(";", currentPosition);
currentPosition = semiColonIndex + 1;
}
else{
else {
currentPosition++;
}
break;
@ -402,7 +422,8 @@ public class DescriptorDecoder {
* @param methodDescriptor
* @return
*/
public static List<DataType> getDataTypeList(String methodDescriptor, DataTypeManager dtManager) {
public static List<DataType> getDataTypeList(String methodDescriptor,
DataTypeManager dtManager) {
ArrayList<DataType> paramDataTypes = new ArrayList<>();
int closeParenIndex = methodDescriptor.indexOf(")");
String argString = methodDescriptor.substring(1, closeParenIndex);
@ -411,14 +432,14 @@ public class DescriptorDecoder {
int currentPosition = 0;
int len = argString.length();
String currentParam = null;
while (currentPosition < len){
while (currentPosition < len) {
int arrayDimensions = 0;
//if it's an array, decode the number of dimensions
while (argString.charAt(currentPosition) == '['){
while (argString.charAt(currentPosition) == '[') {
arrayDimensions++;
currentPosition++;
}
switch (argString.charAt(currentPosition)){
switch (argString.charAt(currentPosition)) {
case BASE_TYPE_BYTE:
case BASE_TYPE_CHAR:
case BASE_TYPE_SHORT:
@ -427,17 +448,17 @@ public class DescriptorDecoder {
case BASE_TYPE_FLOAT:
case BASE_TYPE_DOUBLE:
case BASE_TYPE_BOOLEAN:
currentParam = argString.substring(currentPosition, currentPosition+1);
currentParam = argString.substring(currentPosition, currentPosition + 1);
currentPosition++;
break;
case BASE_TYPE_REFERENCE:
int semiColonIndex = argString.indexOf(";", currentPosition);
currentParam = argString.substring(currentPosition, semiColonIndex+1);
currentParam = argString.substring(currentPosition, semiColonIndex + 1);
currentPosition = semiColonIndex + 1;
break;
}
currentParamType = getDataTypeOfDescriptor(currentParam, dtManager);
if (arrayDimensions > 0){
if (arrayDimensions > 0) {
paramDataTypes.add(dtManager.getPointer(currentParamType));
}
else {
@ -455,47 +476,91 @@ public class DescriptorDecoder {
* @param type
* @return
*/
public static String getDescriptorForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type){
public static String getDescriptorForInvoke(int offset,
AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) {
String descriptor = null;
int name_and_type_index = 0;
switch (type){
switch (type) {
case INVOKE_DYNAMIC:
ConstantPoolInvokeDynamicInfo dynamicInfo = (ConstantPoolInvokeDynamicInfo) constantPool[offset];
ConstantPoolInvokeDynamicInfo dynamicInfo =
(ConstantPoolInvokeDynamicInfo) constantPool[offset];
name_and_type_index = dynamicInfo.getNameAndTypeIndex();
break;
case INVOKE_INTERFACE:
ConstantPoolInterfaceMethodReferenceInfo interfaceInfo = (ConstantPoolInterfaceMethodReferenceInfo) constantPool[offset];
ConstantPoolInterfaceMethodReferenceInfo interfaceInfo =
(ConstantPoolInterfaceMethodReferenceInfo) constantPool[offset];
name_and_type_index = interfaceInfo.getNameAndTypeIndex();
break;
case INVOKE_SPECIAL:
case INVOKE_STATIC:
AbstractConstantPoolInfoJava poolElem = constantPool[offset];
if (poolElem instanceof ConstantPoolInterfaceMethodReferenceInfo) {
interfaceInfo = (ConstantPoolInterfaceMethodReferenceInfo) constantPool[offset];
name_and_type_index = interfaceInfo.getNameAndTypeIndex();
break;
}
if (poolElem instanceof ConstantPoolMethodReferenceInfo) {
ConstantPoolMethodReferenceInfo methodReferenceInfo =
(ConstantPoolMethodReferenceInfo) constantPool[offset];
name_and_type_index = methodReferenceInfo.getNameAndTypeIndex();
break;
}
throw new IllegalArgumentException(
"Unsupported type for invokestatic at constant pool element " + offset);
case INVOKE_SPECIAL:
case INVOKE_VIRTUAL:
ConstantPoolMethodReferenceInfo methodReferenceInfo = (ConstantPoolMethodReferenceInfo) constantPool[offset];
ConstantPoolMethodReferenceInfo methodReferenceInfo =
(ConstantPoolMethodReferenceInfo) constantPool[offset];
name_and_type_index = methodReferenceInfo.getNameAndTypeIndex();
break;
default:
throw new IllegalArgumentException("unimplemented method type: " + type.name());
}
ConstantPoolNameAndTypeInfo methodNameAndType = (ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index];
ConstantPoolNameAndTypeInfo methodNameAndType =
(ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index];
int descriptor_index = methodNameAndType.getDescriptorIndex();
ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
descriptor = descriptorInfo.getString();
return descriptor;
}
public final static String decodeType(ConstantPoolUtf8Info utf,
boolean useFullyQualifiedClassName) {
return DescriptorDecoder.getTypeNameFromDescriptor(utf.getString(), useFullyQualifiedClassName, true);
}
//no L, no ;
public static DataType resolveClassForString(String fullyQualifiedName, DataTypeManager dtm, DataType baseType){
/**
* Resolves the datatype represented by {@code fullyQualifiedName} with a base type of
* {@code baseType} into dtm
* @param fullyQualifiedName String representation of type
* @param dtm data type manager
* @param baseType base type
* @return data type represented by input string
*/
public static DataType resolveClassForString(String fullyQualifiedName, DataTypeManager dtm,
DataType baseType) {
fullyQualifiedName = CategoryPath.DELIMITER_CHAR + fullyQualifiedName;
CategoryPath catPath = new CategoryPath(fullyQualifiedName);
String[] parts = catPath.getPathElements();
DataType dataType = new TypedefDataType(catPath,parts[parts.length-1],baseType);
DataType dataType = new TypedefDataType(catPath, parts[parts.length - 1], baseType);
dtm.resolve(dataType, DataTypeConflictHandler.KEEP_HANDLER);
return dataType;
}
/**
* Returns a String representing the types of the parameters of a method, e.g.
* (java.lang.String, java.lang.Integer) for a method with signature
* public static void test(String x, Integer y);
* @param descriptor method descriptor
* @return string representation of types of method parameters
*/
public static String getParameterString(String descriptor) {
List<String> paramTypeNames = getTypeNameList(descriptor, true, true);
StringBuilder sb = new StringBuilder();
sb.append("(");
//don't append the last element of the list, which is the return type
for (int i = 0, max = paramTypeNames.size() - 1; i < max; ++i) {
sb.append(paramTypeNames.get(i));
if (i < max - 1) {
sb.append(", ");
}
}
sb.append(")");
return sb.toString();
}
}

View File

@ -15,14 +15,14 @@
*/
package ghidra.javaclass.format;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.javaclass.format.attributes.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -48,18 +48,18 @@ public class FieldInfoJava implements StructConverter {
private short nameIndex;
private short descriptorIndex;
private short attributesCount;
private AbstractAttributeInfo [] attributes;
private AbstractAttributeInfo[] attributes;
public FieldInfoJava( BinaryReader reader, ClassFileJava classFile ) throws IOException {
public FieldInfoJava(BinaryReader reader, ClassFileJava classFile) throws IOException {
_offset = reader.getPointerIndex();
accessFlags = reader.readNextShort();
nameIndex = reader.readNextShort();
descriptorIndex = reader.readNextShort();
attributesCount = reader.readNextShort();
attributes = new AbstractAttributeInfo[ attributesCount ];
for ( int i = 0 ; i < attributesCount ; i++ ) {
attributes[ i ] = AttributeFactory.get( reader, classFile.getConstantPool() );
accessFlags = reader.readNextShort();
nameIndex = reader.readNextShort();
descriptorIndex = reader.readNextShort();
attributesCount = reader.readNextShort();
attributes = new AbstractAttributeInfo[getAttributesCount()];
for (int i = 0; i < getAttributesCount(); i++) {
attributes[i] = AttributeFactory.get(reader, classFile.getConstantPool());
}
}
@ -84,8 +84,8 @@ public class FieldInfoJava implements StructConverter {
* unqualified name denoting a field.
* @return a valid index into the constant_pool table
*/
public short getNameIndex() {
return nameIndex;
public int getNameIndex() {
return nameIndex & 0xffff;
}
/**
@ -95,8 +95,8 @@ public class FieldInfoJava implements StructConverter {
* descriptor.
* @return a valid index into the constant_pool table
*/
public short getDescriptorIndex() {
return descriptorIndex;
public int getDescriptorIndex() {
return descriptorIndex & 0xffff;
}
/**
@ -104,8 +104,8 @@ public class FieldInfoJava implements StructConverter {
* attributes of this field.
* @return the number of additional attributes
*/
public short getAttributesCount() {
return attributesCount;
public int getAttributesCount() {
return attributesCount & 0xffff;
}
/**
@ -137,13 +137,13 @@ public class FieldInfoJava implements StructConverter {
* information.
* @return
*/
public AbstractAttributeInfo [] getAttributes() {
public AbstractAttributeInfo[] getAttributes() {
return attributes;
}
public ConstantValueAttribute getConstantValueAttribute() {
for ( AbstractAttributeInfo attributeInfo : attributes ) {
if ( attributeInfo instanceof ConstantValueAttribute ) {
for (AbstractAttributeInfo attributeInfo : attributes) {
if (attributeInfo instanceof ConstantValueAttribute) {
return (ConstantValueAttribute) attributeInfo;
}
}
@ -152,17 +152,17 @@ public class FieldInfoJava implements StructConverter {
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "field_info" + "|" + attributesCount + "|";
String name = "field_info" + "|" + attributesCount + "|";
Structure structure = new StructureDataType( name, 0 );
Structure structure = new StructureDataType(name, 0);
structure.add( WORD, "access_flags", null );
structure.add( WORD, "name_index", null );
structure.add( WORD, "descriptor_index", null );
structure.add( WORD, "attributes_count", null );
structure.add(WORD, "access_flags", null);
structure.add(WORD, "name_index", null);
structure.add(WORD, "descriptor_index", null);
structure.add(WORD, "attributes_count", null);
for ( int i = 0 ; i < attributes.length ; ++i ) {
structure.add( attributes[ i ].toDataType(), "attributes_" + i, null );
for (int i = 0; i < attributes.length; ++i) {
structure.add(attributes[i].toDataType(), "attributes_" + i, null);
}
return structure;

View File

@ -15,42 +15,38 @@
*/
package ghidra.javaclass.format;
import ghidra.framework.options.Options;
import java.util.Arrays;
import ghidra.app.util.opinion.JavaLoader;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
import java.util.Arrays;
public class JavaClassUtil {
public final static long LOOKUP_ADDRESS = 0xE0000000L;
//65536 is the maximum size of the methods_count item in a class file
public static final long METHOD_INDEX_SIZE = 65536 * 4;
public final static boolean isClassFile(Program program) {
Options options = program.getOptions(Program.PROGRAM_INFO);
String firmwarePath = options.getString("Firmware Path", "");
if (program.getExecutablePath().toLowerCase().endsWith(".class") ||
firmwarePath.toLowerCase().endsWith(".class")) {
byte[] bytes = new byte[4];
try {
Address address = program.getAddressFactory().getAddressSpace("constantPool").getMinAddress();
program.getMemory().getBytes(address, bytes);
}
catch (Exception e) {
Msg.info(JavaClassUtil.class, e.getLocalizedMessage());
}
return Arrays.equals(bytes, JavaClassConstants.MAGIC_BYTES);
byte[] bytes = new byte[4];
try {
Address address = program.getAddressFactory().getAddressSpace(
JavaLoader.CONSTANT_POOL).getMinAddress();
program.getMemory().getBytes(address, bytes);
}
return false;
catch (Exception e) {
Msg.info(JavaClassUtil.class, e.getLocalizedMessage());
return false;
}
return Arrays.equals(bytes, JavaClassConstants.MAGIC_BYTES);
}
public static Address toLookupAddress( Program program, int methodIndex ) {
AddressFactory addressFactory = program.getAddressFactory( );
AddressSpace defaultAddressSpace = addressFactory.getDefaultAddressSpace( );
return defaultAddressSpace.getAddress( JavaClassUtil.LOOKUP_ADDRESS + ( methodIndex * 4 ) );
public static Address toLookupAddress(Program program, int methodIndex) {
AddressFactory addressFactory = program.getAddressFactory();
AddressSpace defaultAddressSpace = addressFactory.getDefaultAddressSpace();
return defaultAddressSpace.getAddress(JavaClassUtil.LOOKUP_ADDRESS + (methodIndex * 4));
}
}

View File

@ -15,15 +15,16 @@
*/
package ghidra.javaclass.format;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.javaclass.flags.MethodsInfoAccessFlags;
import ghidra.javaclass.format.attributes.*;
import ghidra.javaclass.format.constantpool.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* Each method, including each instance initialization method (2.9) and the class or
* interface initialization method (2.9), is described by a method_info structure. No
@ -58,8 +59,8 @@ public class MethodInfoJava implements StructConverter {
nameIndex = reader.readNextShort();
descriptorIndex = reader.readNextShort();
attributesCount = reader.readNextShort();
attributes = new AbstractAttributeInfo[attributesCount];
for (int i = 0; i < attributesCount; i++) {
attributes = new AbstractAttributeInfo[getAttributesCount()];
for (int i = 0; i < getAttributesCount(); i++) {
attributes[i] = AttributeFactory.get(reader, classFile.getConstantPool());
}
}
@ -81,13 +82,14 @@ public class MethodInfoJava implements StructConverter {
public short getAccessFlags() {
return accessFlags;
}
/**
*
* @return boolean encoding whether the method is static
*/
public boolean isStatic(){
return AccessFlagsJava.isStatic(accessFlags);
public boolean isStatic() {
return (MethodsInfoAccessFlags.ACC_STATIC.getValue() &
accessFlags) == MethodsInfoAccessFlags.ACC_STATIC.getValue();
}
/**
@ -98,8 +100,8 @@ public class MethodInfoJava implements StructConverter {
* denoting a method.
* @return a valid index into the constant_pool table
*/
public short getNameIndex() {
return nameIndex;
public int getNameIndex() {
return nameIndex & 0xffff;
}
/**
@ -108,8 +110,8 @@ public class MethodInfoJava implements StructConverter {
* CONSTANT_Utf8_info structure representing a valid method descriptor.
* @return a valid index into the constant_pool table
*/
public short getDescriptorIndex() {
return descriptorIndex;
public int getDescriptorIndex() {
return descriptorIndex & 0xffff;
}
/**
@ -117,8 +119,8 @@ public class MethodInfoJava implements StructConverter {
* attributes of this method.
* @return the number of additional attributes of this method
*/
public short getAttributesCount() {
return attributesCount;
public int getAttributesCount() {
return attributesCount & 0xffff;
}
/**
@ -178,11 +180,13 @@ public class MethodInfoJava implements StructConverter {
ConstantPoolUtf8Info methodDescriptor =
(ConstantPoolUtf8Info) constantPool[descriptorIndex];
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(AccessFlagsJava.toString(accessFlags, false).trim());
stringBuffer.append(MethodsInfoAccessFlags.toString(accessFlags));
if (!methodName.getString().equals("<clinit>")) {
if (methodName.getString().equals("<clinit>")) {
stringBuffer.append(" (class initializer)");
}
else {
stringBuffer.append(' ');
if (methodName.getString().equals("<init>")) {//replace constructors with name of this class
ConstantPoolClassInfo thisClass =
(ConstantPoolClassInfo) constantPool[classFile.getThisClass()];
@ -205,13 +209,12 @@ public class MethodInfoJava implements StructConverter {
stringBuffer.append(methodName.getString());
}
stringBuffer.append('(');
CodeAttribute codeAttribute = getCodeAttribute();
if (codeAttribute != null) {
LocalVariableTableAttribute localVariableTable =
codeAttribute.getLocalVariableTableAttribute();
if (localVariableTable != null) {
stringBuffer.append('(');
LocalVariableJava[] localVariables = localVariableTable.getLocalVariables();
int startIndex = getParametersStartIndex();
for (int i = startIndex; i < localVariables.length; ++i) {
@ -224,22 +227,28 @@ public class MethodInfoJava implements StructConverter {
ConstantPoolUtf8Info parameterDescriptor =
(ConstantPoolUtf8Info) constantPool[localVariables[i].getDescriptorIndex()];
stringBuffer.append(DescriptorDecoder.decodeType(parameterDescriptor,
false));
stringBuffer.append(DescriptorDecoder.getTypeNameFromDescriptor(
parameterDescriptor.getString(), false, true));
stringBuffer.append(" ");
stringBuffer.append(parameterName);
}
}
stringBuffer.append(')');
}
else {
stringBuffer.append(
DescriptorDecoder.getParameterString(methodDescriptor.getString()));
}
}
stringBuffer.append(')');
ExceptionsAttribute exceptionsAttribute = getExceptionsAttribute();
if (exceptionsAttribute != null) {
int i = 0;
for (short s : exceptionsAttribute.getExceptionIndexTable()) {
ConstantPoolClassInfo exceptionClass = (ConstantPoolClassInfo) constantPool[s];
for (int k = 0; k < exceptionsAttribute.getNumberOfExceptions(); k++) {
ConstantPoolClassInfo exceptionClass =
(ConstantPoolClassInfo) constantPool[exceptionsAttribute.getExceptionIndexTableEntry(
k)];
ConstantPoolUtf8Info exceptionClassName =
(ConstantPoolUtf8Info) constantPool[exceptionClass.getNameIndex()];
String className = exceptionClassName.getString();
@ -265,7 +274,7 @@ public class MethodInfoJava implements StructConverter {
* otherwise skip index 0 because it contains the 'this' parameter.
*/
private int getParametersStartIndex() {
return AccessFlagsJava.isStatic(accessFlags) ? 0 : 1;
return isStatic() ? 0 : 1;
}
/**
@ -299,7 +308,8 @@ public class MethodInfoJava implements StructConverter {
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "method_info" + "|" + nameIndex + "|" + descriptorIndex + "|" + attributesCount + "|";
String name =
"method_info" + "|" + nameIndex + "|" + descriptorIndex + "|" + attributesCount + "|";
Structure structure = new StructureDataType(name, 0);

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,12 +15,12 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.StructureDataType;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -94,11 +93,11 @@ public abstract class AbstractAttributeInfo implements StructConverter {
private short attributeNameIndex;
private int attributeLength;
protected AbstractAttributeInfo( BinaryReader reader ) throws IOException {
protected AbstractAttributeInfo(BinaryReader reader) throws IOException {
_offset = reader.getPointerIndex();
attributeNameIndex = reader.readNextShort();
attributeLength = reader.readNextInt();
attributeLength = reader.readNextInt();
}
public long getOffset() {
@ -112,8 +111,8 @@ public abstract class AbstractAttributeInfo implements StructConverter {
* @see AttributesConstants
* @return the attribute_name_index
*/
public short getAttributeNameIndex() {
return attributeNameIndex;
public int getAttributeNameIndex() {
return attributeNameIndex & 0xffff;
}
/**
@ -127,10 +126,10 @@ public abstract class AbstractAttributeInfo implements StructConverter {
return attributeLength;
}
protected StructureDataType getBaseStructure( String name ) {
StructureDataType structure = new StructureDataType( name + "|" + attributeLength + "|", 0 );
structure.add( WORD, "attribute_name_index", null );
structure.add( DWORD, "attribute_length" , null );
protected StructureDataType getBaseStructure(String name) {
StructureDataType structure = new StructureDataType(name + "|" + attributeLength + "|", 0);
structure.add(WORD, "attribute_name_index", null);
structure.add(DWORD, "attribute_length", null);
return structure;
}
}

View File

@ -15,6 +15,8 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.javaclass.format.DescriptorDecoder;
@ -22,8 +24,6 @@ import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -69,38 +69,35 @@ public class AnnotationElementValue implements StructConverter {
private AnnotationJava annotation;
private short numberOfValues;
private AnnotationElementValue [] values;
private AnnotationElementValue[] values;
public AnnotationElementValue( BinaryReader reader ) throws IOException {
public AnnotationElementValue(BinaryReader reader) throws IOException {
tag = reader.readNextByte();
if ( tag == DescriptorDecoder.BASE_TYPE_BYTE ||
tag == DescriptorDecoder.BASE_TYPE_CHAR ||
tag == DescriptorDecoder.BASE_TYPE_INT ||
tag == DescriptorDecoder.BASE_TYPE_SHORT ||
tag == DescriptorDecoder.BASE_TYPE_LONG ||
tag == DescriptorDecoder.BASE_TYPE_FLOAT ||
tag == DescriptorDecoder.BASE_TYPE_DOUBLE ||
tag == DescriptorDecoder.BASE_TYPE_BOOLEAN ||
tag == DescriptorDecoder.BASE_TYPE_STRING ) {
if (tag == DescriptorDecoder.BASE_TYPE_BYTE || tag == DescriptorDecoder.BASE_TYPE_CHAR ||
tag == DescriptorDecoder.BASE_TYPE_INT || tag == DescriptorDecoder.BASE_TYPE_SHORT ||
tag == DescriptorDecoder.BASE_TYPE_LONG || tag == DescriptorDecoder.BASE_TYPE_FLOAT ||
tag == DescriptorDecoder.BASE_TYPE_DOUBLE ||
tag == DescriptorDecoder.BASE_TYPE_BOOLEAN ||
tag == DescriptorDecoder.BASE_TYPE_STRING) {
constantValueIndex = reader.readNextShort();
}
else if ( tag == DescriptorDecoder.BASE_TYPE_ENUM ) {
else if (tag == DescriptorDecoder.BASE_TYPE_ENUM) {
typeNameIndex = reader.readNextShort();
constantNameIndex = reader.readNextShort();
}
else if ( tag == DescriptorDecoder.BASE_TYPE_CLASS ) {
else if (tag == DescriptorDecoder.BASE_TYPE_CLASS) {
classInfoIndex = reader.readNextShort();
}
else if ( tag == DescriptorDecoder.BASE_TYPE_ANNOTATION ) {
annotation = new AnnotationJava( reader );
else if (tag == DescriptorDecoder.BASE_TYPE_ANNOTATION) {
annotation = new AnnotationJava(reader);
}
else if ( tag == DescriptorDecoder.BASE_TYPE_ARRAY ) {
else if (tag == DescriptorDecoder.BASE_TYPE_ARRAY) {
numberOfValues = reader.readNextShort();
values = new AnnotationElementValue[ numberOfValues ];
for ( int i = 0 ; i < numberOfValues ; ++i ) {
values[ i ] = new AnnotationElementValue( reader );
values = new AnnotationElementValue[numberOfValues & 0xffff];
for (int i = 0; i < (numberOfValues & 0xffff); ++i) {
values[i] = new AnnotationElementValue(reader);
}
}
}
@ -138,8 +135,8 @@ public class AnnotationElementValue implements StructConverter {
* for the field type designated by the tag item, as specified in Table 4.24.
* @return a valid index into the constant_pool table
*/
public short getConstantValueIndex() {
return constantValueIndex;
public int getConstantValueIndex() {
return constantValueIndex & 0xffff;
}
/**
@ -151,11 +148,11 @@ public class AnnotationElementValue implements StructConverter {
* element_value structure.
* @return a valid index into the constant_pool table
*/
public short getTypeNameIndex() {
if ( tag != DescriptorDecoder.BASE_TYPE_ENUM ) {
public int getTypeNameIndex() {
if (tag != DescriptorDecoder.BASE_TYPE_ENUM) {
throw new IllegalArgumentException();
}
return typeNameIndex;
return typeNameIndex & 0xffff;
}
/**
@ -166,11 +163,11 @@ public class AnnotationElementValue implements StructConverter {
* structure.
* @return a valid index into the constant_pool table
*/
public short getConstantNameIndex() {
if ( tag != DescriptorDecoder.BASE_TYPE_ENUM ) {
public int getConstantNameIndex() {
if (tag != DescriptorDecoder.BASE_TYPE_ENUM) {
throw new IllegalArgumentException();
}
return constantNameIndex;
return constantNameIndex & 0xffff;
}
/**
@ -183,8 +180,8 @@ public class AnnotationElementValue implements StructConverter {
* For example, 'V' for Void.class, 'Ljava/lang/Object;' for Object, etc.
* @return a valid index into the constant_pool table
*/
public short getClassInfoIndex() {
return classInfoIndex;
public int getClassInfoIndex() {
return classInfoIndex & 0xffff;
}
/**
@ -206,32 +203,29 @@ public class AnnotationElementValue implements StructConverter {
* array-typed value represented by this element_value structure.
* @return nested element value table
*/
public AnnotationElementValue [] getValues() {
public AnnotationElementValue[] getValues() {
return values;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "element_value" +"|" + tag + "|";
StructureDataType structure = new StructureDataType( name, 0 );
String name = "element_value" + "|" + tag + "|";
StructureDataType structure = new StructureDataType(name, 0);
if ( tag == DescriptorDecoder.BASE_TYPE_BYTE ||
tag == DescriptorDecoder.BASE_TYPE_CHAR ||
tag == DescriptorDecoder.BASE_TYPE_INT ||
tag == DescriptorDecoder.BASE_TYPE_SHORT ||
tag == DescriptorDecoder.BASE_TYPE_LONG ||
tag == DescriptorDecoder.BASE_TYPE_FLOAT ||
tag == DescriptorDecoder.BASE_TYPE_DOUBLE ||
tag == DescriptorDecoder.BASE_TYPE_BOOLEAN ||
tag == DescriptorDecoder.BASE_TYPE_STRING ) {
if (tag == DescriptorDecoder.BASE_TYPE_BYTE || tag == DescriptorDecoder.BASE_TYPE_CHAR ||
tag == DescriptorDecoder.BASE_TYPE_INT || tag == DescriptorDecoder.BASE_TYPE_SHORT ||
tag == DescriptorDecoder.BASE_TYPE_LONG || tag == DescriptorDecoder.BASE_TYPE_FLOAT ||
tag == DescriptorDecoder.BASE_TYPE_DOUBLE ||
tag == DescriptorDecoder.BASE_TYPE_BOOLEAN ||
tag == DescriptorDecoder.BASE_TYPE_STRING) {
}
else if ( tag == DescriptorDecoder.BASE_TYPE_ENUM ) {
else if (tag == DescriptorDecoder.BASE_TYPE_ENUM) {
}
else if ( tag == DescriptorDecoder.BASE_TYPE_CLASS ) {
else if (tag == DescriptorDecoder.BASE_TYPE_CLASS) {
}
else if ( tag == DescriptorDecoder.BASE_TYPE_ANNOTATION ) {
else if (tag == DescriptorDecoder.BASE_TYPE_ANNOTATION) {
}
else if ( tag == DescriptorDecoder.BASE_TYPE_ARRAY ) {
else if (tag == DescriptorDecoder.BASE_TYPE_ARRAY) {
}
return structure;

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,14 +15,14 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -43,9 +42,9 @@ public class AnnotationElementValuePair implements StructConverter {
private short elementNameIndex;
private AnnotationElementValue value;
public AnnotationElementValuePair( BinaryReader reader ) throws IOException {
public AnnotationElementValuePair(BinaryReader reader) throws IOException {
elementNameIndex = reader.readNextShort();
value = new AnnotationElementValue( reader );
value = new AnnotationElementValue(reader);
}
/**
@ -56,8 +55,8 @@ public class AnnotationElementValuePair implements StructConverter {
* element represented by this element_value_pairs entry.
* @return a valid index into the constant_pool table
*/
public short getElementNameIndex() {
return elementNameIndex;
public int getElementNameIndex() {
return elementNameIndex & 0xffff;
}
/**
@ -71,9 +70,9 @@ public class AnnotationElementValuePair implements StructConverter {
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = new StructureDataType( "element_value_pair", 0 );
structure.add( WORD, "element_name_index", null );
structure.add( value.toDataType(), "element_value_pair", null );
StructureDataType structure = new StructureDataType("element_value_pair", 0);
structure.add(WORD, "element_name_index", null);
structure.add(value.toDataType(), "element_value_pair", null);
return structure;
}
}

View File

@ -15,14 +15,14 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -45,14 +45,14 @@ public class AnnotationJava implements StructConverter {
private short typeIndex;
private short numberOfElementValuePairs;
private AnnotationElementValuePair [] elementValuePairs;
private AnnotationElementValuePair[] elementValuePairs;
public AnnotationJava( BinaryReader reader ) throws IOException {
public AnnotationJava(BinaryReader reader) throws IOException {
typeIndex = reader.readNextShort();
numberOfElementValuePairs = reader.readNextShort();
elementValuePairs = new AnnotationElementValuePair[ numberOfElementValuePairs ];
for ( int i = 0 ; i < numberOfElementValuePairs ; ++i ) {
elementValuePairs[ i ] = new AnnotationElementValuePair( reader );
elementValuePairs = new AnnotationElementValuePair[getNumberOfElementValuePairs()];
for (int i = 0; i < getNumberOfElementValuePairs(); ++i) {
elementValuePairs[i] = new AnnotationElementValuePair(reader);
}
}
@ -64,8 +64,8 @@ public class AnnotationJava implements StructConverter {
* represented by this annotation structure.
* @return valid index into the constant_pool table
*/
public short getTypeIndex() {
return typeIndex;
public int getTypeIndex() {
return typeIndex & 0xffff;
}
/**
@ -77,26 +77,26 @@ public class AnnotationJava implements StructConverter {
* annotation.
* @return the number of element-value pairs of the annotation
*/
public short getNumberOfElementValuePairs() {
return numberOfElementValuePairs;
public int getNumberOfElementValuePairs() {
return numberOfElementValuePairs & 0xffff;
}
/**
* Returns the element value pair table for this annotation.
* @return the element value pair table
*/
public AnnotationElementValuePair [] getElementValuePairs() {
public AnnotationElementValuePair[] getElementValuePairs() {
return elementValuePairs;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "annotation" +"|" + numberOfElementValuePairs + "|";
StructureDataType structure = new StructureDataType( name, 0 );
structure.add( WORD, "type_index", null );
structure.add( WORD, "num_element_value_pairs", null );
for ( int i = 0 ; i < elementValuePairs.length ; ++i ) {
structure.add( elementValuePairs[ i ].toDataType(), "element_value_pair_" + i, null );
String name = "annotation" + "|" + numberOfElementValuePairs + "|";
StructureDataType structure = new StructureDataType(name, 0);
structure.add(WORD, "type_index", null);
structure.add(WORD, "num_element_value_pairs", null);
for (int i = 0; i < elementValuePairs.length; ++i) {
structure.add(elementValuePairs[i].toDataType(), "element_value_pair_" + i, null);
}
return structure;
}

View File

@ -15,90 +15,82 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
import java.io.IOException;
public class AttributeFactory {
public static AbstractAttributeInfo get( BinaryReader reader, AbstractConstantPoolInfoJava [] constantPool ) throws IOException {
int attributeNameIndex = reader.readShort( reader.getPointerIndex() );
public static AbstractAttributeInfo get(BinaryReader reader,
AbstractConstantPoolInfoJava[] constantPool) throws IOException {
if ( attributeNameIndex < 1 || attributeNameIndex >= constantPool.length ) {
throw new RuntimeException( "invalid index");
int attributeNameIndex = reader.readShort(reader.getPointerIndex());
if (attributeNameIndex < 1 || attributeNameIndex >= constantPool.length) {
throw new RuntimeException("invalid index");
}
if ( !( constantPool[ attributeNameIndex ] instanceof ConstantPoolUtf8Info ) ) {
if (!(constantPool[attributeNameIndex] instanceof ConstantPoolUtf8Info)) {
throw new RuntimeException();
}
ConstantPoolUtf8Info utf8 = (ConstantPoolUtf8Info) constantPool[ attributeNameIndex ];
ConstantPoolUtf8Info utf8 = (ConstantPoolUtf8Info) constantPool[attributeNameIndex];
if ( utf8.getString().equals( AttributesConstants.ConstantValue ) ) {
return new ConstantValueAttribute( reader );
switch (utf8.getString()) {
case AttributesConstants.AnnotationDefault:
return new AnnotationDefaultAttribute(reader);
case AttributesConstants.BootstrapMethods:
return new BootstrapMethodsAttribute(reader);
case AttributesConstants.Code:
return new CodeAttribute(reader, constantPool);
case AttributesConstants.ConstantValue:
return new ConstantValueAttribute(reader);
case AttributesConstants.Deprecated:
return new DeprecatedAttribute(reader);
case AttributesConstants.EnclosingMethod:
return new EnclosingMethodAttribute(reader);
case AttributesConstants.Exceptions:
return new ExceptionsAttribute(reader);
case AttributesConstants.InnerClasses:
return new InnerClassesAttribute(reader);
case AttributesConstants.LineNumberTable:
return new LineNumberTableAttribute(reader);
case AttributesConstants.LocalVariableTable:
return new LocalVariableTableAttribute(reader, constantPool);
case AttributesConstants.LocalVariableTypeTable:
return new LocalVariableTypeTableAttribute(reader);
case AttributesConstants.ModuleMainClass:
return new ModuleMainClassAttribute(reader);
case AttributesConstants.ModulePackages:
return new ModulePackagesAttribute(reader);
case AttributesConstants.NestHost:
return new NestHostAttribute(reader);
case AttributesConstants.NestMembers:
return new NestMembersAttribute(reader);
case AttributesConstants.RuntimeInvisibleAnnotations:
return new RuntimeInvisibleAnnotationsAttribute(reader);
case AttributesConstants.RuntimeInvisibleParameterAnnotations:
return new RuntimeParameterAnnotationsAttribute(reader, false /*invisible*/ );
case AttributesConstants.RuntimeVisibleAnnotations:
return new RuntimeVisibleAnnotationsAttribute(reader);
case AttributesConstants.RuntimeVisibleParameterAnnotations:
return new RuntimeParameterAnnotationsAttribute(reader, true /*visible*/ );
case AttributesConstants.Signature:
return new SignatureAttribute(reader);
case AttributesConstants.SourceDebugExtension:
return new SourceDebugExtensionAttribute(reader);
case AttributesConstants.SourceFile:
return new SourceFileAttribute(reader);
case AttributesConstants.StackMapTable:
return new StackMapTableAttribute(reader);
case AttributesConstants.Synthetic:
return new SyntheticAttribute(reader);
case AttributesConstants.Module:
return new ModuleAttribute(reader);
default:
throw new RuntimeException("Unknown attribute type: " + utf8.getString());
}
else if ( utf8.getString().equals( AttributesConstants.Code ) ) {
return new CodeAttribute( reader, constantPool );
}
else if ( utf8.getString().equals( AttributesConstants.StackMapTable ) ) {
return new StackMapTableAttribute( reader );
}
else if ( utf8.getString().equals( AttributesConstants.Exceptions ) ) {
return new ExceptionsAttribute( reader );
}
else if ( utf8.getString().equals( AttributesConstants.InnerClasses ) ) {
return new InnerClassesAttribute( reader );
}
else if ( utf8.getString().equals( AttributesConstants.EnclosingMethod ) ) {
return new EnclosingMethodAttribute( reader );
}
else if ( utf8.getString().equals( AttributesConstants.Synthetic ) ) {
return new SyntheticAttribute( reader );
}
else if ( utf8.getString().equals( AttributesConstants.Signature ) ) {
return new SignatureAttribute( reader );
}
else if ( utf8.getString().equals( AttributesConstants.SourceFile ) ) {
return new SourceFileAttribute( reader );
}
else if ( utf8.getString().equals( AttributesConstants.SourceDebugExtension ) ) {
return new SourceDebugExtensionAttribute( reader );
}
else if ( utf8.getString().equals( AttributesConstants.LineNumberTable ) ) {
return new LineNumberTableAttribute( reader );
}
else if ( utf8.getString().equals( AttributesConstants.LocalVariableTable ) ) {
return new LocalVariableTableAttribute( reader, constantPool );
}
else if ( utf8.getString().equals( AttributesConstants.LocalVariableTypeTable ) ) {
return new LocalVariableTypeTableAttribute( reader );
}
else if ( utf8.getString().equals( AttributesConstants.Deprecated ) ) {
return new DeprecatedAttribute( reader );
}
else if ( utf8.getString().equals( AttributesConstants.RuntimeVisibleAnnotations ) ) {
return new RuntimeVisibleAnnotationsAttribute( reader );
}
else if ( utf8.getString().equals( AttributesConstants.RuntimeInvisibleAnnotations ) ) {
return new RuntimeInvisibleAnnotationsAttribute( reader );
}
else if ( utf8.getString().equals( AttributesConstants.RuntimeVisibleParameterAnnotations ) ) {
return new RuntimeParameterAnnotationsAttribute( reader, true /*visible*/ );
}
else if ( utf8.getString().equals( AttributesConstants.RuntimeInvisibleParameterAnnotations ) ) {
return new RuntimeParameterAnnotationsAttribute( reader, false /*invisible*/ );
}
else if ( utf8.getString().equals( AttributesConstants.AnnotationDefault ) ) {
return new AnnotationDefaultAttribute( reader );
}
else if ( utf8.getString().equals( AttributesConstants.BootstrapMethods ) ) {
return new BootstrapMethodsAttribute( reader );
}
throw new RuntimeException( "Unknown attribute type: " + utf8.getString() );
}
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -34,9 +33,16 @@ public final class AttributesConstants {
public final static String Deprecated = "Deprecated";
public final static String RuntimeVisibleAnnotations = "RuntimeVisibleAnnotations";
public final static String RuntimeInvisibleAnnotations = "RuntimeInvisibleAnnotations";
public final static String RuntimeVisibleParameterAnnotations = "RuntimeVisibleParameterAnnotations";
public final static String RuntimeInvisibleParameterAnnotations = "RuntimeInvisibleParameterAnnotations";
public final static String RuntimeVisibleParameterAnnotations =
"RuntimeVisibleParameterAnnotations";
public final static String RuntimeInvisibleParameterAnnotations =
"RuntimeInvisibleParameterAnnotations";
public final static String AnnotationDefault = "AnnotationDefault";
public final static String BootstrapMethods = "BootstrapMethods";
public final static String Module = "Module";
public final static String ModulePackages = "ModulePackages";
public final static String ModuleMainClass = "ModuleMainClass";
public final static String NestHost = "NestHost";
public final static String NestMembers = "NestMembers";
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,9 +19,7 @@ import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.ArrayDataType;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
@ -34,12 +31,12 @@ public class BootstrapMethods implements StructConverter {
private short bootstrapMethodsReference;
private short numberOfBootstrapArguments;
private short [] bootstrapArguments;
private short[] bootstrapArguments;
public BootstrapMethods( BinaryReader reader ) throws IOException {
public BootstrapMethods(BinaryReader reader) throws IOException {
bootstrapMethodsReference = reader.readNextShort();
numberOfBootstrapArguments = reader.readNextShort();
bootstrapArguments = reader.readNextShortArray( numberOfBootstrapArguments & 0xffff );
bootstrapArguments = reader.readNextShortArray(getNumberOfBootstrapArguments());
}
/**
@ -55,8 +52,8 @@ public class BootstrapMethods implements StructConverter {
*
* @return a valid index into the constant_pool table
*/
public short getBootstrapMethodsReference() {
return bootstrapMethodsReference;
public int getBootstrapMethodsReference() {
return bootstrapMethodsReference & 0xffff;
}
/**
@ -64,8 +61,8 @@ public class BootstrapMethods implements StructConverter {
* items in the bootstrap_arguments array.
* @return the number of items in the bootstrap_arguments array
*/
public short getNumberOfBootstrapArguments() {
return numberOfBootstrapArguments;
public int getNumberOfBootstrapArguments() {
return numberOfBootstrapArguments & 0xffff;
}
/**
@ -80,20 +77,21 @@ public class BootstrapMethods implements StructConverter {
* CONSTANT_Double_info,
* CONSTANT_MethodHandle_info, or
* CONSTANT_MethodType_info structure.
* @return
* @param i entry
* @return index
*/
public short [] getBootstrapArguments() {
return bootstrapArguments;
public int getBootstrapArgumentsEntry(int i) {
return bootstrapArguments[i] & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = new StructureDataType( "bootstrap_methods", 0 );
structure.add( WORD, "bootstrap_method_ref", null );
structure.add( WORD, "num_bootstrap_arguments", null );
if ( numberOfBootstrapArguments > 0 ) {
DataType array = new ArrayDataType( WORD, numberOfBootstrapArguments, WORD.getLength() );
structure.add( array, "bootstrapArguments", null );
StructureDataType structure = new StructureDataType("bootstrap_methods", 0);
structure.add(WORD, "bootstrap_method_ref", null);
structure.add(WORD, "num_bootstrap_arguments", null);
if (numberOfBootstrapArguments > 0) {
DataType array = new ArrayDataType(WORD, numberOfBootstrapArguments, WORD.getLength());
structure.add(array, "bootstrapArguments", null);
}
return structure;
}

View File

@ -15,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -55,33 +55,33 @@ import java.io.IOException;
public class BootstrapMethodsAttribute extends AbstractAttributeInfo {
private short numberOfBootstrapMethods;
private BootstrapMethods [] bootstrapMethods;
private BootstrapMethods[] bootstrapMethods;
public BootstrapMethodsAttribute( BinaryReader reader ) throws IOException {
public BootstrapMethodsAttribute(BinaryReader reader) throws IOException {
super(reader);
numberOfBootstrapMethods = reader.readNextShort();
bootstrapMethods = new BootstrapMethods[ numberOfBootstrapMethods ];
for ( int i = 0 ; i < numberOfBootstrapMethods ; ++i ) {
bootstrapMethods[ i ] = new BootstrapMethods( reader );
bootstrapMethods = new BootstrapMethods[getNumberOfBootstrapMethods()];
for (int i = 0; i < getNumberOfBootstrapMethods(); ++i) {
bootstrapMethods[i] = new BootstrapMethods(reader);
}
}
public short getNumberOfBootstrapMethods() {
return numberOfBootstrapMethods;
public int getNumberOfBootstrapMethods() {
return numberOfBootstrapMethods & 0xffff;
}
public BootstrapMethods[] getBootstrapMethods(){
public BootstrapMethods[] getBootstrapMethods() {
return bootstrapMethods;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = getBaseStructure( "BootstrapMethods_attribute" );
structure.add( WORD, "num_bootstrap_methods", null );
for ( int i = 0 ; i < bootstrapMethods.length ; ++i ) {
structure.add( bootstrapMethods[ i ].toDataType(), "bootstrap_methods" + i, null );
StructureDataType structure = getBaseStructure("BootstrapMethods_attribute");
structure.add(WORD, "num_bootstrap_methods", null);
for (int i = 0; i < bootstrapMethods.length; ++i) {
structure.add(bootstrapMethods[i].toDataType(), "bootstrap_methods" + i, null);
}
return structure;
}

View File

@ -15,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -80,13 +80,13 @@ public class CodeAttribute extends AbstractAttributeInfo {
_codeOffset = reader.getPointerIndex();
code = reader.readNextByteArray(codeLength);
exceptionTableLength = reader.readNextShort();
exceptionTable = new ExceptionHandlerJava[exceptionTableLength];
for (int i = 0; i < exceptionTableLength; i++) {
exceptionTable = new ExceptionHandlerJava[getExceptionTableLength()];
for (int i = 0; i < getExceptionTableLength(); i++) {
exceptionTable[i] = new ExceptionHandlerJava(reader);
}
attributesCount = reader.readNextShort();
attributes = new AbstractAttributeInfo[attributesCount];
for (int i = 0; i < attributesCount; i++) {
attributes = new AbstractAttributeInfo[getAttributesCount()];
for (int i = 0; i < getAttributesCount(); i++) {
attributes[i] = AttributeFactory.get(reader, constantPool);
}
}
@ -96,8 +96,8 @@ public class CodeAttribute extends AbstractAttributeInfo {
* operand stack of this method at any point during execution of the method.
* @return the maximum depth of the operand stack
*/
public short getMaxStack() {
return maxStack;
public int getMaxStack() {
return maxStack & 0xffff;
}
/**
@ -111,8 +111,8 @@ public class CodeAttribute extends AbstractAttributeInfo {
* @return the number of local variables in the
* local variable array allocated upon invocation of this method
*/
public short getMaxLocals() {
return maxLocals;
public int getMaxLocals() {
return maxLocals & 0xffff;
}
/**
@ -148,8 +148,8 @@ public class CodeAttribute extends AbstractAttributeInfo {
* in the exception_table table.
* @return the number of entries in the exception_table table
*/
public short getExceptionTableLength() {
return exceptionTableLength;
public int getExceptionTableLength() {
return exceptionTableLength & 0xffff;
}
/**
@ -168,8 +168,8 @@ public class CodeAttribute extends AbstractAttributeInfo {
* the Code attribute.
* @return the number of attributes of the Code attribute
*/
public short getAttributesCount() {
return attributesCount;
public int getAttributesCount() {
return attributesCount & 0xffff;
}
/**

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -56,8 +55,8 @@ public class ConstantValueAttribute extends AbstractAttributeInfo {
private short constantValueIndex;
public ConstantValueAttribute( BinaryReader reader ) throws IOException {
super( reader );
public ConstantValueAttribute(BinaryReader reader) throws IOException {
super(reader);
constantValueIndex = reader.readNextShort();
}
@ -80,15 +79,15 @@ public class ConstantValueAttribute extends AbstractAttributeInfo {
* </pre>
* @return a valid index into the constant_pool table
*/
public short getConstantValueIndex() {
return constantValueIndex;
public int getConstantValueIndex() {
return constantValueIndex & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = getBaseStructure( "ConstantValue_attribute" );
structure.add( WORD, "constantvalue_index", null );
StructureDataType structure = getBaseStructure("ConstantValue_attribute");
structure.add(WORD, "constantvalue_index", null);
return structure;
}
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -46,8 +45,8 @@ public class EnclosingMethodAttribute extends AbstractAttributeInfo {
private short classIndex;
private short methodIndex;
public EnclosingMethodAttribute( BinaryReader reader ) throws IOException {
super( reader );
public EnclosingMethodAttribute(BinaryReader reader) throws IOException {
super(reader);
classIndex = reader.readNextShort();
methodIndex = reader.readNextShort();
@ -60,8 +59,8 @@ public class EnclosingMethodAttribute extends AbstractAttributeInfo {
* encloses the declaration of the current class.
* @return a valid index into the constant_pool table
*/
public short getClassIndex() {
return classIndex;
public int getClassIndex() {
return classIndex & 0xffff;
}
/**
@ -74,15 +73,15 @@ public class EnclosingMethodAttribute extends AbstractAttributeInfo {
* type of a method in the class referenced by the class_index attribute above.
* @return a valid index into the constant_pool table, or zero
*/
public short getMethodIndex() {
return methodIndex;
public int getMethodIndex() {
return methodIndex & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = getBaseStructure( "EnclosingMethod_attribute" );
structure.add( WORD, "class_index", null );
structure.add( WORD, "method_index", null );
StructureDataType structure = getBaseStructure("EnclosingMethod_attribute");
structure.add(WORD, "class_index", null);
structure.add(WORD, "method_index", null);
return structure;
}

View File

@ -15,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -32,10 +32,10 @@ public class ExceptionHandlerJava implements StructConverter {
private short endPC;
private short handlerPC;
private short catchType;
public ExceptionHandlerJava( BinaryReader reader ) throws IOException {
startPC = reader.readNextShort();
endPC = reader.readNextShort();
public ExceptionHandlerJava(BinaryReader reader) throws IOException {
startPC = reader.readNextShort();
endPC = reader.readNextShort();
handlerPC = reader.readNextShort();
catchType = reader.readNextShort();
}
@ -54,9 +54,10 @@ public class ExceptionHandlerJava implements StructConverter {
* [start_pc, end_pc].
* @return a valid index into the code array
*/
public short getStartPC() {
return startPC;
public int getStartPC() {
return startPC & 0xffff;
}
/**
* The values of the two items start_pc and end_pc indicate the ranges in the
* code array at which the exception handler is active.
@ -72,18 +73,20 @@ public class ExceptionHandlerJava implements StructConverter {
* [start_pc, end_pc].
* @return a valid index into the code array
*/
public short getEndPC() {
return endPC;
public int getEndPC() {
return endPC & 0xffff;
}
/**
* The value of the handler_pc item indicates the start of the exception
* handler. The value of the item must be a valid index into the code array
* and must be the index of the opcode of an instruction.
* @return the start of the exception handler
*/
public short getHandlerPC() {
return handlerPC;
public int getHandlerPC() {
return handlerPC & 0xffff;
}
/**
* If the value of the catch_type item is nonzero, it must be a valid index
* into the constant_pool table. The constant_pool entry at that index
@ -96,17 +99,17 @@ public class ExceptionHandlerJava implements StructConverter {
* for all exceptions. This is used to implement finally (?3.13).
* @return the value of the catch_type item
*/
public short getCatchType() {
return catchType;
public int getCatchType() {
return catchType & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = new StructureDataType( "exception_handler", 0 );
structure.add( WORD, "start_pc", null );
structure.add( WORD, "end_pc", null );
structure.add( WORD, "handler_pc", null );
structure.add( WORD, "catch_type", null );
Structure structure = new StructureDataType("exception_handler", 0);
structure.add(WORD, "start_pc", null);
structure.add(WORD, "end_pc", null);
structure.add(WORD, "handler_pc", null);
structure.add(WORD, "catch_type", null);
return structure;
}
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,12 +15,12 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -49,7 +48,7 @@ public class ExceptionsAttribute extends AbstractAttributeInfo {
super(reader);
numberOfExceptions = reader.readNextShort();
exceptionIndexTable = reader.readNextShortArray(numberOfExceptions);
exceptionIndexTable = reader.readNextShortArray(getNumberOfExceptions());
}
/**
@ -57,8 +56,8 @@ public class ExceptionsAttribute extends AbstractAttributeInfo {
* in the exception_index_table.
* @return the number of entries in the exception_index_table
*/
public short getNumberOfExceptions() {
return numberOfExceptions;
public int getNumberOfExceptions() {
return numberOfExceptions & 0xffff;
}
/**
@ -66,10 +65,11 @@ public class ExceptionsAttribute extends AbstractAttributeInfo {
* the constant_pool table. The constant_pool entry referenced by each table
* item must be a CONSTANT_Class_info structure representing a class
* type that this method is declared to throw.
* @return the exception_index_table array
* @param i entry
* @return index
*/
public short[] getExceptionIndexTable() {
return exceptionIndexTable;
public int getExceptionIndexTableEntry(int i) {
return exceptionIndexTable[i] & 0xffff;
}
@Override

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,14 +15,14 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -44,7 +43,7 @@ public class InnerClass implements StructConverter {
private short innerNameIndex;
private short innerClassAccessFlags;
public InnerClass( BinaryReader reader ) throws IOException {
public InnerClass(BinaryReader reader) throws IOException {
innerClassInfoIndex = reader.readNextShort();
outerClassInfoIndex = reader.readNextShort();
innerNameIndex = reader.readNextShort();
@ -58,8 +57,8 @@ public class InnerClass implements StructConverter {
* items in the classes array entry give information about C.
* @return a valid index into the constant_pool table
*/
public short getInnerClassInfoIndex() {
return innerClassInfoIndex;
public int getInnerClassInfoIndex() {
return innerClassInfoIndex & 0xffff;
}
/**
@ -74,8 +73,8 @@ public class InnerClass implements StructConverter {
* interface of which C is a member.
* @return a valid index into the constant_pool table, or zero
*/
public short getOuterClassInfoIndex() {
return outerClassInfoIndex;
public int getOuterClassInfoIndex() {
return outerClassInfoIndex & 0xffff;
}
/**
@ -88,8 +87,8 @@ public class InnerClass implements StructConverter {
* compiled.
* @return a valid index into the constant_pool table, or zero
*/
public short getInnerNameIndex() {
return innerNameIndex;
public int getInnerNameIndex() {
return innerNameIndex & 0xffff;
}
/**
@ -107,11 +106,11 @@ public class InnerClass implements StructConverter {
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = new StructureDataType( "inner_class", 0 );
structure.add( WORD, "inner_class_info_index", null );
structure.add( WORD, "outer_class_info_index", null );
structure.add( WORD, "inner_name_index", null );
structure.add( WORD, "inner_class_access_flags", null );
StructureDataType structure = new StructureDataType("inner_class", 0);
structure.add(WORD, "inner_class_info_index", null);
structure.add(WORD, "outer_class_info_index", null);
structure.add(WORD, "inner_name_index", null);
structure.add(WORD, "inner_class_access_flags", null);
return structure;
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -50,15 +49,15 @@ import java.io.IOException;
public class InnerClassesAttribute extends AbstractAttributeInfo {
private short numberOfInnerClasses;
private InnerClass [] innerClasses;
private InnerClass[] innerClasses;
public InnerClassesAttribute( BinaryReader reader ) throws IOException {
super( reader );
public InnerClassesAttribute(BinaryReader reader) throws IOException {
super(reader);
numberOfInnerClasses = reader.readNextShort();
innerClasses = new InnerClass[ numberOfInnerClasses ];
for ( int i = 0 ; i < numberOfInnerClasses ; i++ ) {
innerClasses[ i ] = new InnerClass( reader );
innerClasses = new InnerClass[getNumberOfInnerClasses()];
for (int i = 0; i < getNumberOfInnerClasses(); i++) {
innerClasses[i] = new InnerClass(reader);
}
}
@ -66,25 +65,26 @@ public class InnerClassesAttribute extends AbstractAttributeInfo {
* The value of the number_of_classes item indicates the number of entries in
* the classes array.
* @return the number of entries in the classes array
*/
public short getNumberOfInnerClasses() {
return numberOfInnerClasses;
*/
public int getNumberOfInnerClasses() {
return numberOfInnerClasses & 0xffff;
}
/**
* Returns array of inner classes.
* @return array of inner classes.
*/
public InnerClass [] getInnerClasses() {
public InnerClass[] getInnerClasses() {
return innerClasses;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = getBaseStructure( "InnerClasses_attribute" + "|" + numberOfInnerClasses + "|" );
structure.add( WORD, "number_of_classes", null );
for ( int i = 0 ; i < innerClasses.length ; ++i ) {
structure.add( innerClasses[ i ].toDataType(), "inner_class_" + i, null );
StructureDataType structure =
getBaseStructure("InnerClasses_attribute" + "|" + numberOfInnerClasses + "|");
structure.add(WORD, "number_of_classes", null);
for (int i = 0; i < innerClasses.length; ++i) {
structure.add(innerClasses[i].toDataType(), "inner_class_" + i, null);
}
return structure;

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,14 +15,14 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -40,7 +39,7 @@ public class LineNumber implements StructConverter {
private short startPC;
private short lineNumber;
public LineNumber( BinaryReader reader ) throws IOException {
public LineNumber(BinaryReader reader) throws IOException {
startPC = reader.readNextShort();
lineNumber = reader.readNextShort();
}
@ -53,23 +52,23 @@ public class LineNumber implements StructConverter {
* item of the Code attribute of which this LineNumberTable is an attribute.
* @return index into the code array at which the code for a new line in the original source file begins
*/
public short getStartPC() {
return startPC;
public int getStartPC() {
return startPC & 0xffff;
}
/**
* The value of the line_number item must give the corresponding line number in the original source file.
* @return the corresponding line number in the original source file
*/
public short getLineNumber() {
return lineNumber;
public int getLineNumber() {
return lineNumber & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = new StructureDataType( "line_number", 0 );
structure.add( WORD, "start_pc", null );
structure.add( WORD, "line_number", null );
StructureDataType structure = new StructureDataType("line_number", 0);
structure.add(WORD, "start_pc", null);
structure.add(WORD, "line_number", null);
return structure;
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -52,25 +51,25 @@ import java.io.IOException;
public class LineNumberTableAttribute extends AbstractAttributeInfo {
private short lineNumberTableLength;
private LineNumber [] lineNumberTable;
private LineNumber[] lineNumberTable;
public LineNumberTableAttribute( BinaryReader reader ) throws IOException {
super( reader );
public LineNumberTableAttribute(BinaryReader reader) throws IOException {
super(reader);
lineNumberTableLength = reader.readNextShort();
lineNumberTable = new LineNumber[ lineNumberTableLength ];
for ( int i = 0 ; i < lineNumberTableLength ; i++ ) {
lineNumberTable[ i ] = new LineNumber( reader );
lineNumberTable = new LineNumber[lineNumberTableLength & 0xffff];
for (int i = 0; i < (lineNumberTableLength & 0xffff); i++) {
lineNumberTable[i] = new LineNumber(reader);
}
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "LineNumberTable_attribute" + "|" + lineNumberTableLength + "|";
StructureDataType structure = getBaseStructure( name );
structure.add( WORD, "line_number_table_length", null );
for ( int i = 0 ; i < lineNumberTable.length ; ++i ) {
structure.add( lineNumberTable[ i ].toDataType(), "line_number_" + i, null );
StructureDataType structure = getBaseStructure(name);
structure.add(WORD, "line_number_table_length", null);
for (int i = 0; i < lineNumberTable.length; ++i) {
structure.add(lineNumberTable[i].toDataType(), "line_number_" + i, null);
}
return structure;
}

View File

@ -15,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -90,12 +90,12 @@ public class LocalVariableJava implements StructConverter {
private short descriptorIndex;
private short index;
public LocalVariableJava( BinaryReader reader ) throws IOException {
startPC = reader.readNextShort();
length = reader.readNextShort();
nameIndex = reader.readNextShort();
public LocalVariableJava(BinaryReader reader) throws IOException {
startPC = reader.readNextShort();
length = reader.readNextShort();
nameIndex = reader.readNextShort();
descriptorIndex = reader.readNextShort();
index = reader.readNextShort();
index = reader.readNextShort();
}
/**
@ -111,16 +111,16 @@ public class LocalVariableJava implements StructConverter {
* or it must be the first index beyond the end of that code array.
* @return the start PC
*/
public short getStartPC() {
return startPC;
public int getStartPC() {
return startPC & 0xffff;
}
/**
* Returns the length of this local variable in bytes.
* @return the length of this local variable in bytes
*/
public short getLength() {
return length;
public int getLength() {
return length & 0xffff;
}
/**
@ -130,8 +130,8 @@ public class LocalVariableJava implements StructConverter {
* name denoting a local variable.
* @return a valid index into the constant_pool table
*/
public short getNameIndex() {
return nameIndex;
public int getNameIndex() {
return nameIndex & 0xffff;
}
/**
@ -141,8 +141,8 @@ public class LocalVariableJava implements StructConverter {
* encoding the type of a local variable in the source program.
* @return a valid index into the constant_pool table
*/
public short getDescriptorIndex() {
return descriptorIndex;
public int getDescriptorIndex() {
return descriptorIndex & 0xffff;
}
/**
@ -153,18 +153,18 @@ public class LocalVariableJava implements StructConverter {
* index and index + 1.
* @return index in the local variable array
*/
public short getIndex() {
return index;
public int getIndex() {
return index & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = new StructureDataType( "local_variable", 0 );
structure.add( WORD, "start_pc", null );
structure.add( WORD, "length", null );
structure.add( WORD, "name_index", null );
structure.add( WORD, "descriptor_index", null );
structure.add( WORD, "index", null );
Structure structure = new StructureDataType("local_variable", 0);
structure.add(WORD, "start_pc", null);
structure.add(WORD, "length", null);
structure.add(WORD, "name_index", null);
structure.add(WORD, "descriptor_index", null);
structure.add(WORD, "index", null);
return structure;
}

View File

@ -15,14 +15,14 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -53,28 +53,29 @@ import java.io.IOException;
public class LocalVariableTableAttribute extends AbstractAttributeInfo {
private short localVariableTableLength;
private LocalVariableJava [] localVariableTable;
private LocalVariableJava[] localVariableTable;
public LocalVariableTableAttribute( BinaryReader reader, AbstractConstantPoolInfoJava [] constantPool ) throws IOException {
super( reader );
public LocalVariableTableAttribute(BinaryReader reader,
AbstractConstantPoolInfoJava[] constantPool) throws IOException {
super(reader);
localVariableTableLength = reader.readNextShort();
localVariableTable = new LocalVariableJava[ localVariableTableLength ];
for ( int i = 0 ; i < localVariableTableLength ; i++ ) {
localVariableTable[ i ] = new LocalVariableJava( reader );
localVariableTable = new LocalVariableJava[localVariableTableLength & 0xffff];
for (int i = 0; i < (localVariableTableLength & 0xffff); i++) {
localVariableTable[i] = new LocalVariableJava(reader);
}
}
public LocalVariableJava [] getLocalVariables() {
public LocalVariableJava[] getLocalVariables() {
return localVariableTable;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = getBaseStructure( "LocalVariableTable_attribute" );
structure.add( WORD, "local_variable_table_length", null );
for ( int i = 0 ; i < localVariableTable.length ; ++i ) {
structure.add( localVariableTable[ i ].toDataType(), "local_variable_" + i, null );
StructureDataType structure = getBaseStructure("LocalVariableTable_attribute");
structure.add(WORD, "local_variable_table_length", null);
for (int i = 0; i < localVariableTable.length; ++i) {
structure.add(localVariableTable[i].toDataType(), "local_variable_" + i, null);
}
return structure;
}

View File

@ -0,0 +1,478 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.javaclass.format.constantpool.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* Note: text in comments taken from jvms12.pdf
* <p>
* The {@code Module} attribute indicates:
* <ul>
* <li> the modules required by a module </li>
* <li> the packages exported and opened by a module </li>
* <li> the services used and provided by a module </li>
* </ul>
*/
public class ModuleAttribute extends AbstractAttributeInfo {
private short module_name_index;
private short module_flags;
private short module_version_index;
private short requires_count;
private ModuleAttributeRequires[] moduleAttributeRequires;
private short exports_count;
private ModuleAttributeExports[] moduleAttributeExports;
private short opens_count;
private ModuleAttributeOpens[] moduleAttributeOpens;
private short uses_count;
private short[] uses_index;
private short provides_count;
private ModuleAttributeProvides[] moduleAttributeProvides;
protected ModuleAttribute(BinaryReader reader) throws IOException {
super(reader);
module_name_index = reader.readNextShort();
module_flags = reader.readNextShort();
module_version_index = reader.readNextShort();
requires_count = reader.readNextShort();
moduleAttributeRequires = new ModuleAttributeRequires[getRequiresCount()];
for (int i = 0; i < getRequiresCount(); i++) {
moduleAttributeRequires[i] = new ModuleAttributeRequires(reader);
}
exports_count = reader.readNextShort();
moduleAttributeExports = new ModuleAttributeExports[getExportsCount()];
for (int i = 0; i < getExportsCount(); i++) {
moduleAttributeExports[i] = new ModuleAttributeExports(reader);
}
opens_count = reader.readNextShort();
moduleAttributeOpens = new ModuleAttributeOpens[getOpensCount()];
for (int i = 0; i < getOpensCount(); i++) {
moduleAttributeOpens[i] = new ModuleAttributeOpens(reader);
}
uses_count = reader.readNextShort();
uses_index = new short[getUsesCount()];
for (int i = 0; i < getUsesCount(); i++) {
uses_index[i] = reader.readNextShort();
}
provides_count = reader.readNextShort();
moduleAttributeProvides = new ModuleAttributeProvides[getProvidesCount()];
for (int i = 0; i < getProvidesCount(); i++) {
moduleAttributeProvides[i] = new ModuleAttributeProvides(reader);
}
}
/**
* Returns {@code module_name_index}, which must be a valid index into the constant pool.
* The constant_pool entry at that index must be a {@link ConstantPoolModuleInfo} structure
* denoting the current module.
* @return the module name index
*/
public int getModuleNameIndex() {
return module_name_index & 0xffff;
}
/**
* The value of the {@code module_flags} item is as follows:
* <ul>
* <li> 0x0020 (ACC_OPEN): indicates that this module is open </li>
* <li> 0x10000 (ACC_SYNTHETIC): Indicates that this module was not explicitly or implicitly
* declared </li>
* <li> 0x8000 (ACC_MANDATED) indicates that this module was implicitly declared </li>
* </ul>
* @return the module flags
*/
public int getModuleFlags() {
return module_flags & 0xffff;
}
/**
* The value of the {@code module_version_index} item must be either zero or a valid index
* into the constant pool table. If the value is zero, no version information about the
* current module is present. If the value is nonzero, the constant pool entry at that index
* must be a {@link ConstantPoolUtf8Info} structure representing the version of the current module.
* @return the module version index.
*/
public int getModuleVersionIndex() {
return module_version_index & 0xffff;
}
/**
* The value of the {@code requires_count} item indicates the number of entries in the
* {@code requires} table.
* @return the requires count
*/
public int getRequiresCount() {
return requires_count & 0xffff;
}
/**
* Indicates the number of entries in the exports table
* @return the exports count
*/
public int getExportsCount() {
return exports_count & 0xffff;
}
/**
* {@code opens_count} indicates the number of entries in the {@code opens} table.
* @return the opens count
*/
public int getOpensCount() {
return opens_count & 0xffff;
}
/**
* {@code uses_count} indicates the number of entries in the {@code uses_index} table.
* @return {@code uses_count}
*/
public int getUsesCount() {
return uses_count & 0xffff;
}
/**
* The value of each entry in the uses_index table must be a valid index into the constant
* pool. The entry at that index must be a {@link ConstantPoolClassInfo} structure representing
* a service interface which the current module may discover via {@link java.util.ServiceLoader}.
* @param i entry
* @return index at entry {@code i}
*/
public int getUsesEntry(int i) {
return uses_index[i] & 0xffff;
}
/**
* {@code provides_count} indicates the number of entries in the {@code provides} table.
* @return {@code provides_count}
*/
public int getProvidesCount() {
return provides_count & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = getBaseStructure("Module_attribute");
structure.add(WORD, "module_name_index", null);
structure.add(WORD, "module_flags", null);
structure.add(WORD, "module_version_index", null);
structure.add(WORD, "requires_count", null);
for (int i = 0; i < getRequiresCount(); i++) {
structure.add(moduleAttributeRequires[i].toDataType(), "requires_" + i, null);
}
structure.add(WORD, "exports_count", null);
for (int i = 0; i < getExportsCount(); i++) {
structure.add(moduleAttributeExports[i].toDataType(), "exports_" + i, null);
}
structure.add(WORD, "opens_count", null);
for (int i = 0; i < getOpensCount(); i++) {
structure.add(moduleAttributeOpens[i].toDataType(), "opens_" + i, null);
}
structure.add(WORD, "uses_count", null);
for (int i = 0; i < getUsesCount(); i++) {
structure.add(WORD, "uses_" + i, null);
}
structure.add(WORD, "provides_count", null);
for (int i = 0; i < getProvidesCount(); i++) {
structure.add(WORD, "provides_" + i, null);
}
return structure;
}
/**
* Objects of this class specify a dependence of the current module.
*/
static class ModuleAttributeRequires implements StructConverter {
private short requires_index;
private short requires_flags;
private short requires_version_index;
public ModuleAttributeRequires(BinaryReader reader) throws IOException {
requires_index = reader.readNextShort();
requires_flags = reader.readNextShort();
requires_version_index = reader.readNextShort();
}
/**
* The value of the {@code requires_index} item must be a valid index into
* the constant pool. The entry at that index must be a {@link ConstantPoolModuleInfo} structure
* denoting a module that the current module depends on.
* @return the requires index
*/
public int getRequiresIndex() {
return requires_index & 0xffff;
}
/**
* The value of the {@code requires_flags} item is as follows:
* <ul>
* <li> 0x0020 ACC_TRANSITIVE </li>
* <li> 0x0040 ACC_STATIC_PHASE </li>
* <li> 0x1000 ACC_SYNTHETIC </li>
* <li> 0x8000 ACC_MANDATED </li>
* </ul>
* @return the requires flags
*/
public short getRequiresFlags() {
return requires_flags;
}
/**
* Must be either 0 or a valid index into the constant pool. If the value of the
* item is nonzero, the constant pool entry at that index must be a {@link ConstantPoolUtf8Info}
* structure representing the version of the module specified by {@code requires_index}.
* @return requires_index
*/
public int getRequiresVersionIndex() {
return requires_version_index & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = new StructureDataType("requires", 0);
structure.add(WORD, "requires_index", null);
structure.add(WORD, "requires_flags", null);
structure.add(WORD, "requires_version_index", null);
return structure;
}
}
/**
* Each entry in the {@code exports} table specifies a package exported by the current module.
*/
static class ModuleAttributeExports implements StructConverter {
private short exports_index;
private short exports_flags;
private short exports_to_count;
private short[] exports_to_index;
public ModuleAttributeExports(BinaryReader reader) throws IOException {
exports_index = reader.readNextShort();
exports_flags = reader.readNextShort();
exports_to_count = reader.readNextShort();
exports_to_index = new short[getExportsToCount()];
for (int i = 0; i < getExportsToCount(); i++) {
exports_to_index[i] = reader.readNextShort();
}
}
/**
* {@code exports_index} must be a valid index into the constant pool. The
* entry at that index must be a {@link ConstantPoolPackageInfo} structure
* representing a package exported by the current module.
* @return exports_index
*/
public int getExportsIndex() {
return exports_index & 0xffff;
}
/**
* The value of {@code exports_flags} is as follows:
* <ul>
* <li> 0x1000 (ACC_SYNTHETIC) </li>
* <li> 0x8000 (ACC_MANDATED) </li>
* </ul>
* @return exports_flags
*/
public short getExportsFlags() {
return exports_flags;
}
/**
* {@code exports_to_count} indicates the number of entries in the
* {@code exports_to_index} table
* @return {@code exports_to_count}
*/
public int getExportsToCount() {
return exports_to_count & 0xffff;
}
/**
* The value of each entry in the {@cod exports_to_index} must be a valid index
* into the constant pool. The entry at that index must be a {@link ConstantPoolModuleInfo}
* structure denoting a module whose code can access the types and members in this exported
* package
* @param i the entry to retrieve
* @return module index
*/
public int getExportsToEntry(int i) {
return exports_to_index[i] & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = new StructureDataType("exports", 0);
structure.add(WORD, "exports_index", null);
structure.add(WORD, "exports_flags", null);
structure.add(WORD, "exports_to_counts", null);
for (int i = 0; i < getExportsToCount(); i++) {
structure.add(WORD, "exports_to_index_" + i, null);
}
return structure;
}
}
/**
* An object of this class specifies a package opened by the current module.
*/
static class ModuleAttributeOpens implements StructConverter {
private short opens_index;
private short opens_flags;
private short opens_to_count;
private short[] opens_to_index;
public ModuleAttributeOpens(BinaryReader reader) throws IOException {
opens_index = reader.readNextShort();
opens_flags = reader.readNextShort();
opens_to_count = reader.readNextShort();
opens_to_index = new short[getOpensToCount()];
for (int i = 0; i < getOpensToCount(); i++) {
opens_to_index[i] = reader.readNextShort();
}
}
/**
* {@code opens_index} must be a valid index into the constant pool. The entry at this
* index must be a {@link ConstantPoolPackageInfo} structure representing a package
* opened by the current module.
* @return {@code opens_index}
*/
public int getOpensIndex() {
return opens_index & 0xffff;
}
/**
* The value of {@code opens_flags} is as follows:
* <ul>
* <li> 0x1000 (ACC_SYNTHETIC) </li>
* <li> 0x8000 (ACC_MANDATED) </li>
* </ul>
* @return {@code opens_flags}
*/
public short getOpensFlags() {
return opens_flags;
}
/**
* {@code opens_to_count} indicates the number of entries in the {@code opens_to_index}
* table.
* @return {@code opens_to_count}
*/
public int getOpensToCount() {
return opens_to_count & 0xffff;
}
/**
* Each entry in the {@code opens_to_index} table must be a valid index into
* the constant pool. The entry at that index must be a {@link ConstantPoolModuleInfo} structure
* denoting a module whose code can access the types and members in this opened package.
* @param i desired entry
* @return index
*/
public int getOpensToEntry(int i) {
return opens_to_index[i] & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = new StructureDataType("exports", 0);
structure.add(WORD, "opens_index", null);
structure.add(WORD, "opens_flags", null);
structure.add(WORD, "opens_to_counts", null);
for (int i = 0; i < getOpensToCount(); i++) {
structure.add(WORD, "opens_to_index_" + i, null);
}
return structure;
}
}
/**
* Each entry in the {@code provides} table represents a service implementation for a
* given service interface.
*/
static class ModuleAttributeProvides implements StructConverter {
private short provides_index;
private short provides_with_count;
private short[] provides_with_index;
public ModuleAttributeProvides(BinaryReader reader) throws IOException {
provides_index = reader.readNextShort();
provides_with_count = reader.readNextShort();
provides_with_index = new short[getProvidesWithCount()];
for (int i = 0; i < getProvidesWithCount(); i++) {
provides_with_index[i] = reader.readNextShort();
}
}
/**
* {@code provides_index} must be a valid index into the constant pool. The entry
* at that index must be a {@link ConstantPoolClassInfo} structure representing a
* service interface for which the current module provides a service implementation.
* @return {@code provides_index}
*/
public int getProvidesIndex() {
return provides_index & 0xffff;
}
/**
* {@code provides_with_count} indicates the number of entries in the {@code provides_with_index} table
* @return {@code provides_with_count}
*/
public int getProvidesWithCount() {
return provides_with_count & 0xffff;
}
/**
* The value of each entry in the {@code provides_with_index} table must be a valid
* index into the constant pool. The entry at that index must be a {@link ConstantPoolClassInfo}
* structure representing a service implementation for the service interface specified by
* {@code provides_index}.
* @param i entry
* @return index
*/
public int getProvidesWithIndexEntry(int i) {
return provides_with_index[i];
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = new StructureDataType("provides", 0);
structure.add(WORD, "provides_index", null);
structure.add(WORD, "provides_with_counts", null);
for (int i = 0; i < getProvidesWithCount(); i++) {
structure.add(WORD, "provides_with_index_" + i, null);
}
return structure;
}
}
}

View File

@ -0,0 +1,57 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.javaclass.format.constantpool.ConstantPoolClassInfo;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
/**
* Note: text based on/taken from jvms12.pdf
* <p>
* Objects of this class indicate the main class of a module.
*/
public class ModuleMainClassAttribute extends AbstractAttributeInfo {
private short main_class_index;
protected ModuleMainClassAttribute(BinaryReader reader) throws IOException {
super(reader);
main_class_index = reader.readNextShort();
}
/**
* {@code main_class index} must be a valid index into the constant pool. The entry at
* that index must be a {@link ConstantPoolClassInfo} structure representing the main
* class of the current module.
* @return index of main class.
*/
public int getMainClassIndex() {
return main_class_index & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = getBaseStructure("ModuleMainClass_attribute");
structure.add(WORD, "main_class_index", null);
return structure;
}
}

View File

@ -0,0 +1,77 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.javaclass.format.constantpool.ConstantPoolPackageInfo;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
/**
* Note: text in this file based on/taken from jvms12.pdf
* <p>
* The {@code ModulePackages} attribute indicates all the packages of a module that are
* exported or opened by the {@code Module} attribute, as well as all the package of the service
* implementations recored in the {@code Module} attribute.
*/
public class ModulePackagesAttribute extends AbstractAttributeInfo {
private short package_count;
private short[] package_index;
protected ModulePackagesAttribute(BinaryReader reader) throws IOException {
super(reader);
package_count = reader.readNextShort();
package_index = new short[getPackageCount()];
for (short i = 0; i < getPackageCount(); i++) {
package_index[i] = reader.readNextShort();
}
}
/**
* The value of the {@code package_count} item indicates the number of entries
* in the {@code package_index} table
* @return {@code package_index}
*/
public int getPackageCount() {
return package_count & 0xffff;
}
/**
* The value of each entry in the {@code package_index} table must be a valid index
* into the constant pool. The entry at that index must be a {@link ConstantPoolPackageInfo}
* structure representing a package in the current module.
* @param i entry
* @return package index
*/
public int getPackageIndexEntry(int i) {
return package_index[i] & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = getBaseStructure("ModulePackages_attribute");
structure.add(WORD, "package_count", null);
for (int i = 0; i < package_index.length; ++i) {
structure.add(WORD, "classes" + i, null);
}
return structure;
}
}

View File

@ -0,0 +1,58 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.javaclass.format.constantpool.ConstantPoolClassInfo;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
/**
* Note: text taken from/based on jvms12.pdf
* <p>
* The {@code NestHost} attribute records the nest host of the next to which the current
* class or interface claims to belong.
*/
public class NestHostAttribute extends AbstractAttributeInfo {
private short host_class_index;
protected NestHostAttribute(BinaryReader reader) throws IOException {
super(reader);
host_class_index = reader.readNextShort();
}
/**
* The value of the {@code host_class_index} item must be a valid index into the constant
* pool. The entry at that index must be a {@link ConstantPoolClassInfo} structure representing
* a class or interface which is the nest host for the current class or interface.
* @return {@code host_class_index}
*/
public int getHostClassIndex() {
return host_class_index & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = getBaseStructure("NestHost_attribute");
structure.add(WORD, "host_class_index", null);
return structure;
}
}

View File

@ -0,0 +1,77 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.javaclass.format.constantpool.ConstantPoolClassInfo;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
/**
* Note: text taken from/based on jvms12.pdf
* <p>
* The {@NestMembers} attribute records the classes and interfaces that are authorized to
* claim membership in the nest hosted by the current class or interface.
*/
public class NestMembersAttribute extends AbstractAttributeInfo {
private short number_of_classes;
private short[] classes;
protected NestMembersAttribute(BinaryReader reader) throws IOException {
super(reader);
number_of_classes = reader.readNextShort();
classes = new short[getNumberOfClasses()];
for (short i = 0; i < getNumberOfClasses(); i++) {
classes[i] = reader.readNextShort();
}
}
/**
* The value of the {@code number_of_classes} item indicates the number of entries in
* the {@code classes} array.
* @return {@code number_of_classes}
*/
public int getNumberOfClasses() {
return number_of_classes & 0xffff;
}
/**
* Each value in the {@code classes} array must be a valid index into the constant pool.
* The constant pool entry at that index must be a {@link ConstantPoolClassInfo} structure
* representing a class or interface which is a member of the nest hosted by the current
* class or interface.
* @param i entry
* @return class index
*/
public int getClassesEntry(int i) {
return classes[i] & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = getBaseStructure("NestMembers_attribute");
structure.add(WORD, "number_of_classes", null);
for (int i = 0; i < classes.length; ++i) {
structure.add(WORD, "classes" + i, null);
}
return structure;
}
}

View File

@ -15,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -52,17 +52,17 @@ import java.io.IOException;
public class RuntimeInvisibleAnnotationsAttribute extends AbstractAttributeInfo {
private short numberOfAnnotations;
private AnnotationJava [] annotations;
private AnnotationJava[] annotations;
public RuntimeInvisibleAnnotationsAttribute( BinaryReader reader ) throws IOException {
super( reader );
public RuntimeInvisibleAnnotationsAttribute(BinaryReader reader) throws IOException {
super(reader);
numberOfAnnotations = reader.readNextShort();
annotations = new AnnotationJava[ numberOfAnnotations ];
annotations = new AnnotationJava[getNumberOfAnnotations()];
for ( int i = 0 ; i < numberOfAnnotations ; ++i ) {
annotations[ i ] = new AnnotationJava( reader );
for (int i = 0; i < getNumberOfAnnotations(); ++i) {
annotations[i] = new AnnotationJava(reader);
}
}
@ -74,8 +74,8 @@ public class RuntimeInvisibleAnnotationsAttribute extends AbstractAttributeInfo
* may be directly attached to a program element.
* @return the number of runtime-visible annotations
*/
public short getNumberOfAnnotations() {
return numberOfAnnotations;
public int getNumberOfAnnotations() {
return numberOfAnnotations & 0xffff;
}
/**
@ -83,17 +83,17 @@ public class RuntimeInvisibleAnnotationsAttribute extends AbstractAttributeInfo
* annotation on a program element.
* @return the annotations table
*/
public AnnotationJava [] getAnnotations() {
public AnnotationJava[] getAnnotations() {
return annotations;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "RuntimeInvisibleAnnotations_attribute" +"|" + numberOfAnnotations + "|";
StructureDataType structure = getBaseStructure( name );
structure.add( WORD, "num_annotations", null );
for ( int i = 0 ; i < annotations.length ; ++i ) {
structure.add( annotations[ i ].toDataType(), "annotation_" + i, null );
String name = "RuntimeInvisibleAnnotations_attribute" + "|" + numberOfAnnotations + "|";
StructureDataType structure = getBaseStructure(name);
structure.add(WORD, "num_annotations", null);
for (int i = 0; i < annotations.length; ++i) {
structure.add(annotations[i].toDataType(), "annotation_" + i, null);
}
return structure;
}

View File

@ -15,15 +15,15 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -65,22 +65,24 @@ public class RuntimeParameterAnnotationsAttribute extends AbstractAttributeInfo
private boolean _isVisible;
private byte numberOfParameters;
private Map<Integer, AnnotationJava []> parameterAnnotations = new HashMap<Integer, AnnotationJava []>();
private Map<Integer, AnnotationJava[]> parameterAnnotations =
new HashMap<Integer, AnnotationJava[]>();
public RuntimeParameterAnnotationsAttribute( BinaryReader reader, boolean isVisible ) throws IOException {
super( reader );
public RuntimeParameterAnnotationsAttribute(BinaryReader reader, boolean isVisible)
throws IOException {
super(reader);
_isVisible = isVisible;
numberOfParameters = reader.readNextByte();
for ( int i = 0 ; i < numberOfParameters ; ++i ) {
for (int i = 0; i < getNumberOfParameters(); ++i) {
short numberOfAnnotations = reader.readNextShort();
AnnotationJava [] annotations = new AnnotationJava[ numberOfAnnotations ];
for ( int a = 0 ; a < numberOfAnnotations ; ++a ) {
annotations[ a ] = new AnnotationJava( reader );
AnnotationJava[] annotations = new AnnotationJava[(numberOfAnnotations & 0xffff)];
for (int a = 0; a < (numberOfAnnotations & 0xffff); ++a) {
annotations[a] = new AnnotationJava(reader);
}
parameterAnnotations.put( i, annotations );
parameterAnnotations.put(i, annotations);
}
}
@ -100,8 +102,8 @@ public class RuntimeParameterAnnotationsAttribute extends AbstractAttributeInfo
* (This duplicates information that could be extracted from the method descriptor.)
* @return the number of parameters for this method
*/
public byte getNumberOfParameters() {
return numberOfParameters;
public int getNumberOfParameters() {
return numberOfParameters & 0xff;
}
/**
@ -120,23 +122,23 @@ public class RuntimeParameterAnnotationsAttribute extends AbstractAttributeInfo
* @param parameter the parameter index
* @return the annotations for the given parameter
*/
public AnnotationJava [] getParameterAnnotations( int parameter ) {
return parameterAnnotations.get( parameter );
public AnnotationJava[] getParameterAnnotations(int parameter) {
return parameterAnnotations.get(parameter);
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = _isVisible ?
"RuntimeVisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|" :
"RuntimeInvisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|";
String name = _isVisible
? "RuntimeVisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|"
: "RuntimeInvisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|";
StructureDataType structure = getBaseStructure( name );
structure.add( BYTE, "num_parameters", null );
for ( int i = 0 ; i < numberOfParameters ; ++i ) {
structure.add( WORD, "num_annotations_" + i, null );
AnnotationJava [] annotations = parameterAnnotations.get( i );
for ( int a = 0 ; a < annotations.length ; ++a ) {
structure.add( annotations[ a ].toDataType(), "annotations_" + i + "_" + a, null );
StructureDataType structure = getBaseStructure(name);
structure.add(BYTE, "num_parameters", null);
for (int i = 0; i < numberOfParameters; ++i) {
structure.add(WORD, "num_annotations_" + i, null);
AnnotationJava[] annotations = parameterAnnotations.get(i);
for (int a = 0; a < annotations.length; ++a) {
structure.add(annotations[a].toDataType(), "annotations_" + i + "_" + a, null);
}
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -45,8 +44,8 @@ public class SignatureAttribute extends AbstractAttributeInfo {
private short signatureIndex;
public SignatureAttribute( BinaryReader reader ) throws IOException {
super( reader );
public SignatureAttribute(BinaryReader reader) throws IOException {
super(reader);
signatureIndex = reader.readNextShort();
}
@ -60,14 +59,14 @@ public class SignatureAttribute extends AbstractAttributeInfo {
* type signature otherwise.
* @return a valid index into the constant_pool table
*/
public short getSignatureIndex() {
return signatureIndex;
public int getSignatureIndex() {
return signatureIndex & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = getBaseStructure( "Signature_attribute" );
structure.add( WORD, "signature_index", null );
StructureDataType structure = getBaseStructure("Signature_attribute");
structure.add(WORD, "signature_index", null);
return structure;
}

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -43,8 +42,8 @@ public class SourceFileAttribute extends AbstractAttributeInfo {
private short sourceFileIndex;
public SourceFileAttribute( BinaryReader reader ) throws IOException {
super( reader );
public SourceFileAttribute(BinaryReader reader) throws IOException {
super(reader);
sourceFileIndex = reader.readNextShort();
}
@ -62,14 +61,14 @@ public class SourceFileAttribute extends AbstractAttributeInfo {
* at the time the file name is actually used.
* @return a valid index into the constant_pool table
*/
public short getSourceFileIndex() {
return sourceFileIndex;
public int getSourceFileIndex() {
return sourceFileIndex & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = getBaseStructure( "SourceFile_attribute" );
structure.add( WORD, "sourcefile_index", null );
StructureDataType structure = getBaseStructure("SourceFile_attribute");
structure.add(WORD, "sourcefile_index", null);
return structure;
}

View File

@ -15,11 +15,11 @@
*/
package ghidra.javaclass.format.constantpool;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -46,7 +46,7 @@ public abstract class AbstractConstantPoolInfoJava implements StructConverter {
private long _offset;
private byte tag;
protected AbstractConstantPoolInfoJava( BinaryReader reader ) throws IOException {
protected AbstractConstantPoolInfoJava(BinaryReader reader) throws IOException {
_offset = reader.getPointerIndex();
tag = reader.readNextByte();

View File

@ -15,14 +15,12 @@
*/
package ghidra.javaclass.format.constantpool;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -56,8 +54,8 @@ public abstract class AbstractConstantPoolReferenceInfo extends AbstractConstant
* <p>
* @return a valid index into the constant_pool table
*/
public short getClassIndex() {
return classIndex;
public int getClassIndex() {
return classIndex & 0xffff;
}
/**
@ -77,17 +75,17 @@ public abstract class AbstractConstantPoolReferenceInfo extends AbstractConstant
* <p>
* @return a valid index into the constant_pool table
*/
public short getNameAndTypeIndex() {
return nameAndTypeIndex;
public int getNameAndTypeIndex() {
return nameAndTypeIndex & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "unnamed";
Structure structure = new StructureDataType( name, 0 );
structure.add( BYTE, "tag", null );
structure.add( WORD, "class_index", null );
structure.add( WORD, "name_and_type_index", null );
Structure structure = new StructureDataType(name, 0);
structure.add(BYTE, "tag", null);
structure.add(WORD, "class_index", null);
structure.add(WORD, "name_and_type_index", null);
return structure;
}

View File

@ -18,9 +18,7 @@ package ghidra.javaclass.format.constantpool;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
@ -47,8 +45,8 @@ public class ConstantPoolClassInfo extends AbstractConstantPoolInfoJava {
private short nameIndex;
public ConstantPoolClassInfo( BinaryReader reader ) throws IOException {
super( reader );
public ConstantPoolClassInfo(BinaryReader reader) throws IOException {
super(reader);
nameIndex = reader.readNextShort();
}
@ -60,16 +58,16 @@ public class ConstantPoolClassInfo extends AbstractConstantPoolInfoJava {
* interface name encoded in internal form (?4.2.1).
* @return a valid index into the constant_pool table
*/
public short getNameIndex() {
return nameIndex;
public int getNameIndex() {
return nameIndex & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_Class_info";
Structure structure = new StructureDataType( name, 0 );
structure.add( BYTE, "tag", null );
structure.add( WORD, "name_index", null );
Structure structure = new StructureDataType(name, 0);
structure.add(BYTE, "tag", null);
structure.add(WORD, "name_index", null);
return structure;
}

View File

@ -0,0 +1,79 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.javaclass.format.constantpool;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* Note: text extracted from jvms12.pdf
* <p>
*
* The CONSTANT_Dynamic_info structure is defined as follows:
* <pre>
* CONSTANT_Dynamic_info {
* u1 tag;
* u2 bootstrap_method_attr_index;
* u2 name_and_type_index;
* }
* </pre>
*/
public class ConstantPoolDynamicInfo extends AbstractConstantPoolInfoJava {
private short bootstrap_method_attr_index;
private short name_and_type_index;
protected ConstantPoolDynamicInfo(BinaryReader reader) throws IOException {
super(reader);
bootstrap_method_attr_index = reader.readNextShort();
name_and_type_index = reader.readNextShort();
}
/**
* The value of the bootstrap_method_attr_index item must be a valid index
* into the bootstrap_methods array of the bootstrap method table of
* this class file.
* @return a valid index into the bootstrap_methods array
*/
public int getBootstrapMethodAttrIndex() {
return bootstrap_method_attr_index & 0xffff;
}
/**
* The value of the name_and_type_index item must be a valid index into
* the constant_pool table. The constant_pool entry at that index must be a
* CONSTANT_NameAndType_info structure representing a field descriptor.
* @return a valid index into the constant_pool table
*/
public int getNameAndTypeIndex() {
return name_and_type_index & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_Dynamic_info";
Structure structure = new StructureDataType(name, 0);
structure.add(BYTE, "tag", null);
structure.add(WORD, "bootstrap_method_attr_index", null);
structure.add(WORD, "name_and_type_index", null);
return structure;
}
}

View File

@ -15,62 +15,74 @@
*/
package ghidra.javaclass.format.constantpool;
import ghidra.app.util.bin.BinaryReader;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
public class ConstantPoolFactory {
public static AbstractConstantPoolInfoJava get( BinaryReader reader ) throws IOException {
public static AbstractConstantPoolInfoJava get(BinaryReader reader) throws IOException {
switch ( reader.peekNextByte() ) {
switch (reader.peekNextByte()) {
case ConstantPoolTagsJava.CONSTANT_Class:
return new ConstantPoolClassInfo( reader );
return new ConstantPoolClassInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Double:
return new ConstantPoolDoubleInfo( reader );
return new ConstantPoolDoubleInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Fieldref:
return new ConstantPoolFieldReferenceInfo( reader );
return new ConstantPoolFieldReferenceInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Float:
return new ConstantPoolFloatInfo( reader );
return new ConstantPoolFloatInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Integer:
return new ConstantPoolIntegerInfo( reader );
return new ConstantPoolIntegerInfo(reader);
case ConstantPoolTagsJava.CONSTANT_InterfaceMethodref:
return new ConstantPoolInterfaceMethodReferenceInfo( reader );
return new ConstantPoolInterfaceMethodReferenceInfo(reader);
case ConstantPoolTagsJava.CONSTANT_InvokeDynamic:
return new ConstantPoolInvokeDynamicInfo( reader );
return new ConstantPoolInvokeDynamicInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Long:
return new ConstantPoolLongInfo( reader );
return new ConstantPoolLongInfo(reader);
case ConstantPoolTagsJava.CONSTANT_MethodHandle:
return new ConstantPoolMethodHandleInfo( reader );
return new ConstantPoolMethodHandleInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Methodref:
return new ConstantPoolMethodReferenceInfo( reader );
return new ConstantPoolMethodReferenceInfo(reader);
case ConstantPoolTagsJava.CONSTANT_MethodType:
return new ConstantPoolMethodTypeInfo( reader );
return new ConstantPoolMethodTypeInfo(reader);
case ConstantPoolTagsJava.CONSTANT_NameAndType:
return new ConstantPoolNameAndTypeInfo( reader );
return new ConstantPoolNameAndTypeInfo(reader);
case ConstantPoolTagsJava.CONSTANT_String:
return new ConstantPoolStringInfo( reader );
return new ConstantPoolStringInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Utf8:
return new ConstantPoolUtf8Info( reader );
return new ConstantPoolUtf8Info(reader);
case ConstantPoolTagsJava.CONSTANT_Dynamic:
return new ConstantPoolDynamicInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Module:
return new ConstantPoolModuleInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Package:
return new ConstantPoolPackageInfo(reader);
case 0:
return null;
default:
throw new IllegalArgumentException(
"Unsupport Constant Pool Entry Type: " + reader.peekNextByte());
}
throw new RuntimeException();
}
}

View File

@ -15,19 +15,17 @@
*/
package ghidra.javaclass.format.constantpool;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
* The CONSTANT_InvokeDynamic_info structure is used by an invokedynamic
* instruction (?invokedynamic) to specify a bootstrap method, the dynamic
* instruction to specify a bootstrap method, the dynamic
* invocation name, the argument and return types of the call, and optionally, a
* sequence of additional constants called static arguments to the bootstrap method.
* <pre>
@ -43,8 +41,8 @@ public class ConstantPoolInvokeDynamicInfo extends AbstractConstantPoolInfoJava
private short bootstrapMethodAttrIndex;
private short nameAndTypeIndex;
public ConstantPoolInvokeDynamicInfo( BinaryReader reader ) throws IOException {
super( reader );
public ConstantPoolInvokeDynamicInfo(BinaryReader reader) throws IOException {
super(reader);
bootstrapMethodAttrIndex = reader.readNextShort();
nameAndTypeIndex = reader.readNextShort();
}
@ -55,8 +53,8 @@ public class ConstantPoolInvokeDynamicInfo extends AbstractConstantPoolInfoJava
* this class file.
* @return a valid index into the bootstrap_methods array
*/
public short getBootstrapMethodAttrIndex() {
return bootstrapMethodAttrIndex;
public int getBootstrapMethodAttrIndex() {
return bootstrapMethodAttrIndex & 0xffff;
}
/**
@ -66,17 +64,17 @@ public class ConstantPoolInvokeDynamicInfo extends AbstractConstantPoolInfoJava
* and method descriptor.
* @return a valid index into the constant_pool table
*/
public short getNameAndTypeIndex() {
return nameAndTypeIndex;
public int getNameAndTypeIndex() {
return nameAndTypeIndex & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_InvokeDynamic_info";
Structure structure = new StructureDataType( name, 0 );
structure.add( BYTE, "tag", null );
structure.add( WORD, "bootstrap_method_attr_index", null );
structure.add( WORD, "name_and_type_index", null );
Structure structure = new StructureDataType(name, 0);
structure.add(BYTE, "tag", null);
structure.add(WORD, "bootstrap_method_attr_index", null);
structure.add(WORD, "name_and_type_index", null);
return structure;
}

View File

@ -15,14 +15,11 @@
*/
package ghidra.javaclass.format.constantpool;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
@ -37,12 +34,12 @@ import java.io.IOException;
* </pre>
*/
public class ConstantPoolMethodHandleInfo extends AbstractConstantPoolInfoJava {
private byte referenceKind;
private int referenceIndex;
public ConstantPoolMethodHandleInfo( BinaryReader reader ) throws IOException {
super( reader );
private byte referenceKind;
private short referenceIndex;
public ConstantPoolMethodHandleInfo(BinaryReader reader) throws IOException {
super(reader);
referenceKind = reader.readNextByte();
referenceIndex = reader.readNextShort();
}
@ -101,16 +98,16 @@ public class ConstantPoolMethodHandleInfo extends AbstractConstantPoolInfoJava {
* @return a valid index into the constant_pool table
*/
public int getReferenceIndex() {
return referenceIndex;
return referenceIndex & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_MethodHandle_info";
Structure structure = new StructureDataType( name, 0 );
structure.add( BYTE, "tag", null );
structure.add( BYTE, "reference_kind", null );
structure.add( WORD, "reference_index", null );
Structure structure = new StructureDataType(name, 0);
structure.add(BYTE, "tag", null);
structure.add(BYTE, "reference_kind", null);
structure.add(WORD, "reference_index", null);
return structure;
}

View File

@ -18,9 +18,7 @@ package ghidra.javaclass.format.constantpool;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
@ -38,8 +36,8 @@ public class ConstantPoolMethodTypeInfo extends AbstractConstantPoolInfoJava {
private short descriptorIndex;
public ConstantPoolMethodTypeInfo( BinaryReader reader ) throws IOException {
super( reader );
public ConstantPoolMethodTypeInfo(BinaryReader reader) throws IOException {
super(reader);
descriptorIndex = reader.readNextShort();
}
@ -49,16 +47,16 @@ public class ConstantPoolMethodTypeInfo extends AbstractConstantPoolInfoJava {
* CONSTANT_Utf8_info structure representing a method descriptor.
* @return a valid index into the constant_pool table
*/
public short getDescriptorIndex() {
return descriptorIndex;
public int getDescriptorIndex() {
return descriptorIndex & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_MethodType_info";
Structure structure = new StructureDataType( name, 0 );
structure.add( BYTE, "tag", null );
structure.add( WORD, "descriptor_index", null );
Structure structure = new StructureDataType(name, 0);
structure.add(BYTE, "tag", null);
structure.add(WORD, "descriptor_index", null);
return structure;
}

View File

@ -0,0 +1,57 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.javaclass.format.constantpool;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* Note: text in comments taken from/based on jvms12.pdf
* <p>
* The {@code CONSTANT_Module_info} structure is used to represent a module.
*/
public class ConstantPoolModuleInfo extends AbstractConstantPoolInfoJava {
private short name_index;
protected ConstantPoolModuleInfo(BinaryReader reader) throws IOException {
super(reader);
name_index = reader.readNextShort();
}
/**
* The value of the {@code name_index} item must be a valid index into the constant pool.
* The entry at that index must be a {@link ConstantPoolUtf8Info} structure representing a
* valid module name.
* @return the module name index
*/
public int getNameIndex() {
return name_index & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_Module_info";
Structure structure = new StructureDataType(name, 0);
structure.add(BYTE, "tag", null);
structure.add(WORD, "name_index", null);
return structure;
}
}

View File

@ -15,14 +15,12 @@
*/
package ghidra.javaclass.format.constantpool;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -41,8 +39,8 @@ public class ConstantPoolNameAndTypeInfo extends AbstractConstantPoolInfoJava {
private short nameIndex;
private short descriptorIndex;
public ConstantPoolNameAndTypeInfo( BinaryReader reader ) throws IOException {
super( reader );
public ConstantPoolNameAndTypeInfo(BinaryReader reader) throws IOException {
super(reader);
nameIndex = reader.readNextShort();
descriptorIndex = reader.readNextShort();
}
@ -55,8 +53,8 @@ public class ConstantPoolNameAndTypeInfo extends AbstractConstantPoolInfoJava {
* method.
* @return a valid index into the constant_pool table to the name
*/
public short getNameIndex() {
return nameIndex;
public int getNameIndex() {
return nameIndex & 0xffff;
}
/**
@ -66,17 +64,17 @@ public class ConstantPoolNameAndTypeInfo extends AbstractConstantPoolInfoJava {
* or method descriptor.
* @return a valid index into the constant_pool table to the descriptor
*/
public short getDescriptorIndex() {
return descriptorIndex;
public int getDescriptorIndex() {
return descriptorIndex & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_NameAndType_info";
Structure structure = new StructureDataType( name, 0 );
structure.add( BYTE, "tag", null );
structure.add( WORD, "name_index", null );
structure.add( WORD, "descriptor_index", null );
Structure structure = new StructureDataType(name, 0);
structure.add(BYTE, "tag", null);
structure.add(WORD, "name_index", null);
structure.add(WORD, "descriptor_index", null);
return structure;
}

View File

@ -0,0 +1,57 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.javaclass.format.constantpool;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* Note: text taken from/based on jvms12.pdf
* <p>
* Objects of this class represent a package exported or opened by a module
*/
public class ConstantPoolPackageInfo extends AbstractConstantPoolInfoJava {
private short name_index;
protected ConstantPoolPackageInfo(BinaryReader reader) throws IOException {
super(reader);
name_index = reader.readNextShort();
}
/**
* The {@code name_index} must be a valid index into the constant pool. The entry at that index
* must be a {@link ConstantPoolUtf8Info} structure representing a valid package name (encoded
* in internal form).
* @return the name index
*/
public int getNameIndex() {
return name_index & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_Package_info";
Structure structure = new StructureDataType(name, 0);
structure.add(BYTE, "tag", null);
structure.add(WORD, "name_index", null);
return structure;
}
}

View File

@ -18,9 +18,7 @@ package ghidra.javaclass.format.constantpool;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
@ -39,7 +37,7 @@ public class ConstantPoolStringInfo extends AbstractConstantPoolInfoJava {
private short stringIndex;
public ConstantPoolStringInfo( BinaryReader reader ) throws IOException {
public ConstantPoolStringInfo(BinaryReader reader) throws IOException {
super(reader);
stringIndex = reader.readNextShort();
}
@ -51,16 +49,16 @@ public class ConstantPoolStringInfo extends AbstractConstantPoolInfoJava {
* code points to which the String object is to be initialized.
* @return a valid index into the constant_pool table
*/
public short getStringIndex() {
return stringIndex;
public int getStringIndex() {
return stringIndex & 0xffff;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_String_info";
Structure structure = new StructureDataType( name, 0 );
structure.add( BYTE, "tag", null );
structure.add( WORD, "string_index", null );
Structure structure = new StructureDataType(name, 0);
structure.add(BYTE, "tag", null);
structure.add(WORD, "string_index", null);
return structure;
}

View File

@ -17,19 +17,22 @@ package ghidra.javaclass.format.constantpool;
public final class ConstantPoolTagsJava {
public final static byte CONSTANT_Class = 7;
public final static byte CONSTANT_Fieldref = 9;
public final static byte CONSTANT_Methodref = 10;
public final static byte CONSTANT_InterfaceMethodref = 11;
public final static byte CONSTANT_String = 8;
public final static byte CONSTANT_Integer = 3;
public final static byte CONSTANT_Float = 4;
public final static byte CONSTANT_Long = 5;
public final static byte CONSTANT_Double = 6;
public final static byte CONSTANT_NameAndType = 12;
public final static byte CONSTANT_Utf8 = 1;
public final static byte CONSTANT_MethodHandle = 15;
public final static byte CONSTANT_MethodType = 16;
public final static byte CONSTANT_InvokeDynamic = 18;
public final static byte CONSTANT_Class = 7;
public final static byte CONSTANT_Fieldref = 9;
public final static byte CONSTANT_Methodref = 10;
public final static byte CONSTANT_InterfaceMethodref = 11;
public final static byte CONSTANT_String = 8;
public final static byte CONSTANT_Integer = 3;
public final static byte CONSTANT_Float = 4;
public final static byte CONSTANT_Long = 5;
public final static byte CONSTANT_Double = 6;
public final static byte CONSTANT_NameAndType = 12;
public final static byte CONSTANT_Utf8 = 1;
public final static byte CONSTANT_MethodHandle = 15;
public final static byte CONSTANT_MethodType = 16;
public final static byte CONSTANT_Dynamic = 17;
public final static byte CONSTANT_InvokeDynamic = 18;
public final static byte CONSTANT_Module = 19;
public final static byte CONSTANT_Package = 20;
}

View File

@ -41,12 +41,12 @@ import ghidra.util.exception.DuplicateNameException;
public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
private short length;
private byte [] bytes;
private byte[] bytes;
public ConstantPoolUtf8Info( BinaryReader reader ) throws IOException {
super( reader );
public ConstantPoolUtf8Info(BinaryReader reader) throws IOException {
super(reader);
length = reader.readNextShort();
bytes = reader.readNextByteArray( length );
bytes = reader.readNextByteArray(getLength());
}
/**
@ -55,8 +55,8 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
* structure are not null-terminated.
* @return the number of bytes in the bytes array
*/
public short getLength() {
return length;
public int getLength() {
return length & 0xffff;
}
/**
@ -65,7 +65,7 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
* range (byte)0xf0 - (byte)0xff.
* @return the bytes of the string
*/
public byte [] getBytes() {
public byte[] getBytes() {
return bytes;
}
@ -75,7 +75,7 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
* @return the byte array translated into a string
*/
public String getString() {
return new String( bytes );
return new String(bytes);
}
@Override
@ -86,10 +86,10 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_Utf8_info" + "|" + length + "|";
Structure structure = new StructureDataType( name, 0 );
structure.add( BYTE, "tag", null );
structure.add( WORD, "length", null );
if ( length > 0 ) {
Structure structure = new StructureDataType(name, 0);
structure.add(BYTE, "tag", null);
structure.add(WORD, "length", null);
if (length > 0) {
structure.add(UTF8, length, "data", null);
}
return structure;

View File

@ -28,9 +28,8 @@ import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
public class InvokeMethodsTest {
@Test
public void testEmitPcodeToResolveMethodReferenceInvokeDynamic() throws IOException{
public void testEmitPcodeToResolveMethodReferenceInvokeDynamic() throws IOException {
short bootstrap = 0;
ArrayList<Byte> classFile = new ArrayList<>();
TestClassFileCreator.appendMagic(classFile);
@ -39,151 +38,173 @@ public class InvokeMethodsTest {
TestClassFileCreator.appendInvokeDynamicInfo(classFile, bootstrap, (short) 2); //1
TestClassFileCreator.appendNameAndType(classFile, (short) 3, (short) 4); //2
TestClassFileCreator.appendUtf8(classFile, "dynamicMethodName"); //3
TestClassFileCreator.appendUtf8(classFile,"(I)I"); //4 (descriptor)
TestClassFileCreator.appendUtf8(classFile, "(I)I"); //4 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
StringBuilder pCode = new StringBuilder();
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
JavaInvocationType.INVOKE_DYNAMIC);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
assertEquals("incorrect pcode for dynamic invocation", expected.toString(), pCode.toString());
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
assertEquals("incorrect pcode for dynamic invocation", expected.toString(),
pCode.toString());
}
@Test
public void testEmitPcodeToResolveMethodReferenceInvokeInterface() throws IOException{
public void testEmitPcodeToResolveMethodReferenceInvokeInterface() throws IOException {
ArrayList<Byte> classFile = new ArrayList<>();
TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7);
TestClassFileCreator.appendInterfaceMethodRef(classFile, (short) 2, (short)3); //1
TestClassFileCreator.appendInterfaceMethodRef(classFile, (short) 2, (short) 3); //1
TestClassFileCreator.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "interfaceMethodName"); //5
TestClassFileCreator.appendUtf8(classFile,"(I)I"); //6 (descriptor)
TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
StringBuilder pCode = new StringBuilder();
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_INTERFACE);
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
JavaInvocationType.INVOKE_INTERFACE);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1", ConstantPoolJava.CPOOL_INVOKEINTERFACE);
assertEquals("incorrect pcode for interface method invocation", expected.toString(), pCode.toString());
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1",
ConstantPoolJava.CPOOL_INVOKEINTERFACE);
assertEquals("incorrect pcode for interface method invocation", expected.toString(),
pCode.toString());
}
@Test
public void testEmitPcodeToResolveMethodReferenceInvokeSpecial() throws IOException{
public void testEmitPcodeToResolveMethodReferenceInvokeSpecial() throws IOException {
ArrayList<Byte> classFile = new ArrayList<>();
TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7);
TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short)3); //1
TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short) 3); //1
TestClassFileCreator.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "methodName"); //5
TestClassFileCreator.appendUtf8(classFile,"(I)I"); //6 (descriptor)
TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
StringBuilder pCode = new StringBuilder();
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_SPECIAL);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1", ConstantPoolJava.CPOOL_INVOKESPECIAL);
assertEquals("incorrect pcode for special method invocation", expected.toString(), pCode.toString());
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
JavaInvocationType.INVOKE_SPECIAL);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1",
ConstantPoolJava.CPOOL_INVOKESPECIAL);
assertEquals("incorrect pcode for special method invocation", expected.toString(),
pCode.toString());
}
@Test
public void testEmitPcodeToResolveMethodReferenceInvokeStatic() throws IOException{
public void testEmitPcodeToResolveMethodReferenceInvokeStatic() throws IOException {
ArrayList<Byte> classFile = new ArrayList<>();
TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7);
TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short)3); //1
TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short) 3); //1
TestClassFileCreator.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "methodName"); //5
TestClassFileCreator.appendUtf8(classFile,"(I)I"); //6 (descriptor)
TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
StringBuilder pCode = new StringBuilder();
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_STATIC);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKESTATIC);
assertEquals("incorrect pcode for static method invocation", expected.toString(), pCode.toString());
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
JavaInvocationType.INVOKE_STATIC);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKESTATIC);
assertEquals("incorrect pcode for static method invocation", expected.toString(),
pCode.toString());
}
@Test
public void testEmitPcodeToResolveMethodReferenceInvokeVirtual() throws IOException{
public void testEmitPcodeToResolveMethodReferenceInvokeVirtual() throws IOException {
ArrayList<Byte> classFile = new ArrayList<>();
TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7);
TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short)3); //1
TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short) 3); //1
TestClassFileCreator.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "methodName"); //5
TestClassFileCreator.appendUtf8(classFile,"(I)I"); //6 (descriptor)
TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
StringBuilder pCode = new StringBuilder();
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_VIRTUAL);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1", ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
assertEquals("incorrect pcode for static method invocation", expected.toString(), pCode.toString());
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
JavaInvocationType.INVOKE_VIRTUAL);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1",
ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
assertEquals("incorrect pcode for static method invocation", expected.toString(),
pCode.toString());
}
@Test
public void testEmitPcodeToReverseStackNoParamsNoThis(){
public void testEmitPcodeToReverseStackNoParamsNoThis() {
StringBuilder pCode = new StringBuilder();
//InvokeMethods.emitPcodeToReverseStack(pCode, new ArrayList<JavaComputationalCategory>(), false);
StringBuilder expected = new StringBuilder();
assertEquals("incorrect pcode reversing stack: no params no this", expected.toString(), pCode.toString());
assertEquals("incorrect pcode reversing stack: no params no this", expected.toString(),
pCode.toString());
}
//test bad category
@Test
public void testGetPcodeForInvoke() throws IOException{
public void testGetPcodeForInvoke() throws IOException {
ArrayList<Byte> classFile = new ArrayList<>();
TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 5);
TestClassFileCreator.appendInvokeDynamicInfo(classFile, (short) 0, (short)2); //1
TestClassFileCreator.appendInvokeDynamicInfo(classFile, (short) 0, (short) 2); //1
TestClassFileCreator.appendNameAndType(classFile, (short) 3, (short) 4); //2
TestClassFileCreator.appendUtf8(classFile, "dynamicMethodName"); //3
TestClassFileCreator.appendUtf8(classFile,"(JJII)I"); //4 (descriptor)
TestClassFileCreator.appendUtf8(classFile, "(JJII)I"); //4 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = InvokeMethods.getPcodeForInvoke(1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode =
InvokeMethods.getPcodeForInvoke(1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
StringBuilder expected = new StringBuilder();
String descriptor = DescriptorDecoder.getDescriptorForInvoke(1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
List<JavaComputationalCategory> categories = DescriptorDecoder.getParameterCategories(descriptor);
String descriptor = DescriptorDecoder.getDescriptorForInvoke(1, constantPool,
JavaInvocationType.INVOKE_DYNAMIC);
List<JavaComputationalCategory> categories =
DescriptorDecoder.getParameterCategories(descriptor);
InvokeMethods.emitPcodeToMoveParams(expected, categories, false, 24);
InvokeMethods.emitPcodeToResolveMethodReference(expected, 1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
PcodeTextEmitter.emitIndirectCall(expected, InvokeMethods.CALL_TARGET);
PcodeTextEmitter.emitPushCat1Value(expected, InvokeMethods.CAT_1_RETURN);
System.out.println(pCode);
System.out.println(expected);
InvokeMethods.emitPcodeToResolveMethodReference(expected, 1, constantPool,
JavaInvocationType.INVOKE_DYNAMIC);
PcodeTextEmitter.emitIndirectCall(expected, InvokeMethods.CALL_TARGET);
PcodeTextEmitter.emitPushCat1Value(expected, InvokeMethods.CAT_1_RETURN);
assertEquals("incorrect pcode for invoke dynamic: (JJII)I", expected.toString(), pCode);
}

View File

@ -22,35 +22,35 @@ import org.junit.Test;
public class PcodeTextEmitterTest {
@Test
public void testEmitPushType1Value(){
public void testEmitPushType1Value() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitPushCat1Value(pCode, "x");
assertTrue(pCode.toString().equals("SP = SP - 4;\n*:4 SP = x;\n"));
}
@Test
public void testEmitPushType2Value(){
public void testEmitPushType2Value() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitPushCat2Value(pCode, "x");
assertTrue(pCode.toString().equals("SP = SP - 8;\n*:8 SP = x;\n"));
}
@Test
public void testEmitPopType1Value(){
public void testEmitPopType1Value() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitPopCat1Value(pCode, "x");
assertTrue(pCode.toString().equals("x:4 = *:4 SP;\nSP = SP + 4;\n"));
}
@Test
public void testEmitPopType2Value(){
public void testEmitPopType2Value() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitPopCat2Value(pCode, "x");
assertTrue(pCode.toString().equals("x:8 = *:8 SP;\nSP = SP + 8;\n"));
}
@Test
public void testEmitVarnodeBytesFromPcodeOpCall(){
@Test
public void testEmitVarnodeBytesFromPcodeOpCall() {
StringBuilder pCode = new StringBuilder();
//test no args
@ -64,9 +64,9 @@ public class PcodeTextEmitterTest {
//two args
pCode = new StringBuilder();
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 4, "PCODEOP", "ARG1", "ARG2");
assertTrue(pCode.toString().equals("LHS:4 = PCODEOP(ARG1,ARG2);\n"));
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 4, "PCODEOP", "ARG1",
"ARG2");
assertTrue(pCode.toString().equals("LHS:4 = PCODEOP(ARG1,ARG2);\n"));
//test no args
pCode = new StringBuilder();
@ -80,12 +80,13 @@ public class PcodeTextEmitterTest {
//two args
pCode = new StringBuilder();
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 8, "PCODEOP", "ARG1", "ARG2");
assertTrue(pCode.toString().equals("LHS:8 = PCODEOP(ARG1,ARG2);\n"));
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 8, "PCODEOP", "ARG1",
"ARG2");
assertTrue(pCode.toString().equals("LHS:8 = PCODEOP(ARG1,ARG2);\n"));
}
@Test
public void testEmitVoidPcodeOpCall(){
@Test
public void testEmitVoidPcodeOpCall() {
StringBuilder pCode = new StringBuilder();
//test no args
@ -94,17 +95,17 @@ public class PcodeTextEmitterTest {
//one arg
pCode = new StringBuilder();
PcodeTextEmitter.emitVoidPcodeOpCall(pCode,"PCODEOP", "ARG1");
PcodeTextEmitter.emitVoidPcodeOpCall(pCode, "PCODEOP", "ARG1");
assertTrue(pCode.toString().equals("PCODEOP(ARG1);\n"));
//two args
pCode = new StringBuilder();
PcodeTextEmitter.emitVoidPcodeOpCall(pCode,"PCODEOP", "ARG1", "ARG2");
assertTrue(pCode.toString().equals("PCODEOP(ARG1,ARG2);\n"));
PcodeTextEmitter.emitVoidPcodeOpCall(pCode, "PCODEOP", "ARG1", "ARG2");
assertTrue(pCode.toString().equals("PCODEOP(ARG1,ARG2);\n"));
}
@Test
public void testEmitAssignRegisterFromPcodeOpCall(){
public void testEmitAssignRegisterFromPcodeOpCall() {
//void call
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, "REG", "TEST");
@ -122,38 +123,59 @@ public class PcodeTextEmitterTest {
}
@Test
public void testEmitAssignConstantToRegister(){
public void testEmitAssignConstantToRegister() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitAssignConstantToRegister(pCode, "REGISTER", 0);
assertTrue(pCode.toString().equals("REGISTER = 0x0;\n"));
}
@Test
public void testEmitLabelDef(){
public void testEmitLabelDef() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitLabelDefinition(pCode, "LABEL");
assertEquals("bad label definition emitted", "<LABEL>\n", pCode.toString());
}
@Test
public void testEmitAddToStackPointer(){
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitAddToStackPointer(pCode, 4);
assertEquals("SP = SP + 4;\n", pCode.toString());
}
@Test
public void testEmitIndirectCall(){
public void testEmitIndirectCall() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitIndirectCall(pCode, "call_target");
assertEquals("call [call_target];\n", pCode.toString());
}
@Test
public void testEmitWriteToMemory(){
public void testEmitWriteToMemory() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitWriteToMemory(pCode, "ram", 4, "offset", "test");
assertEquals("*[ram]:4 offset = test;\n", pCode.toString());
}
@Test
public void testEmitSignExtension() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitSignExtension(pCode, "dest", 4, "src");
assertEquals("dest:4 = sext(src);\n", pCode.toString());
}
@Test
public void testEmitZeroExtension() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitZeroExtension(pCode, "dest", 4, "src");
assertEquals("dest:4 = zext(src);\n", pCode.toString());
}
@Test
public void testEmitTruncate() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitTruncate(pCode, "dest", 4, "src");
assertEquals("dest = src:4;\n", pCode.toString());
}
@Test
public void testAssignVarnodeFromDereference() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, "dest", 4, "src");
assertEquals("dest:4 = *:4 src;\n", pCode.toString());
}
}

View File

@ -15,8 +15,7 @@
*/
package ghidra.app.util.pcodeInject;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.ArrayList;
@ -26,36 +25,37 @@ import org.junit.Test;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
public class ReferenceMethodsTest {
public ReferenceMethodsTest(){
public ReferenceMethodsTest() {
}
@Test
public void testGetStatic1() throws IOException {
ArrayList<Byte> classFile = new ArrayList<>();
TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7);
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
TestClassFileCreator.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"I"); //6 (descriptor)
TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForGetStatic(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.VALUE, 4, ConstantPoolJava.CPOOL_OP , "0", "1", ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.TEMP_1, 4,
ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromDereference(expected, ReferenceMethods.VALUE, 4,
ReferenceMethods.TEMP_1);
PcodeTextEmitter.emitPushCat1Value(expected, ReferenceMethods.VALUE);
assertTrue(pCode.equals(expected.toString()));
assertTrue(pCode.equals(expected.toString()));
}
@Test
@ -64,180 +64,204 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7);
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
TestClassFileCreator.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"J"); //6 (descriptor)
TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForGetStatic(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.VALUE, 8, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.TEMP_1, 8,
ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromDereference(expected, ReferenceMethods.VALUE, 8,
ReferenceMethods.TEMP_1);
PcodeTextEmitter.emitPushCat2Value(expected, ReferenceMethods.VALUE);
assertEquals(pCode,expected.toString());
assertEquals(pCode, expected.toString());
}
@Test
public void testPutStatic1() throws IOException {
ArrayList<Byte> classFile = new ArrayList<>();
TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7);
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
TestClassFileCreator.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"I"); //6 (descriptor)
TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForPutStatic(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 4, ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE);
assertEquals(pCode,expected.toString());
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET,
4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 4,
ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE);
assertEquals(pCode, expected.toString());
}
@Test
public void testPutStatic2() throws IOException {
ArrayList<Byte> classFile = new ArrayList<>();
TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7);
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
TestClassFileCreator.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"J"); //6 (descriptor)
TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForPutStatic(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat2Value(expected, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 8, ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE);
assertEquals(pCode,expected.toString());
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET,
4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 8,
ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE);
assertEquals(pCode, expected.toString());
}
@Test
public void testGetField1() throws IOException {
ArrayList<Byte> classFile = new ArrayList<>();
TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7);
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
TestClassFileCreator.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"I"); //6 (descriptor)
TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForGetField(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.VALUE, 4, ConstantPoolJava.CPOOL_OP , ReferenceMethods.OBJECT_REF, "1", ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.TEMP_1, 4,
ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1",
ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromDereference(expected, ReferenceMethods.VALUE, 4,
ReferenceMethods.TEMP_1);
PcodeTextEmitter.emitPushCat1Value(expected, ReferenceMethods.VALUE);
assertEquals(pCode,expected.toString());
assertEquals(pCode, expected.toString());
}
@Test
public void testGetField2() throws IOException {
ArrayList<Byte> classFile = new ArrayList<>();
TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7);
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
TestClassFileCreator.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"J"); //6 (descriptor)
TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForGetField(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.VALUE, 8, ConstantPoolJava.CPOOL_OP , ReferenceMethods.OBJECT_REF, "1", ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.TEMP_1, 8,
ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1",
ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromDereference(expected, ReferenceMethods.VALUE, 8,
ReferenceMethods.TEMP_1);
PcodeTextEmitter.emitPushCat2Value(expected, ReferenceMethods.VALUE);
assertEquals(pCode,expected.toString());
assertEquals(pCode, expected.toString());
}
@Test
public void testPutField1() throws IOException {
ArrayList<Byte> classFile = new ArrayList<>();
TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7);
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
TestClassFileCreator.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"I"); //6 (descriptor)
TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForPutField(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1", ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 4, ReferenceMethods.FIELD_OFFSET, ReferenceMethods.NEW_VALUE);
assertEquals(pCode,expected.toString());
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET,
4, ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1",
ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 4,
ReferenceMethods.FIELD_OFFSET, ReferenceMethods.NEW_VALUE);
assertEquals(pCode, expected.toString());
}
@Test
public void testPutField2() throws IOException {
ArrayList<Byte> classFile = new ArrayList<>();
TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7);
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
TestClassFileCreator.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"J"); //6 (descriptor)
TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForPutField(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat2Value(expected, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1", ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 8, ReferenceMethods.FIELD_OFFSET, ReferenceMethods.NEW_VALUE);
assertEquals(pCode,expected.toString());
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET,
4, ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1",
ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 8,
ReferenceMethods.FIELD_OFFSET, ReferenceMethods.NEW_VALUE);
assertEquals(pCode, expected.toString());
}
}

View File

@ -15,8 +15,7 @@
*/
package ghidra.javaclass.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.ArrayList;
@ -437,4 +436,78 @@ public class DescriptorDecoderTest extends AbstractGenericTest {
assertEquals("Integer[][][]", typeNames.get(3));
}
@Test
public void testGetReturnTypeOfMethodDescriptor() {
String ItoInt = "(I)Ljava/lang/Integer;";
DataType type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(ItoInt, dtm);
assertEquals(new PointerDataType(dtInteger), type);
String IntIntInttoInt =
"(Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;";
type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(IntIntInttoInt, dtm);
assertEquals(new PointerDataType(dtInteger), type);
String voidTovoid = "()V";
type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(voidTovoid, dtm);
assertEquals(DataType.VOID, type);
String ItoI = "(I)I";
type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(ItoI, dtm);
assertEquals(IntegerDataType.dataType, type);
String OneDIntTwoDInttoInt =
"([Ljava/lang/Integer;[[Ljava/lang/Integer;)Ljava/lang/Integer;";
type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(OneDIntTwoDInttoInt, dtm);
assertEquals(new PointerDataType(dtInteger), type);
String DDtoD = "(DD)D";
type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(DDtoD, dtm);
assertEquals(DoubleDataType.dataType, type);
String crazy = "(DJLjava/lang/Integer;[[Ljava/lang/Integer;)[[Ljava/lang/Integer;";
type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(crazy, dtm);
assertEquals(dtm.getPointer(DWordDataType.dataType), type);
String getClass = "()Ljava/lang/Class";
type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(getClass, dtm);
assertEquals(PointerDataType.dataType, type);
}
@Test
public void testGetParameterString() {
String ItoInt = "(I)Ljava/lang/Integer;";
String paramString = DescriptorDecoder.getParameterString(ItoInt);
assertEquals("(int)", paramString);
String IntIntInttoInt =
"(Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;";
paramString = DescriptorDecoder.getParameterString(IntIntInttoInt);
assertEquals("(java.lang.Integer, java.lang.Integer, java.lang.Integer)", paramString);
String voidToVoid = "()V";
paramString = DescriptorDecoder.getParameterString(voidToVoid);
assertEquals("()", paramString);
String ItoI = "(I)I";
paramString = DescriptorDecoder.getParameterString(ItoI);
assertEquals("(int)", paramString);
String OneDIntTwoDInttoInt =
"([Ljava/lang/Integer;[[Ljava/lang/Integer;)Ljava/lang/Integer;";
paramString = DescriptorDecoder.getParameterString(OneDIntTwoDInttoInt);
assertEquals("(java.lang.Integer[], java.lang.Integer[][])", paramString);
String DDtoD = "(DD)D";
paramString = DescriptorDecoder.getParameterString(DDtoD);
assertEquals("(double, double)", paramString);
String crazy = "(DJLjava/lang/Integer;[[Ljava/lang/Integer;)[[Ljava/lang/Integer;";
paramString = DescriptorDecoder.getParameterString(crazy);
assertEquals("(double, long, java.lang.Integer, java.lang.Integer[][])", paramString);
}
}

View File

@ -0,0 +1,42 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.javaclass.test;
import static org.junit.Assert.*;
import org.junit.Test;
import ghidra.javaclass.flags.MethodsInfoAccessFlags;
public class MethodsInfoAccessFlagsTest {
@Test
public void testToString() {
int flags = MethodsInfoAccessFlags.ACC_PUBLIC.getValue() |
MethodsInfoAccessFlags.ACC_STATIC.getValue() |
MethodsInfoAccessFlags.ACC_FINAL.getValue() |
MethodsInfoAccessFlags.ACC_SYNCHRONIZED.getValue();
String flagString = MethodsInfoAccessFlags.toString(flags);
assertEquals("public static final synchronized", flagString);
flags = MethodsInfoAccessFlags.ACC_PROTECTED.getValue() |
MethodsInfoAccessFlags.ACC_NATIVE.getValue();
assertEquals("protected native", MethodsInfoAccessFlags.toString(flags));
flags = MethodsInfoAccessFlags.ACC_PRIVATE.getValue() |
MethodsInfoAccessFlags.ACC_ABSTRACT.getValue();
assertEquals("private abstract", MethodsInfoAccessFlags.toString(flags));
}
}