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,14 +26,14 @@ import ghidra.util.xml.SpecXmlUtils;
* *
*/ */
public abstract class ConstantPool { public abstract class ConstantPool {
public static final int PRIMITIVE = 0; // Constant -value- of datatype -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 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 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_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 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 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 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 CHECK_CAST = 7; // Pointer to object, new name in -token-, new datatype in -type-
public static class Record { public static class Record {
public int tag; // The type of the record public int tag; // The type of the record
@ -44,30 +44,40 @@ public abstract class ConstantPool {
public boolean hasThisPtr = false; public boolean hasThisPtr = false;
public boolean isConstructor = false; public boolean isConstructor = false;
public StringBuilder build(long ref,PcodeDataTypeManager dtmanage) { public StringBuilder build(long ref, PcodeDataTypeManager dtmanage) {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
buf.append("<cpoolrec"); buf.append("<cpoolrec");
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "ref", ref); SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "ref", ref);
if (tag == STRING_LITERAL) if (tag == STRING_LITERAL) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "string"); SpecXmlUtils.encodeStringAttribute(buf, "tag", "string");
else if (tag == CLASS_REFERENCE) }
else if (tag == CLASS_REFERENCE) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "classref"); SpecXmlUtils.encodeStringAttribute(buf, "tag", "classref");
else if (tag == POINTER_METHOD) }
else if (tag == POINTER_METHOD) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "method"); SpecXmlUtils.encodeStringAttribute(buf, "tag", "method");
else if (tag == POINTER_FIELD) }
else if (tag == POINTER_FIELD) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "field"); SpecXmlUtils.encodeStringAttribute(buf, "tag", "field");
else if (tag == ARRAY_LENGTH) }
else if (tag == ARRAY_LENGTH) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "arraylength"); SpecXmlUtils.encodeStringAttribute(buf, "tag", "arraylength");
else if (tag == INSTANCE_OF) }
else if (tag == INSTANCE_OF) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "instanceof"); SpecXmlUtils.encodeStringAttribute(buf, "tag", "instanceof");
else if (tag == CHECK_CAST) }
else if (tag == CHECK_CAST) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "checkcast"); SpecXmlUtils.encodeStringAttribute(buf, "tag", "checkcast");
else }
else {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "primitive"); SpecXmlUtils.encodeStringAttribute(buf, "tag", "primitive");
if (hasThisPtr) }
if (hasThisPtr) {
SpecXmlUtils.encodeBooleanAttribute(buf, "hasthis", true); SpecXmlUtils.encodeBooleanAttribute(buf, "hasthis", true);
if (isConstructor) }
if (isConstructor) {
SpecXmlUtils.encodeBooleanAttribute(buf, "constructor", true); SpecXmlUtils.encodeBooleanAttribute(buf, "constructor", true);
}
buf.append(">\n"); buf.append(">\n");
if (tag == PRIMITIVE) { if (tag == PRIMITIVE) {
buf.append("<value>"); buf.append("<value>");

View file

@ -100,14 +100,6 @@
</pcode> </pcode>
</callotherfixup> </callotherfixup>
<callotherfixup targetop="lookupswitchCallOther">
<pcode dynamic="true">
<input name="default"/>
<input name="numPairs"/>
<input name ="padding"/>
</pcode>
</callotherfixup>
<callotherfixup targetop="multianewarrayCallOther"> <callotherfixup targetop="multianewarrayCallOther">
<pcode dynamic="true"> <pcode dynamic="true">
<input name="cpool_index_multianewarray"/> <input name="cpool_index_multianewarray"/>

View file

@ -66,7 +66,6 @@ define pcodeop invokeinterfaceCallOther;
define pcodeop invokespecialCallOther; define pcodeop invokespecialCallOther;
define pcodeop invokestaticCallOther; define pcodeop invokestaticCallOther;
define pcodeop invokevirtualCallOther; define pcodeop invokevirtualCallOther;
define pcodeop lookupswitchCallOther;
define pcodeop multianewarrayCallOther; define pcodeop multianewarrayCallOther;
define pcodeop putStaticCallOther; define pcodeop putStaticCallOther;
define pcodeop putFieldCallOther; 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; ] :checkcast index is (in_table_switch=0 & in_lookup_switch=0 & op=0xc0); indexbyte1; indexbyte2 [ index = indexbyte1<<8 | indexbyte2; ]
{ {
_object: $(SIZE) = *:$(SIZE) SP; #_object: $(SIZE) = *:$(SIZE) SP;
throwExceptionOp(_object); #throwExceptionOp(_object);
#_res:1 = cpool(_object,index,$(CPOOL_CHECKCAST)); #_res:1 = cpool(_object,index,$(CPOOL_CHECKCAST));
#throwExceptionOp(_res); #throwExceptionOp(_res);
@ -428,9 +427,12 @@ Default:"default" addr is defaultbyte1; defaultbyte2; defaultbyte3; defaultbyte4
#_ref: $(SIZE) = cpool(0:4,index,$(CPOOL_CHECKCAST)); #_ref: $(SIZE) = cpool(0:4,index,$(CPOOL_CHECKCAST));
#checkcastOp(_object,_ref); #checkcastOp(_object,_ref);
#_object:$(SIZE) = 0; _object:$(SIZE) = 0;
#pop(_object); pop(_object);
#_res:1 = cpool(_object,index,$(CPOOL_INSTANCEOF)); _object = cpool(_object,index,$(CPOOL_CHECKCAST));
push(_object);
#_res:1 = cpool(_object,index,$(CPOOL_CHECKCAST));
#_result:$(SIZE) = zext(_res); #_result:$(SIZE) = zext(_res);
#push(_result); #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.AbstractConstantPoolInfoJava;
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info; import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.lang.LanguageCompilerSpecPair; import ghidra.program.model.lang.LanguageCompilerSpecPair;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Program; 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 static final String JAVA_NAME = "Java Class File";
private Register alignmentReg; private Register alignmentReg;
public static final long CODE_OFFSET = 0x10000L;
public static final String CONSTANT_POOL = "constantPool";
@Override @Override
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException { public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
@ -61,22 +64,24 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
return loadSpecs; return loadSpecs;
} }
private boolean checkClass(ByteProvider provider) { private boolean checkClass(ByteProvider provider) throws IOException {
BinaryReader reader = new BinaryReader(provider, false); 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 { try {
classFile = new ClassFileJava(reader); new ClassFileJava(reader);
} }
catch (IOException e) { catch (IOException e) {
return false; return false;
} catch (RuntimeException re) { }
catch (RuntimeException re) {
return false; return false;
} }
int magic = classFile.getMagic(); return true;
if (magic == 0xCAFEBABE) {
return true;
}
return false;
} }
@Override @Override
@ -117,7 +122,7 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
throws LockException, MemoryConflictException, AddressOverflowException, throws LockException, MemoryConflictException, AddressOverflowException,
CancelledException, DuplicateNameException, IOException { CancelledException, DuplicateNameException, IOException {
AddressFactory af = program.getAddressFactory(); AddressFactory af = program.getAddressFactory();
AddressSpace space = af.getAddressSpace("constantPool"); AddressSpace space = af.getAddressSpace(CONSTANT_POOL);
Memory memory = program.getMemory(); Memory memory = program.getMemory();
alignmentReg = program.getRegister("alignmentPad"); alignmentReg = program.getRegister("alignmentPad");
@ -130,28 +135,27 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
memory.createInitializedBlock("_" + provider.getName() + "_", address, memory.createInitializedBlock("_" + provider.getName() + "_", address,
provider.getInputStream(0), provider.length(), monitor, false); provider.getInputStream(0), provider.length(), monitor, false);
createMethodLookupMemoryBlock( program, monitor ); createMethodLookupMemoryBlock(program, monitor);
createMethodMemoryBlocks(program, provider, classFile, monitor); createMethodMemoryBlocks(program, provider, classFile, monitor);
} }
private void createMethodLookupMemoryBlock(Program program, TaskMonitor 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; MemoryBlock block = null;
Memory memory = program.getMemory(); Memory memory = program.getMemory();
try { 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 catch (LockException | DuplicateNameException | MemoryConflictException
| AddressOverflowException | CancelledException e) { | AddressOverflowException | CancelledException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
block.setRead( true ); block.setRead(true);
block.setWrite( false ); block.setWrite(false);
block.setExecute( false ); block.setExecute(false);
} }
@ -164,12 +168,11 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
monitor.setProgress(0); monitor.setProgress(0);
monitor.setMaximum(methods.length); monitor.setMaximum(methods.length);
long codeOffset = 0x10000; Address start = toAddr(program, CODE_OFFSET);
Address start = toAddr(program, codeOffset);
try { try {
//program.setImageBase(start, true); //program.setImageBase(start, true);
//for (MethodInfoJava method : methods) { //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]; MethodInfoJava method = methods[i];
monitor.incrementProgress(1); monitor.incrementProgress(1);
CodeAttribute code = method.getCodeAttribute(); CodeAttribute code = method.getCodeAttribute();
@ -180,18 +183,19 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
long offset = code.getCodeOffset(); long offset = code.getCodeOffset();
Memory memory = program.getMemory(); Memory memory = program.getMemory();
short nameIndex = method.getNameIndex(); int nameIndex = method.getNameIndex();
short descriptorIndex = method.getDescriptorIndex(); int descriptorIndex = method.getDescriptorIndex();
ConstantPoolUtf8Info methodNameInfo = (ConstantPoolUtf8Info) constantPool[nameIndex]; ConstantPoolUtf8Info methodNameInfo =
(ConstantPoolUtf8Info) constantPool[nameIndex];
ConstantPoolUtf8Info methodDescriptorInfo = ConstantPoolUtf8Info methodDescriptorInfo =
(ConstantPoolUtf8Info) constantPool[descriptorIndex]; (ConstantPoolUtf8Info) constantPool[descriptorIndex];
String methodName = methodNameInfo.getString() + methodDescriptorInfo.getString(); String methodName = methodNameInfo.getString() + methodDescriptorInfo.getString();
MemoryBlock memoryBlock = MemoryBlock memoryBlock = memory.createInitializedBlock(methodName, start,
memory.createInitializedBlock(methodName, start, provider.getInputStream(offset), length, monitor, false);
provider.getInputStream(offset), length, monitor, false); Address methodIndexAddress = JavaClassUtil.toLookupAddress(program, i);
Address methodIndexAddress = JavaClassUtil.toLookupAddress( program, i ); program.getMemory().setInt(methodIndexAddress, (int) start.getOffset());
program.getMemory( ).setInt( methodIndexAddress, (int) start.getOffset() ); program.getListing().createData(methodIndexAddress, PointerDataType.dataType);
setAlignmentInfo(program, setAlignmentInfo(program,
new AddressSet(memoryBlock.getStart(), memoryBlock.getEnd())); new AddressSet(memoryBlock.getStart(), memoryBlock.getEnd()));
@ -200,10 +204,9 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
start = start.add(1); start = start.add(1);
} }
} }
} catch (Exception e1) { }
catch (Exception e1) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e1.printStackTrace(); e1.printStackTrace();
} }
@ -214,9 +217,8 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
int alignmentValue = 3; int alignmentValue = 3;
while (addressIterator.hasNext()) { while (addressIterator.hasNext()) {
Address address = addressIterator.next(); Address address = addressIterator.next();
SetRegisterCmd cmd = SetRegisterCmd cmd = new SetRegisterCmd(alignmentReg, address, address,
new SetRegisterCmd(alignmentReg, address, address, BigInteger.valueOf(alignmentValue));
BigInteger.valueOf(alignmentValue));
cmd.applyTo(program); cmd.applyTo(program);
if (alignmentValue == 0) { if (alignmentValue == 0) {
alignmentValue = 3; alignmentValue = 3;

View file

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

View file

@ -31,7 +31,7 @@ public class InjectInvokeDynamic extends InjectPayloadJava {
InjectContext injectContext = getInjectContext(program, context); InjectContext injectContext = getInjectContext(program, context);
AbstractConstantPoolInfoJava[] constantPool = getConstantPool(program); AbstractConstantPoolInfoJava[] constantPool = getConstantPool(program);
int constantPoolIndex = (int) injectContext.inputlist.get(0).getOffset(); 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; 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"; static final String PARAM_SPACE = "parameterSpace";
//private constructor to enforce noninstantiability //private constructor to enforce noninstantiability
private InvokeMethods(){ private InvokeMethods() {
throw new AssertionError(); throw new AssertionError();
} }
@ -50,24 +50,28 @@ public class InvokeMethods {
* @param type - the JavaInvocationType of the invocation * @param type - the JavaInvocationType of the invocation
* @return - the pcode as a string * @return - the pcode as a string
*/ */
public static String getPcodeForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool,
public static String getPcodeForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) { JavaInvocationType type) {
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
String descriptor = DescriptorDecoder.getDescriptorForInvoke(offset, constantPool, type); String descriptor = DescriptorDecoder.getDescriptorForInvoke(offset, constantPool, type);
List<JavaComputationalCategory> categories = DescriptorDecoder.getParameterCategories(descriptor); List<JavaComputationalCategory> categories =
boolean includeThisPointer = type.equals(JavaInvocationType.INVOKE_VIRTUAL) || type.equals(JavaInvocationType.INVOKE_SPECIAL) || type.equals(JavaInvocationType.INVOKE_INTERFACE); 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); int stackPurge = DescriptorDecoder.getStackPurge(descriptor);
if (includeThisPointer){ if (includeThisPointer) {
stackPurge += 4; stackPurge += 4;
} }
emitPcodeToMoveParams(pCode, categories, includeThisPointer, stackPurge); emitPcodeToMoveParams(pCode, categories, includeThisPointer, stackPurge);
emitPcodeToResolveMethodReference(pCode, offset, constantPool, type); emitPcodeToResolveMethodReference(pCode, offset, constantPool, type);
PcodeTextEmitter.emitIndirectCall(pCode, CALL_TARGET); PcodeTextEmitter.emitIndirectCall(pCode, CALL_TARGET);
JavaComputationalCategory retType = DescriptorDecoder.getReturnCategoryOfMethodDescriptor(descriptor); JavaComputationalCategory retType =
switch (retType){ DescriptorDecoder.getReturnCategoryOfMethodDescriptor(descriptor);
switch (retType) {
case CAT_1: case CAT_1:
PcodeTextEmitter.emitPushCat1Value(pCode, CAT_1_RETURN); PcodeTextEmitter.emitPushCat1Value(pCode, CAT_1_RETURN);
break; break;
@ -80,6 +84,42 @@ public class InvokeMethods {
return pCode.toString(); 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 * 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 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 * @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 //pop the parameters off of the stack
for (int i = categories.size() - 1; i >= 0; --i){ for (int i = categories.size() - 1; i >= 0; --i) {
switch (categories.get(i)){ switch (categories.get(i)) {
case CAT_1: case CAT_1:
PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER + Integer.toString(i)); PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER + Integer.toString(i));
totalSize -= 4; 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; break;
case CAT_2: case CAT_2:
PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER + Integer.toString(i)); 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.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; totalSize -= 8;
break; break;
default: default:
@ -111,15 +156,15 @@ public class InvokeMethods {
} }
} }
//pop off the this pointer if there is one //pop off the this pointer if there is one
if (includeThisPointer){ if (includeThisPointer) {
PcodeTextEmitter.emitPopCat1Value(pCode, THIS); PcodeTextEmitter.emitPopCat1Value(pCode, THIS);
totalSize -= 4; 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. * Emits pcode to assign the result of a cpool op to the call_target register for an invocation.
* @param pCode - the pcode buffer * @param pCode - the pcode buffer
@ -127,25 +172,37 @@ public class InvokeMethods {
* @param constantPool - the constant pool * @param constantPool - the constant pool
* @param type - the type of the invocation * @param type - the type of the invocation
*/ */
static void emitPcodeToResolveMethodReference(StringBuilder pCode, int offset, AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type){ static void emitPcodeToResolveMethodReference(StringBuilder pCode, int offset,
switch (type){ AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) {
switch (type) {
case INVOKE_DYNAMIC: 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; break;
case INVOKE_INTERFACE: 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; break;
case INVOKE_SPECIAL: 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; break;
case INVOKE_STATIC: 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; break;
case INVOKE_VIRTUAL: 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; break;
default: 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) * (Use/add to PcodeTextEmitter.java to actually emit pcode text)
* See ConstantPoolJava.java for examples of the use of the CPOOL pcode op. * See ConstantPoolJava.java for examples of the use of the CPOOL pcode op.
* *
* TODO: * possible improvements:
* 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:
* *
* 2) incorporate exceptions. * 2) incorporate exceptions.
* 6) decide how to display the information used in an invokedynamic instruction * 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 LDC = "ldcCallOther";
public static final String LDC2_W = "ldc2_wCallOther"; public static final String LDC2_W = "ldc2_wCallOther";
public static final String LDC_W = "ldc_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 MULTIANEWARRAY = "multianewarrayCallOther";
public static final String PUTFIELD = "putFieldCallOther"; public static final String PUTFIELD = "putFieldCallOther";
@ -149,7 +137,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
implementedOps.add(LDC); implementedOps.add(LDC);
implementedOps.add(LDC2_W); implementedOps.add(LDC2_W);
implementedOps.add(LDC_W); implementedOps.add(LDC_W);
implementedOps.add(LOOKUP_SWITCH);
implementedOps.add(MULTIANEWARRAY); implementedOps.add(MULTIANEWARRAY);
implementedOps.add(PUTFIELD); implementedOps.add(PUTFIELD);
implementedOps.add(PUTSTATIC); implementedOps.add(PUTSTATIC);
@ -170,8 +157,9 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
@Override @Override
protected InjectPayloadSleigh allocateInject(String sourceName, String name, int tp) { protected InjectPayloadSleigh allocateInject(String sourceName, String name, int tp) {
InjectPayloadJava payload = null; InjectPayloadJava payload = null;
if (tp != InjectPayload.CALLOTHERFIXUP_TYPE) if (tp != InjectPayload.CALLOTHERFIXUP_TYPE) {
return super.allocateInject(sourceName, name, tp); return super.allocateInject(sourceName, name, tp);
}
switch (name) { switch (name) {
case GETFIELD: case GETFIELD:
payload = new InjectGetField(sourceName, language); payload = new InjectGetField(sourceName, language);
@ -199,9 +187,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
case LDC_W: case LDC_W:
payload = new InjectLdc(sourceName, language); payload = new InjectLdc(sourceName, language);
break; break;
case LOOKUP_SWITCH:
payload = new InjectLookupSwitch(sourceName, language);
break;
case MULTIANEWARRAY: case MULTIANEWARRAY:
payload = new InjectMultiANewArray(sourceName, language); payload = new InjectMultiANewArray(sourceName, language);
break; break;

View file

@ -15,7 +15,6 @@
*/ */
package ghidra.app.util.pcodeInject; package ghidra.app.util.pcodeInject;
/** /**
* *
* This is a utility class containing methods to emit pcode for decompile callbacks occurring during analysis of * This is a utility class containing methods to emit pcode for decompile callbacks occurring during analysis of
@ -27,10 +26,10 @@ package ghidra.app.util.pcodeInject;
*/ */
public class PcodeTextEmitter { public class PcodeTextEmitter {
static final String RAM = "ram"; static final String RAM = "ram";
//private constructor to enforce noninstantiability //private constructor to enforce noninstantiability
private PcodeTextEmitter(){ private PcodeTextEmitter() {
throw new AssertionError(); throw new AssertionError();
} }
@ -39,7 +38,7 @@ public class PcodeTextEmitter {
* @param pCode - StringBuilder to hold pcode. * @param pCode - StringBuilder to hold pcode.
* @param valueName - name of varnode to push. * @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("SP = SP - 4;\n*:4 SP = ");
pCode.append(valueName); pCode.append(valueName);
pCode.append(";\n"); pCode.append(";\n");
@ -50,7 +49,7 @@ public class PcodeTextEmitter {
* @param pCode - StringBuilder to hold pcode. * @param pCode - StringBuilder to hold pcode.
* @param valueName - name of varnode to push. * @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("SP = SP - 8;\n*:8 SP = ");
pCode.append(valueName); pCode.append(valueName);
pCode.append(";\n"); pCode.append(";\n");
@ -61,7 +60,7 @@ public class PcodeTextEmitter {
* @param pCode - StringBuilder to hold pcode. * @param pCode - StringBuilder to hold pcode.
* @param destName - name of destination varnode. * @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(destName);
pCode.append(":8 = *:8 SP;\nSP = SP + 8;\n"); pCode.append(":8 = *:8 SP;\nSP = SP + 8;\n");
} }
@ -71,7 +70,7 @@ public class PcodeTextEmitter {
* @param pCode - StringBuilder to hold pcode. * @param pCode - StringBuilder to hold pcode.
* @param destName - name of destination varnode. * @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(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 pcodeop - name of pcodeop
* @param args - zero or more arguments for the 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(varnodeName);
pCode.append(":"); pCode.append(":");
pCode.append(Integer.toString(size)); pCode.append(Integer.toString(size));
pCode.append(" = "); pCode.append(" = ");
pCode.append(pcodeop); pCode.append(pcodeop);
pCode.append("("); 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]); pCode.append(args[i]);
if (i < numArgs - 1){ if (i < numArgs - 1) {
pCode.append(","); pCode.append(",");
} }
} }
pCode.append(");\n"); pCode.append(");\n");
} }
/** /**
* Emits pcode to call a void black-box pcodeop * Emits pcode to call a void black-box pcodeop
* @param pCode StringBuilder to hold the pcode * @param pCode StringBuilder to hold the pcode
* @param pcodeop - name of pcodeop * @param pcodeop - name of pcodeop
* @param args - zero or more arguments for the 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(pcodeop);
pCode.append("("); 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]); pCode.append(args[i]);
if (i < numArgs - 1){ if (i < numArgs - 1) {
pCode.append(","); pCode.append(",");
} }
} }
pCode.append(");\n"); pCode.append(");\n");
} }
/** /**
* Appends the pcode to assign an integer constant to a register * Appends the pcode to assign an integer constant to a register
* @param pCode * @param pCode
* @param constantPool * @param constantPool
* @param index * @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(register);
pCode.append(" = 0x"); pCode.append(" = 0x");
pCode.append(Integer.toHexString(constant)); pCode.append(Integer.toHexString(constant));
pCode.append(";\n"); pCode.append(";\n");
} }
/** /**
* Appends the pcode to assign a register to the result of a pcode op call with arguments args * Appends the pcode to assign a register to the result of a pcode op call with arguments args
* @param pCode * @param pCode
@ -140,14 +138,15 @@ public class PcodeTextEmitter {
* @param pcodeop * @param pcodeop
* @param args * @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(register);
pCode.append(" = "); pCode.append(" = ");
pCode.append(pcodeop); pCode.append(pcodeop);
pCode.append("("); 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]); pCode.append(args[i]);
if (i < numArgs - 1){ if (i < numArgs - 1) {
pCode.append(","); pCode.append(",");
} }
} }
@ -159,13 +158,22 @@ public class PcodeTextEmitter {
* @param pCode * @param pCode
* @param caseName * @param caseName
*/ */
public static void emitLabelDefinition(StringBuilder pCode, String caseName){ public static void emitLabelDefinition(StringBuilder pCode, String caseName) {
pCode.append("<"); pCode.append("<");
pCode.append(caseName); pCode.append(caseName);
pCode.append(">\n"); 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("*[");
pCode.append(space); pCode.append(space);
pCode.append("]:"); pCode.append("]:");
@ -177,19 +185,25 @@ public class PcodeTextEmitter {
pCode.append(";\n"); 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("call [");
pCode.append(target); pCode.append(target);
pCode.append("];\n"); pCode.append("];\n");
} }
public static void emitAddToStackPointer(StringBuilder pCode, int amount){ /**
pCode.append("SP = SP + "); * Appends the pcode to sign-extend the value src into dest
pCode.append(Integer.toString(amount)); * @param pCode buffer to append to
pCode.append(";\n"); * @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){ */
public static void emitSignExtension(StringBuilder pCode, String dest, int size, String src) {
pCode.append(dest); pCode.append(dest);
pCode.append(":"); pCode.append(":");
pCode.append(Integer.toString(size)); pCode.append(Integer.toString(size));
@ -198,7 +212,14 @@ public class PcodeTextEmitter {
pCode.append(");\n"); 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(dest);
pCode.append(":"); pCode.append(":");
pCode.append(Integer.toString(size)); pCode.append(Integer.toString(size));
@ -207,7 +228,14 @@ public class PcodeTextEmitter {
pCode.append(");\n"); 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(dest);
pCode.append(" = "); pCode.append(" = ");
pCode.append(src); pCode.append(src);
@ -216,5 +244,24 @@ public class PcodeTextEmitter {
pCode.append(";\n"); 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; package ghidra.app.util.pcodeInject;
import ghidra.javaclass.format.DescriptorDecoder; import ghidra.javaclass.format.DescriptorDecoder;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava; import ghidra.javaclass.format.constantpool.*;
import ghidra.javaclass.format.constantpool.ConstantPoolFieldReferenceInfo;
import ghidra.javaclass.format.constantpool.ConstantPoolNameAndTypeInfo;
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
/** /**
* *
@ -37,14 +34,15 @@ import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
public class ReferenceMethods { public class ReferenceMethods {
static final String VALUE = "value"; 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 NEW_VALUE = "newValue";
static final String OBJECT_REF = "objectRef"; static final String OBJECT_REF = "objectRef";
static final String FIELD_OFFSET = "fieldOffset"; static final String FIELD_OFFSET = "fieldOffset";
static final String STATIC_OFFSET = "staticOffset"; static final String STATIC_OFFSET = "staticOffset";
//private constructor to enforce noninstantiability //private constructor to enforce noninstantiability
private ReferenceMethods(){ private ReferenceMethods() {
throw new AssertionError(); throw new AssertionError();
} }
@ -54,43 +52,62 @@ public class ReferenceMethods {
* @param constantPool - the constant pool of the class file * @param constantPool - the constant pool of the class file
* @return - the pcode string * @return - the pcode string
*/ */
public static String getPcodeForGetStatic(int index, AbstractConstantPoolInfoJava[] constantPool) { public static String getPcodeForGetStatic(int index,
AbstractConstantPoolInfoJava[] constantPool) {
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
//determine the computational category and push a value of the correct size onto the operand stack //determine the computational category and push a value of the correct size onto the operand stack
String descriptor = getDescriptorForFieldRef(constantPool, index); String descriptor = getDescriptorForFieldRef(constantPool, index);
switch (descriptor.charAt(0)){ switch (descriptor.charAt(0)) {
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP); ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); ConstantPoolJava.CPOOL_GETSTATIC);
break; 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 case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP); ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1);
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break; break;
case DescriptorDecoder.BASE_TYPE_CHAR: //char case DescriptorDecoder.BASE_TYPE_CHAR: //char
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP); ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1);
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break; break;
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP); ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); ConstantPoolJava.CPOOL_GETSTATIC);
break; 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_ARRAY: //array dimension
case DescriptorDecoder.BASE_TYPE_FLOAT: //float case DescriptorDecoder.BASE_TYPE_FLOAT: //float
case DescriptorDecoder.BASE_TYPE_INT: //int case DescriptorDecoder.BASE_TYPE_INT: //int
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 4,
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 4, TEMP_1);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break; break;
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
case DescriptorDecoder.BASE_TYPE_LONG: //long case DescriptorDecoder.BASE_TYPE_LONG: //long
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 8, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 8,
PcodeTextEmitter.emitPushCat2Value(pCode,VALUE); ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 8, TEMP_1);
PcodeTextEmitter.emitPushCat2Value(pCode, VALUE);
break; break;
default: default:
throw new IllegalArgumentException("Invalid descriptor: " + descriptor); throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
@ -104,48 +121,67 @@ public class ReferenceMethods {
* @param constantPool - the constant pool of the class file * @param constantPool - the constant pool of the class file
* @return - the pcode string * @return - the pcode string
*/ */
public static String getPcodeForPutStatic(int index, AbstractConstantPoolInfoJava[] constantPool){ public static String getPcodeForPutStatic(int index,
AbstractConstantPoolInfoJava[] constantPool) {
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
String descriptor = getDescriptorForFieldRef(constantPool, index); String descriptor = getDescriptorForFieldRef(constantPool, index);
switch (descriptor.charAt(0)){ switch (descriptor.charAt(0)) {
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE); ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET, TEMP); ConstantPoolJava.CPOOL_PUTSTATIC);
break; 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 case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE); ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET, TEMP); ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET,
TEMP_1);
break; break;
case DescriptorDecoder.BASE_TYPE_CHAR: //char case DescriptorDecoder.BASE_TYPE_CHAR: //char
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE); ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET, TEMP); ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET,
TEMP_1);
break; break;
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE); ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET, TEMP); ConstantPoolJava.CPOOL_PUTSTATIC);
break; 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_ARRAY: //array dimension
case DescriptorDecoder.BASE_TYPE_FLOAT: //float case DescriptorDecoder.BASE_TYPE_FLOAT: //float
case DescriptorDecoder.BASE_TYPE_INT: //int case DescriptorDecoder.BASE_TYPE_INT: //int
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, STATIC_OFFSET, NEW_VALUE); ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, STATIC_OFFSET,
NEW_VALUE);
break; break;
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
case DescriptorDecoder.BASE_TYPE_LONG: //long case DescriptorDecoder.BASE_TYPE_LONG: //long
PcodeTextEmitter.emitPopCat2Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat2Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, STATIC_OFFSET, NEW_VALUE); ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, STATIC_OFFSET,
NEW_VALUE);
break; break;
default: default:
throw new IllegalArgumentException("Invalid descriptor: " + descriptor); throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
@ -159,49 +195,68 @@ public class ReferenceMethods {
* @param constantPool * @param constantPool
* @return - the pcode string * @return - the pcode string
*/ */
public static String getPcodeForGetField(int index, AbstractConstantPoolInfoJava[] constantPool) { public static String getPcodeForGetField(int index,
AbstractConstantPoolInfoJava[] constantPool) {
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
String descriptor = getDescriptorForFieldRef(constantPool, index); String descriptor = getDescriptorForFieldRef(constantPool, index);
switch (descriptor.charAt(0)){ switch (descriptor.charAt(0)) {
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP); ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); ConstantPoolJava.CPOOL_GETFIELD);
break; 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 case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP); ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1);
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break; break;
case DescriptorDecoder.BASE_TYPE_CHAR: //char case DescriptorDecoder.BASE_TYPE_CHAR: //char
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP); ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1);
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break; break;
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP); ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1);
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break; break;
case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension
case DescriptorDecoder.BASE_TYPE_FLOAT: //float case DescriptorDecoder.BASE_TYPE_FLOAT: //float
case DescriptorDecoder.BASE_TYPE_INT: //int case DescriptorDecoder.BASE_TYPE_INT: //int
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 4,
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 4, TEMP_1);
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
break; break;
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
case DescriptorDecoder.BASE_TYPE_LONG: //long case DescriptorDecoder.BASE_TYPE_LONG: //long
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 8, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 8,
PcodeTextEmitter.emitPushCat2Value(pCode,VALUE); ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 8, TEMP_1);
PcodeTextEmitter.emitPushCat2Value(pCode, VALUE);
break; break;
default: default:
throw new IllegalArgumentException("Invalid descriptor: " + descriptor); throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
@ -215,64 +270,81 @@ public class ReferenceMethods {
* @param constantPool - the constant pool * @param constantPool - the constant pool
* @return - the pcode * @return - the pcode
*/ */
public static String getPcodeForPutField(int index, AbstractConstantPoolInfoJava[] constantPool) { public static String getPcodeForPutField(int index,
AbstractConstantPoolInfoJava[] constantPool) {
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
//determine the computational category and push a value of the correct size onto the operand stack //determine the computational category and push a value of the correct size onto the operand stack
String descriptor = getDescriptorForFieldRef(constantPool, index); String descriptor = getDescriptorForFieldRef(constantPool, index);
switch (descriptor.charAt(0)) {
switch (descriptor.charAt(0)){
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE); ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET, TEMP); ConstantPoolJava.CPOOL_PUTFIELD);
break; 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 case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE); ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET, TEMP); ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET,
TEMP_1);
break; break;
case DescriptorDecoder.BASE_TYPE_CHAR: //char case DescriptorDecoder.BASE_TYPE_CHAR: //char
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE); ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET, TEMP); ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET,
TEMP_1);
break; break;
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE); ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET, TEMP); ConstantPoolJava.CPOOL_PUTFIELD);
break; 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_ARRAY: //array dimension
case DescriptorDecoder.BASE_TYPE_FLOAT: //float case DescriptorDecoder.BASE_TYPE_FLOAT: //float
case DescriptorDecoder.BASE_TYPE_INT: //int case DescriptorDecoder.BASE_TYPE_INT: //int
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, FIELD_OFFSET, NEW_VALUE); ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, FIELD_OFFSET,
NEW_VALUE);
break; break;
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
case DescriptorDecoder.BASE_TYPE_LONG: //long case DescriptorDecoder.BASE_TYPE_LONG: //long
PcodeTextEmitter.emitPopCat2Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat2Value(pCode, NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, FIELD_OFFSET, NEW_VALUE); ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, FIELD_OFFSET,
NEW_VALUE);
break; break;
default: default:
throw new IllegalArgumentException("Invalid descriptor: " + descriptor); throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
} }
return pCode.toString(); return pCode.toString();
/*JavaComputationalCategory category = DescriptorDecoder.getComputationalCategoryOfDescriptor(descriptor); /*JavaComputationalCategory category = DescriptorDecoder.getComputationalCategoryOfDescriptor(descriptor);
switch (category){ switch (category){
case CAT_1: case CAT_1:
@ -295,21 +367,21 @@ public class ReferenceMethods {
return pCode.toString();*/ return pCode.toString();*/
} }
/** /**
* Returns the descriptor of a field reference in the constant pool * Returns the descriptor of a field reference in the constant pool
* @param constantPool * @param constantPool
* @param index * @param index
* @return * @return
*/ */
static String getDescriptorForFieldRef(AbstractConstantPoolInfoJava[] constantPool, int index){ static String getDescriptorForFieldRef(AbstractConstantPoolInfoJava[] constantPool, int index) {
ConstantPoolFieldReferenceInfo fieldRef = (ConstantPoolFieldReferenceInfo) constantPool[index]; ConstantPoolFieldReferenceInfo fieldRef =
(ConstantPoolFieldReferenceInfo) constantPool[index];
int nameAndTypeIndex = fieldRef.getNameAndTypeIndex(); int nameAndTypeIndex = fieldRef.getNameAndTypeIndex();
ConstantPoolNameAndTypeInfo nameAndTypeInfo = (ConstantPoolNameAndTypeInfo) constantPool[nameAndTypeIndex]; ConstantPoolNameAndTypeInfo nameAndTypeInfo =
ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()]; (ConstantPoolNameAndTypeInfo) constantPool[nameAndTypeIndex];
ConstantPoolUtf8Info descriptorInfo =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
return descriptorInfo.getString(); 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 java.util.*;
import org.apache.commons.lang3.StringUtils;
import ghidra.app.cmd.comments.SetCommentCmd; import ghidra.app.cmd.comments.SetCommentCmd;
import ghidra.app.cmd.disassemble.DisassembleCommand; 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.AnalysisWorker;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager; import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.services.AnalysisPriority; import ghidra.app.services.AnalysisPriority;
import ghidra.app.services.AnalyzerType; import ghidra.app.services.AnalyzerType;
import ghidra.app.util.bin.*; import ghidra.app.util.bin.*;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.JavaLoader;
import ghidra.framework.cmd.CompoundCmd;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.javaclass.flags.MethodsInfoAccessFlags;
import ghidra.javaclass.format.*; import ghidra.javaclass.format.*;
import ghidra.javaclass.format.attributes.*; import ghidra.javaclass.format.attributes.*;
import ghidra.javaclass.format.constantpool.*; 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.listing.Function.FunctionUpdateType;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.scalar.Scalar; import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.RefType; import ghidra.program.model.symbol.*;
import ghidra.program.model.symbol.SourceType; import ghidra.util.Msg;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.*;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker { public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker {
@ -108,7 +114,7 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
TaskMonitor monitor) throws Exception { TaskMonitor monitor) throws Exception {
Address address = Address address =
program.getAddressFactory().getAddressSpace("constantPool").getMinAddress(); program.getAddressFactory().getAddressSpace(JavaLoader.CONSTANT_POOL).getMinAddress();
ByteProvider provider = new MemoryByteProvider(program.getMemory(), address); ByteProvider provider = new MemoryByteProvider(program.getMemory(), address);
BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian()); BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian());
@ -130,7 +136,7 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
markupFields(program, classFile, monitor); markupFields(program, classFile, monitor);
markupMethods(program, classFile, monitor); markupMethods(program, classFile, monitor);
disassembleMethods(program, classFile, monitor); disassembleMethods(program, classFile, monitor);
labelOperands(program, classFile); processInstructions(program, constantPoolData, classFile, monitor);
recordJavaVersionInfo(program, classFile); recordJavaVersionInfo(program, classFile);
BasicCompilerSpec.enableJavaLanguageDecompilation(program); BasicCompilerSpec.enableJavaLanguageDecompilation(program);
return true; return true;
@ -157,10 +163,10 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
/** /**
* Create datatypes for all classes mentioned in the constant pool * Create datatypes for all classes mentioned in the constant pool
* @param program * @param program program file
* @param classFile * @param classFile ClassFileJava associated with {@code program}
* @param monitor * @param monitor for canceling analysis
* @param messageLog * @param messageLog for logging messages
*/ */
private void createProgramDataTypes(Program program, ClassFileJava classFile, private void createProgramDataTypes(Program program, ClassFileJava classFile,
TaskMonitor monitor, MessageLog messageLog) { TaskMonitor monitor, MessageLog messageLog) {
@ -264,7 +270,19 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
javaVersion = "1.8"; javaVersion = "1.8";
break; break;
case 53: 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; break;
default: default:
javaVersion = "Unknown"; javaVersion = "Unknown";
@ -294,7 +312,7 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
AbstractConstantPoolInfoJava[] constantPool, Map<Integer, Integer> indexMap) { AbstractConstantPoolInfoJava[] constantPool, Map<Integer, Integer> indexMap) {
AbstractAttributeInfo[] attributes = classFile.getAttributes(); AbstractAttributeInfo[] attributes = classFile.getAttributes();
for (AbstractAttributeInfo attribute : attributes) { for (AbstractAttributeInfo attribute : attributes) {
short nameIndex = attribute.getAttributeNameIndex(); int nameIndex = attribute.getAttributeNameIndex();
AbstractConstantPoolInfoJava poolEntry = classFile.getConstantPool()[nameIndex]; AbstractConstantPoolInfoJava poolEntry = classFile.getConstantPool()[nameIndex];
if (poolEntry instanceof ConstantPoolUtf8Info) { if (poolEntry instanceof ConstantPoolUtf8Info) {
String name = ((ConstantPoolUtf8Info) poolEntry).getString(); String name = ((ConstantPoolUtf8Info) poolEntry).getString();
@ -388,24 +406,179 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
return indexMap; return indexMap;
} }
private void labelOperands(Program program, ClassFileJava classFile) { private void processInstructions(Program program, Data constantPoolData,
InstructionIterator instructionIt = ClassFileJava classFile, TaskMonitor monitor) throws CancelledException {
program.getListing().getInstructions(toAddr(program, 0x10000), true);
while (instructionIt.hasNext()) {
Instruction instruction = instructionIt.next();
Scalar opValue = instruction.getScalar(0); InstructionIterator instructionIt =
if (opValue == null) { 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; continue;
} }
AbstractConstantPoolInfoJava[] constantPool = classFile.getConstantPool(); if (instruction.getMnemonicString().equals("invokedynamic")) {
int index = (int) (opValue.getValue() & 0xFFFFFFFF); addInvokeDynamicComments(program, constantPool, indexMap, bootstrapMethods,
String opMarkup = getOperandMarkup(program, constantPool, index); instruction);
instruction.setComment(CodeUnit.EOL_COMMENT, opMarkup); }
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) { private void markupFields(Program program, ClassFileJava classFile, TaskMonitor monitor) {
AbstractConstantPoolInfoJava[] constantPool = classFile.getConstantPool(); 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 @Override
public String getWorkerName() { public String getWorkerName() {
return getName(); 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. * 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. * Also overrides the signatures on all method invocations made within the method body.
* @param function - the function (method) * @param function - the function (method)
* @param methodDescriptor - the name of the memory block containing the function's code. It is assumed that blockName * @param methodInfo information about the method from the constant pool
* is the concatenation of the method name and the descriptor * @param classFile class file containing the method
* @param constantPool * @param dtManager data type manager for program
* @throws DuplicateNameException * @throws DuplicateNameException if there are duplicate name issues with function or parameter names
* @throws InvalidInputException * @throws InvalidInputException if a function or parameter name is invalid
*/ */
private void setFunctionInfo(Function function, MethodInfoJava methodInfo, private void setFunctionInfo(Function function, MethodInfoJava methodInfo,
ClassFileJava classFile, DataTypeManager dtManager) ClassFileJava classFile, DataTypeManager dtManager)
@ -833,5 +722,60 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
} }
function.replaceParameters(params, FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true, function.replaceParameters(params, FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true,
SourceType.ANALYSIS); 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 * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,23 +15,33 @@
*/ */
package ghidra.javaclass.flags; package ghidra.javaclass.flags;
public final class ClassFileFlags { public enum ClassFileFlags {
/** Declared public; may be accessed from outside its package. */ /** Declared public; may be accessed from outside its package. */
public final static short ACC_PUBLIC = 0x0001; ACC_PUBLIC(0x0001),
/** Declared final; no subclasses allowed. */ /** 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. */ /** 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. */ /** Is an interface, not a class. */
public final static short ACC_INTERFACE = 0x0200; ACC_INTERFACE(0x0200),
/** Declared abstract; must not be instantiated. */ /** Declared abstract; must not be instantiated. */
public final static short ACC_ABSTRACT = 0x0400; ACC_ABSTRACT(0x0400),
/** Declared synthetic; not present in the source code. */ /** Declared synthetic; not present in the source code. */
public final static short ACC_SYNTHETIC = 0x1000; ACC_SYNTHETIC(0x1000),
/** Declared as an annotation type. */ /** Declared as an annotation type. */
public final static short ACC_ANNOTATION = 0x2000; ACC_ANNOTATION(0x2000),
/** Declared as an enum type. */ /** 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 * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,25 +15,33 @@
*/ */
package ghidra.javaclass.flags; package ghidra.javaclass.flags;
final class FieldInfoAccessFlags { public enum FieldInfoAccessFlags {
/** Declared public; may be accessed from outside its package. */ /** 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. */ /** Declared private; usable only within the defining class. */
public final short ACC_PRIVATE = 0x0002; ACC_PRIVATE(0x0002),
/** Declared protected; may be accessed within subclasses. */ /** Declared protected; may be accessed within subclasses. */
public final short ACC_PROTECTED = 0x0004; ACC_PROTECTED(0x0004),
/** Declared static. */ /** Declared static. */
public final short ACC_STATIC = 0x0008; ACC_STATIC(0x0008),
/** Declared final; never directly assigned to after object construction (JLS ?17.5). */ /** 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. */ /** 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. */ /** 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. */ /** Declared synthetic; not present in the source code. */
public final short ACC_SYNTHETIC = 0x1000; ACC_SYNTHETIC(0x1000),
/** Declared as an element of an enum. */ /** 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; package ghidra.javaclass.flags;
public final class MethodsInfoAccessFlags { public enum MethodsInfoAccessFlags {
/** Declared public; may be accessed from outside its package. */ /** 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. */ /** 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. */ /** Declared protected; may be accessed within subclasses. */
public final static short ACC_PROTECTED = 0x0004; ACC_PROTECTED(0x0004),
/** Declared static. */ /** Declared static. */
public final static short ACC_STATIC = 0x0008; ACC_STATIC(0x0008),
/** Declared final; must not be overridden (5.4.5). */ /** 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. */ /** 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. */ /** A bridge method, generated by the compiler. */
public final static short ACC_BRIDGE = 0x0040; ACC_BRIDGE(0x0040),
/** Declared with variable number of arguments. */ /** 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. */ /** 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. */ /** Declared abstract; no implementation is provided. */
public final static short ACC_ABSTRACT = 0x0400; ACC_ABSTRACT(0x0400),
/** Declared strictfp; floating-point mode is FP-strict. */ /** 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. */ /** 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; package ghidra.javaclass.format;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter; import ghidra.app.util.bin.StructConverter;
import ghidra.javaclass.format.attributes.AbstractAttributeInfo; import ghidra.javaclass.format.attributes.AbstractAttributeInfo;
import ghidra.javaclass.format.attributes.AttributeFactory; import ghidra.javaclass.format.attributes.AttributeFactory;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava; import ghidra.javaclass.format.constantpool.*;
import ghidra.javaclass.format.constantpool.ConstantPoolDoubleInfo; import ghidra.program.model.data.*;
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.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/** /**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF * NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p> * <p>
@ -85,9 +79,9 @@ public class ClassFileJava implements StructConverter {
minorVersion = reader.readNextShort(); minorVersion = reader.readNextShort();
majorVersion = reader.readNextShort(); majorVersion = reader.readNextShort();
constantPoolCount = reader.readNextShort(); constantPoolCount = reader.readNextShort();
constantPool = new AbstractConstantPoolInfoJava[constantPoolCount]; constantPool = new AbstractConstantPoolInfoJava[getConstantPoolCount()];
//NOTE: start at index 1 per JVM specification!!! //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); constantPool[i] = ConstantPoolFactory.get(reader);
//From section 4.4.5 of JVM specification: //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 ///located at index n+2. The constant_pool index n+1 must be valid but is considered
//unusable. //unusable.
if (constantPool[i] instanceof ConstantPoolLongInfo || if (constantPool[i] instanceof ConstantPoolLongInfo ||
constantPool[i] instanceof ConstantPoolDoubleInfo) { constantPool[i] instanceof ConstantPoolDoubleInfo) {
++i; ++i;
} }
} }
@ -105,20 +99,20 @@ public class ClassFileJava implements StructConverter {
thisClass = reader.readNextShort(); thisClass = reader.readNextShort();
superClass = reader.readNextShort(); superClass = reader.readNextShort();
interfacesCount = reader.readNextShort(); interfacesCount = reader.readNextShort();
interfaces = reader.readNextShortArray(interfacesCount); interfaces = reader.readNextShortArray(getInterfacesCount());
fieldsCount = reader.readNextShort(); fieldsCount = reader.readNextShort();
fields = new FieldInfoJava[fieldsCount]; fields = new FieldInfoJava[getFieldsCount()];
for (int i = 0; i < fieldsCount; i++) { for (int i = 0; i < getFieldsCount(); i++) {
fields[i] = new FieldInfoJava(reader, this); fields[i] = new FieldInfoJava(reader, this);
} }
methodsCount = reader.readNextShort(); methodsCount = reader.readNextShort();
methods = new MethodInfoJava[methodsCount]; methods = new MethodInfoJava[getMethodsCount()];
for (int i = 0; i < methodsCount; i++) { for (int i = 0; i < getMethodsCount(); i++) {
methods[i] = new MethodInfoJava(reader, this); methods[i] = new MethodInfoJava(reader, this);
} }
attributesCount = reader.readNextShort(); attributesCount = reader.readNextShort();
attributes = new AbstractAttributeInfo[attributesCount]; attributes = new AbstractAttributeInfo[getAttributesCount()];
for (int i = 0; i < attributesCount; i++) { for (int i = 0; i < getAttributesCount(); i++) {
attributes[i] = AttributeFactory.get(reader, getConstantPool()); 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. * 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 * @return the number of entries in the constant_pool table plus one
*/ */
public short getConstantPoolCount() { public int getConstantPoolCount() {
return constantPoolCount; return constantPoolCount & 0xffff;
} }
/** /**
@ -207,8 +201,8 @@ public class ClassFileJava implements StructConverter {
* defined by this class file. * defined by this class file.
* @return a valid index into the constant_pool table to a CONSTANT_Class_info * @return a valid index into the constant_pool table to a CONSTANT_Class_info
*/ */
public short getThisClass() { public int getThisClass() {
return thisClass; return thisClass & 0xffff;
} }
/** /**
@ -228,8 +222,8 @@ public class ClassFileJava implements StructConverter {
* must be a CONSTANT_Class_info structure representing the class Object. * 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 * @return a valid index into the constant_pool table to a CONSTANT_Class_info
*/ */
public short getSuperClass() { public int getSuperClass() {
return superClass; return superClass & 0xffff;
} }
/** /**
@ -237,8 +231,8 @@ public class ClassFileJava implements StructConverter {
* superinterfaces of this class or interface type. * superinterfaces of this class or interface type.
* @return the number of direct superinterfaces of this class * @return the number of direct superinterfaces of this class
*/ */
public short getInterfacesCount() { public int getInterfacesCount() {
return interfacesCount; 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 * 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 * direct superinterface of this class or interface type, in the left-to-right order
* given in the source for the type. * given in the source for the type.
* @return an array of interfaces * @param i entry
* @return interface index
*/ */
public short[] getInterfaces() { public int getInterfacesEntry(int i) {
return interfaces; return interfaces[i] & 0xffff;
} }
/** /**
@ -261,8 +256,8 @@ public class ClassFileJava implements StructConverter {
* interface type. * interface type.
* @return the number of field_info structures in the fields table * @return the number of field_info structures in the fields table
*/ */
public short getFieldsCount() { public int getFieldsCount() {
return fieldsCount; return fieldsCount & 0xffff;
} }
/** /**
@ -282,8 +277,8 @@ public class ClassFileJava implements StructConverter {
* structures in the methods table. * structures in the methods table.
* @return the number of method_info structures in the methods table * @return the number of method_info structures in the methods table
*/ */
public short getMethodsCount() { public int getMethodsCount() {
return methodsCount; return methodsCount & 0xffff;
} }
/** /**
@ -309,8 +304,8 @@ public class ClassFileJava implements StructConverter {
* in the attributes table of this class. * in the attributes table of this class.
* @return the number of attributes in the attributes table * @return the number of attributes in the attributes table
*/ */
public short getAttributesCount() { public int getAttributesCount() {
return attributesCount; return attributesCount & 0xffff;
} }
/** /**
@ -370,14 +365,14 @@ public class ClassFileJava implements StructConverter {
structure.add(WORD, "super_class", null); structure.add(WORD, "super_class", null);
structure.add(WORD, "interfaces_count", null); structure.add(WORD, "interfaces_count", null);
if (interfacesCount > 0) { if (getInterfacesCount() > 0) {
DataType array = new ArrayDataType(WORD, interfacesCount, WORD.getLength()); DataType array = new ArrayDataType(WORD, getInterfacesCount(), WORD.getLength());
structure.add(array, "interfaces", null); structure.add(array, "interfaces", null);
} }
structure.add(WORD, "field_count", null); structure.add(WORD, "field_count", null);
if (fieldsCount > 0) { if (getFieldsCount() > 0) {
Structure fieldStruct = new StructureDataType("fields", 0); Structure fieldStruct = new StructureDataType("fields", 0);
for (int i = 0; i < fields.length; ++i) { for (int i = 0; i < fields.length; ++i) {
fieldStruct.add(fields[i].toDataType(), "field_" + i, null); fieldStruct.add(fields[i].toDataType(), "field_" + i, null);
@ -387,7 +382,7 @@ public class ClassFileJava implements StructConverter {
structure.add(WORD, "method_count", null); structure.add(WORD, "method_count", null);
if (methodsCount > 0) { if (getMethodsCount() > 0) {
Structure methodsStruct = new StructureDataType("methods", 0); Structure methodsStruct = new StructureDataType("methods", 0);
for (int i = 0; i < methods.length; ++i) { for (int i = 0; i < methods.length; ++i) {
methodsStruct.add(methods[i].toDataType(), "methods_" + i, null); methodsStruct.add(methods[i].toDataType(), "methods_" + i, null);
@ -396,7 +391,7 @@ public class ClassFileJava implements StructConverter {
} }
structure.add(WORD, "attributes_count", null); structure.add(WORD, "attributes_count", null);
if (attributesCount > 0){ if (getAttributesCount() > 0) {
Structure attributesStruct = new StructureDataType("attributes", 0); Structure attributesStruct = new StructureDataType("attributes", 0);
for (int i = 0; i < attributes.length; ++i) { for (int i = 0; i < attributes.length; ++i) {
attributesStruct.add(attributes[i].toDataType(), "attributes_" + i, null); attributesStruct.add(attributes[i].toDataType(), "attributes_" + i, null);

View file

@ -19,12 +19,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import ghidra.app.util.pcodeInject.*; import ghidra.app.util.pcodeInject.*;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava; import ghidra.javaclass.format.constantpool.*;
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.program.model.data.*; import ghidra.program.model.data.*;
/** /**
@ -34,7 +29,6 @@ import ghidra.program.model.data.*;
* *
*/ */
public class DescriptorDecoder { public class DescriptorDecoder {
public final static byte BASE_TYPE_BYTE = 'B'; 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_ENUM = 'e';
public final static byte BASE_TYPE_ANNOTATION = '@'; public final static byte BASE_TYPE_ANNOTATION = '@';
//private constructor to enforce noninstantiability //private constructor to enforce noninstantiability
private DescriptorDecoder(){ private DescriptorDecoder() {
throw new AssertionError(); throw new AssertionError();
} }
@ -65,11 +58,11 @@ public class DescriptorDecoder {
* @param methodDescriptor * @param methodDescriptor
* @return * @return
*/ */
public static int getStackPurge(String methodDescriptor){ public static int getStackPurge(String methodDescriptor) {
int stackPurge = 0; int stackPurge = 0;
List<JavaComputationalCategory> categories = getParameterCategories(methodDescriptor); List<JavaComputationalCategory> categories = getParameterCategories(methodDescriptor);
for (JavaComputationalCategory cat : categories){ for (JavaComputationalCategory cat : categories) {
switch (cat){ switch (cat) {
case CAT_1: case CAT_1:
stackPurge += PcodeInjectLibraryJava.REFERENCE_SIZE; stackPurge += PcodeInjectLibraryJava.REFERENCE_SIZE;
break; break;
@ -83,28 +76,38 @@ public class DescriptorDecoder {
return stackPurge; return stackPurge;
} }
/** /**
* Returns the computational category of the return type of a method descriptor. * Returns the computational category of the return type of a method descriptor.
* @param methodDescriptor * @param methodDescriptor
* @return * @return
*/ */
public static JavaComputationalCategory getReturnCategoryOfMethodDescriptor(String methodDescriptor){ public static JavaComputationalCategory getReturnCategoryOfMethodDescriptor(
String methodDescriptor) {
int closeParenIndex = methodDescriptor.indexOf(")"); int closeParenIndex = methodDescriptor.indexOf(")");
if (closeParenIndex == -1){ if (closeParenIndex == -1) {
throw new IllegalArgumentException("Invalid method descriptor: " + methodDescriptor); 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); 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(")"); int closeParenIndex = methodDescriptor.indexOf(")");
if (closeParenIndex == -1){ if (closeParenIndex == -1) {
throw new IllegalArgumentException("Invalid method descriptor: " + methodDescriptor); throw new IllegalArgumentException("Invalid method descriptor: " + methodDescriptor);
} }
String returnDescriptor = methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length()); String returnDescriptor =
if (returnDescriptor.startsWith("[")){ methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
if (returnDescriptor.startsWith("[")) {
return getPointerType(returnDescriptor, dtManager); return getPointerType(returnDescriptor, dtManager);
} }
return DescriptorDecoder.getDataTypeOfDescriptor(returnDescriptor, dtManager); return DescriptorDecoder.getDataTypeOfDescriptor(returnDescriptor, dtManager);
@ -115,11 +118,12 @@ public class DescriptorDecoder {
* @param descriptor * @param descriptor
* @return * @return
*/ */
public static JavaComputationalCategory getComputationalCategoryOfDescriptor(String descriptor){ public static JavaComputationalCategory getComputationalCategoryOfDescriptor(
String descriptor) {
//all references to objects start with "L" //all references to objects start with "L"
//all references to arrays start with "[" //all references to arrays start with "["
//all other descriptors are just one letter. //all other descriptors are just one letter.
switch (descriptor.charAt(0)){ switch (descriptor.charAt(0)) {
case BASE_TYPE_BYTE: //signed byte case BASE_TYPE_BYTE: //signed byte
case BASE_TYPE_CHAR: //char case BASE_TYPE_CHAR: //char
case BASE_TYPE_FLOAT: //float case BASE_TYPE_FLOAT: //float
@ -144,7 +148,8 @@ public class DescriptorDecoder {
* @param methodDescriptor * @param methodDescriptor
* @return * @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<>(); ArrayList<String> typeNames = new ArrayList<>();
int closeParenIndex = methodDescriptor.indexOf(")"); int closeParenIndex = methodDescriptor.indexOf(")");
String argString = methodDescriptor.substring(1, closeParenIndex); String argString = methodDescriptor.substring(1, closeParenIndex);
@ -152,36 +157,41 @@ public class DescriptorDecoder {
int currentPosition = 0; int currentPosition = 0;
int len = argString.length(); int len = argString.length();
while (currentPosition < len){ while (currentPosition < len) {
String currentParam = argString.substring(currentPosition, currentPosition + 1); String currentParam = argString.substring(currentPosition, currentPosition + 1);
if (currentParam.equals("[")){ if (currentParam.equals("[")) {
int initialBracket = currentPosition; int initialBracket = currentPosition;
while (argString.charAt(currentPosition) == '['){ while (argString.charAt(currentPosition) == '[') {
currentPosition++; currentPosition++;
} }
//advance past the base type of the array //advance past the base type of the array
if (argString.charAt(currentPosition) == 'L'){ if (argString.charAt(currentPosition) == 'L') {
int semiColonIndex = argString.indexOf(";", currentPosition); int semiColonIndex = argString.indexOf(";", currentPosition);
currentPosition = semiColonIndex + 1; currentPosition = semiColonIndex + 1;
} }
else{ else {
currentPosition++; currentPosition++;
} }
currentParamTypeName = getTypeNameFromDescriptor(argString.substring(initialBracket,currentPosition), fullyQualifiedName, replaceSlash); currentParamTypeName =
getTypeNameFromDescriptor(argString.substring(initialBracket, currentPosition),
fullyQualifiedName, replaceSlash);
typeNames.add(currentParamTypeName); typeNames.add(currentParamTypeName);
continue; continue;
} }
//advance to next type in argString //advance to next type in argString
//if it's a reference, it starts with L and ends with a ; //if it's a reference, it starts with L and ends with a ;
//otherwise you only need to advance one character //otherwise you only need to advance one character
switch(currentParam){ switch (currentParam) {
case "L": case "L":
int semiColonIndex = argString.indexOf(";", currentPosition); 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 ; currentPosition = semiColonIndex + 1; //advance past ;
break; break;
default: default:
currentParamTypeName = getTypeNameFromDescriptor(currentParam, fullyQualifiedName, replaceSlash); currentParamTypeName =
getTypeNameFromDescriptor(currentParam, fullyQualifiedName, replaceSlash);
currentPosition++; currentPosition++;
} }
typeNames.add(currentParamTypeName); typeNames.add(currentParamTypeName);
@ -189,42 +199,43 @@ public class DescriptorDecoder {
} }
//now add the the name of the return type //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)); typeNames.add(getTypeNameFromDescriptor(returnType, fullyQualifiedName, replaceSlash));
return typeNames; return typeNames;
} }
/** /**
* Returns the type name for a parameter descriptor * Returns the type name for a parameter descriptor
* @param descriptor * @param descriptor
* @return * @return
*/ */
public static String getTypeNameFromDescriptor(String descriptor, boolean fullyQualifiedName, boolean replaceSlash){ public static String getTypeNameFromDescriptor(String descriptor, boolean fullyQualifiedName,
if (descriptor.startsWith("L")){ boolean replaceSlash) {
if (descriptor.startsWith("L")) {
//leave off the initial L and the final ; //leave off the initial L and the final ;
String name = descriptor.substring(1, descriptor.length()-1); String name = descriptor.substring(1, descriptor.length() - 1);
if (fullyQualifiedName){ if (fullyQualifiedName) {
if (replaceSlash){ if (replaceSlash) {
return name.replace("/", "."); return name.replace("/", ".");
} }
return name; return name;
} }
int lastSlash = name.lastIndexOf("/"); int lastSlash = name.lastIndexOf("/");
//lastSlash+1 so the slash is not included in the name //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; int dimension = descriptor.lastIndexOf("[") + 1;
String baseType = getTypeNameFromDescriptor(descriptor.replace("[", ""), fullyQualifiedName, replaceSlash); String baseType = getTypeNameFromDescriptor(descriptor.replace("[", ""),
fullyQualifiedName, replaceSlash);
StringBuilder sb = new StringBuilder(baseType); StringBuilder sb = new StringBuilder(baseType);
for (int i = 0; i < dimension; ++i){ for (int i = 0; i < dimension; ++i) {
sb.append("[]"); sb.append("[]");
} }
return sb.toString(); return sb.toString();
} }
switch (descriptor.charAt(0)){ switch (descriptor.charAt(0)) {
case BASE_TYPE_BYTE: //signed byte case BASE_TYPE_BYTE: //signed byte
return "byte"; return "byte";
case BASE_TYPE_CHAR: //char case BASE_TYPE_CHAR: //char
@ -248,17 +259,18 @@ public class DescriptorDecoder {
} }
} }
public static DataType getReferenceTypeOfDescriptor(String descriptor, DataTypeManager dtManager, boolean includesLandSemi){ public static DataType getReferenceTypeOfDescriptor(String descriptor,
if (includesLandSemi){ DataTypeManager dtManager, boolean includesLandSemi) {
descriptor = descriptor.substring(1, descriptor.length()-1); if (includesLandSemi) {
descriptor = descriptor.substring(1, descriptor.length() - 1);
} }
String[] parts = descriptor.split("/"); String[] parts = descriptor.split("/");
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (int i = 0; i < parts.length; i++){ for (String part : parts) {
sb.append(CategoryPath.DELIMITER_CHAR); 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); DataType referencedType = dtManager.getDataType(dataPath);
return new PointerDataType(referencedType); return new PointerDataType(referencedType);
} }
@ -268,17 +280,17 @@ public class DescriptorDecoder {
* @param descriptor * @param descriptor
* @return * @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 objects start with "L"
//all references to arrays start with "[" //all references to arrays start with "["
//all other descriptors are just one letter. //all other descriptors are just one letter.
if (descriptor.startsWith("[")){ if (descriptor.startsWith("[")) {
return getPointerType(descriptor, dtManager); return getPointerType(descriptor, dtManager);
} }
switch (descriptor.charAt(0)){ switch (descriptor.charAt(0)) {
case BASE_TYPE_BYTE: case BASE_TYPE_BYTE:
return SignedByteDataType.dataType; return SignedByteDataType.dataType;
case BASE_TYPE_CHAR: case BASE_TYPE_CHAR:
return CharDataType.dataType; return CharDataType.dataType;
case BASE_TYPE_INT: case BASE_TYPE_INT:
return IntegerDataType.dataType; return IntegerDataType.dataType;
@ -297,15 +309,21 @@ public class DescriptorDecoder {
case BASE_TYPE_VOID: //void (only for return types) case BASE_TYPE_VOID: //void (only for return types)
return DataType.VOID; return DataType.VOID;
default: 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("["); int lastBracket = descriptor.lastIndexOf("[");
String baseTypeOfArray = descriptor.substring(lastBracket+1, lastBracket+2); String baseTypeOfArray = descriptor.substring(lastBracket + 1, lastBracket + 2);
DataType baseType = null; DataType baseType = null;
switch (baseTypeOfArray.charAt(0)){ switch (baseTypeOfArray.charAt(0)) {
case BASE_TYPE_BYTE: case BASE_TYPE_BYTE:
baseType = ArrayMethods.getArrayBaseType(JavaClassConstants.T_BYTE, dtManager); baseType = ArrayMethods.getArrayBaseType(JavaClassConstants.T_BYTE, dtManager);
break; break;
@ -334,7 +352,8 @@ public class DescriptorDecoder {
return dtManager.getPointer(DWordDataType.dataType); return dtManager.getPointer(DWordDataType.dataType);
default: default:
throw new IllegalArgumentException("Invalid array base type category: " + baseTypeOfArray); throw new IllegalArgumentException(
"Invalid array base type category: " + baseTypeOfArray);
} }
return dtManager.getPointer(baseType); return dtManager.getPointer(baseType);
} }
@ -345,17 +364,18 @@ public class DescriptorDecoder {
* @param methodDescriptor * @param methodDescriptor
* @return * @return
*/ */
public static List<JavaComputationalCategory> getParameterCategories(String methodDescriptor){ public static List<JavaComputationalCategory> getParameterCategories(String methodDescriptor) {
ArrayList<JavaComputationalCategory> categories = new ArrayList<>(); ArrayList<JavaComputationalCategory> categories = new ArrayList<>();
int closeParenIndex = methodDescriptor.indexOf(")"); int closeParenIndex = methodDescriptor.indexOf(")");
String argString = methodDescriptor.substring(1, closeParenIndex); String argString = methodDescriptor.substring(1, closeParenIndex);
int currentPosition = 0; int currentPosition = 0;
int len = argString.length(); int len = argString.length();
while (currentPosition < len){ while (currentPosition < len) {
String currentParam = argString.substring(currentPosition, currentPosition + 1); String currentParam = argString.substring(currentPosition, currentPosition + 1);
JavaComputationalCategory category = DescriptorDecoder.getComputationalCategoryOfDescriptor(currentParam); JavaComputationalCategory category =
DescriptorDecoder.getComputationalCategoryOfDescriptor(currentParam);
switch (category){ switch (category) {
case CAT_1: case CAT_1:
categories.add(JavaComputationalCategory.CAT_1); categories.add(JavaComputationalCategory.CAT_1);
break; break;
@ -370,22 +390,22 @@ public class DescriptorDecoder {
//if it's a reference, it starts with L and ends with a ; //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) //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 //otherwise you only need to advance one character
switch(currentParam){ switch (currentParam) {
case "L": case "L":
int semiColonIndex = argString.indexOf(";", currentPosition); int semiColonIndex = argString.indexOf(";", currentPosition);
currentPosition = semiColonIndex + 1; //advance past ; currentPosition = semiColonIndex + 1; //advance past ;
break; break;
case "[": case "[":
//advance past all the ['s //advance past all the ['s
while (argString.charAt(currentPosition) == '['){ while (argString.charAt(currentPosition) == '[') {
currentPosition++; currentPosition++;
} }
//advance past the base type of the array //advance past the base type of the array
if (argString.charAt(currentPosition) == 'L'){ if (argString.charAt(currentPosition) == 'L') {
semiColonIndex = argString.indexOf(";", currentPosition); semiColonIndex = argString.indexOf(";", currentPosition);
currentPosition = semiColonIndex + 1; currentPosition = semiColonIndex + 1;
} }
else{ else {
currentPosition++; currentPosition++;
} }
break; break;
@ -402,7 +422,8 @@ public class DescriptorDecoder {
* @param methodDescriptor * @param methodDescriptor
* @return * @return
*/ */
public static List<DataType> getDataTypeList(String methodDescriptor, DataTypeManager dtManager) { public static List<DataType> getDataTypeList(String methodDescriptor,
DataTypeManager dtManager) {
ArrayList<DataType> paramDataTypes = new ArrayList<>(); ArrayList<DataType> paramDataTypes = new ArrayList<>();
int closeParenIndex = methodDescriptor.indexOf(")"); int closeParenIndex = methodDescriptor.indexOf(")");
String argString = methodDescriptor.substring(1, closeParenIndex); String argString = methodDescriptor.substring(1, closeParenIndex);
@ -411,14 +432,14 @@ public class DescriptorDecoder {
int currentPosition = 0; int currentPosition = 0;
int len = argString.length(); int len = argString.length();
String currentParam = null; String currentParam = null;
while (currentPosition < len){ while (currentPosition < len) {
int arrayDimensions = 0; int arrayDimensions = 0;
//if it's an array, decode the number of dimensions //if it's an array, decode the number of dimensions
while (argString.charAt(currentPosition) == '['){ while (argString.charAt(currentPosition) == '[') {
arrayDimensions++; arrayDimensions++;
currentPosition++; currentPosition++;
} }
switch (argString.charAt(currentPosition)){ switch (argString.charAt(currentPosition)) {
case BASE_TYPE_BYTE: case BASE_TYPE_BYTE:
case BASE_TYPE_CHAR: case BASE_TYPE_CHAR:
case BASE_TYPE_SHORT: case BASE_TYPE_SHORT:
@ -427,17 +448,17 @@ public class DescriptorDecoder {
case BASE_TYPE_FLOAT: case BASE_TYPE_FLOAT:
case BASE_TYPE_DOUBLE: case BASE_TYPE_DOUBLE:
case BASE_TYPE_BOOLEAN: case BASE_TYPE_BOOLEAN:
currentParam = argString.substring(currentPosition, currentPosition+1); currentParam = argString.substring(currentPosition, currentPosition + 1);
currentPosition++; currentPosition++;
break; break;
case BASE_TYPE_REFERENCE: case BASE_TYPE_REFERENCE:
int semiColonIndex = argString.indexOf(";", currentPosition); int semiColonIndex = argString.indexOf(";", currentPosition);
currentParam = argString.substring(currentPosition, semiColonIndex+1); currentParam = argString.substring(currentPosition, semiColonIndex + 1);
currentPosition = semiColonIndex + 1; currentPosition = semiColonIndex + 1;
break; break;
} }
currentParamType = getDataTypeOfDescriptor(currentParam, dtManager); currentParamType = getDataTypeOfDescriptor(currentParam, dtManager);
if (arrayDimensions > 0){ if (arrayDimensions > 0) {
paramDataTypes.add(dtManager.getPointer(currentParamType)); paramDataTypes.add(dtManager.getPointer(currentParamType));
} }
else { else {
@ -455,47 +476,91 @@ public class DescriptorDecoder {
* @param type * @param type
* @return * @return
*/ */
public static String getDescriptorForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type){ public static String getDescriptorForInvoke(int offset,
AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) {
String descriptor = null; String descriptor = null;
int name_and_type_index = 0; int name_and_type_index = 0;
switch (type){ switch (type) {
case INVOKE_DYNAMIC: case INVOKE_DYNAMIC:
ConstantPoolInvokeDynamicInfo dynamicInfo = (ConstantPoolInvokeDynamicInfo) constantPool[offset]; ConstantPoolInvokeDynamicInfo dynamicInfo =
(ConstantPoolInvokeDynamicInfo) constantPool[offset];
name_and_type_index = dynamicInfo.getNameAndTypeIndex(); name_and_type_index = dynamicInfo.getNameAndTypeIndex();
break; break;
case INVOKE_INTERFACE: case INVOKE_INTERFACE:
ConstantPoolInterfaceMethodReferenceInfo interfaceInfo = (ConstantPoolInterfaceMethodReferenceInfo) constantPool[offset]; ConstantPoolInterfaceMethodReferenceInfo interfaceInfo =
(ConstantPoolInterfaceMethodReferenceInfo) constantPool[offset];
name_and_type_index = interfaceInfo.getNameAndTypeIndex(); name_and_type_index = interfaceInfo.getNameAndTypeIndex();
break; break;
case INVOKE_SPECIAL:
case INVOKE_STATIC: 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: case INVOKE_VIRTUAL:
ConstantPoolMethodReferenceInfo methodReferenceInfo = (ConstantPoolMethodReferenceInfo) constantPool[offset]; ConstantPoolMethodReferenceInfo methodReferenceInfo =
(ConstantPoolMethodReferenceInfo) constantPool[offset];
name_and_type_index = methodReferenceInfo.getNameAndTypeIndex(); name_and_type_index = methodReferenceInfo.getNameAndTypeIndex();
break; break;
default: default:
throw new IllegalArgumentException("unimplemented method type: " + type.name()); 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(); int descriptor_index = methodNameAndType.getDescriptorIndex();
ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index]; ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
descriptor = descriptorInfo.getString(); descriptor = descriptorInfo.getString();
return descriptor; return descriptor;
} }
public final static String decodeType(ConstantPoolUtf8Info utf, /**
boolean useFullyQualifiedClassName) { * Resolves the datatype represented by {@code fullyQualifiedName} with a base type of
return DescriptorDecoder.getTypeNameFromDescriptor(utf.getString(), useFullyQualifiedClassName, true); * {@code baseType} into dtm
} * @param fullyQualifiedName String representation of type
* @param dtm data type manager
//no L, no ; * @param baseType base type
public static DataType resolveClassForString(String fullyQualifiedName, DataTypeManager dtm, DataType baseType){ * @return data type represented by input string
*/
public static DataType resolveClassForString(String fullyQualifiedName, DataTypeManager dtm,
DataType baseType) {
fullyQualifiedName = CategoryPath.DELIMITER_CHAR + fullyQualifiedName; fullyQualifiedName = CategoryPath.DELIMITER_CHAR + fullyQualifiedName;
CategoryPath catPath = new CategoryPath(fullyQualifiedName); CategoryPath catPath = new CategoryPath(fullyQualifiedName);
String[] parts = catPath.getPathElements(); 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); dtm.resolve(dataType, DataTypeConflictHandler.KEEP_HANDLER);
return dataType; 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; package ghidra.javaclass.format;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter; import ghidra.app.util.bin.StructConverter;
import ghidra.javaclass.format.attributes.*; import ghidra.javaclass.format.attributes.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/** /**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF * NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p> * <p>
@ -48,18 +48,18 @@ public class FieldInfoJava implements StructConverter {
private short nameIndex; private short nameIndex;
private short descriptorIndex; private short descriptorIndex;
private short attributesCount; 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(); _offset = reader.getPointerIndex();
accessFlags = reader.readNextShort(); accessFlags = reader.readNextShort();
nameIndex = reader.readNextShort(); nameIndex = reader.readNextShort();
descriptorIndex = reader.readNextShort(); descriptorIndex = reader.readNextShort();
attributesCount = reader.readNextShort(); attributesCount = reader.readNextShort();
attributes = new AbstractAttributeInfo[ attributesCount ]; attributes = new AbstractAttributeInfo[getAttributesCount()];
for ( int i = 0 ; i < attributesCount ; i++ ) { for (int i = 0; i < getAttributesCount(); i++) {
attributes[ i ] = AttributeFactory.get( reader, classFile.getConstantPool() ); attributes[i] = AttributeFactory.get(reader, classFile.getConstantPool());
} }
} }
@ -84,8 +84,8 @@ public class FieldInfoJava implements StructConverter {
* unqualified name denoting a field. * unqualified name denoting a field.
* @return a valid index into the constant_pool table * @return a valid index into the constant_pool table
*/ */
public short getNameIndex() { public int getNameIndex() {
return nameIndex; return nameIndex & 0xffff;
} }
/** /**
@ -95,8 +95,8 @@ public class FieldInfoJava implements StructConverter {
* descriptor. * descriptor.
* @return a valid index into the constant_pool table * @return a valid index into the constant_pool table
*/ */
public short getDescriptorIndex() { public int getDescriptorIndex() {
return descriptorIndex; return descriptorIndex & 0xffff;
} }
/** /**
@ -104,8 +104,8 @@ public class FieldInfoJava implements StructConverter {
* attributes of this field. * attributes of this field.
* @return the number of additional attributes * @return the number of additional attributes
*/ */
public short getAttributesCount() { public int getAttributesCount() {
return attributesCount; return attributesCount & 0xffff;
} }
/** /**
@ -137,13 +137,13 @@ public class FieldInfoJava implements StructConverter {
* information. * information.
* @return * @return
*/ */
public AbstractAttributeInfo [] getAttributes() { public AbstractAttributeInfo[] getAttributes() {
return attributes; return attributes;
} }
public ConstantValueAttribute getConstantValueAttribute() { public ConstantValueAttribute getConstantValueAttribute() {
for ( AbstractAttributeInfo attributeInfo : attributes ) { for (AbstractAttributeInfo attributeInfo : attributes) {
if ( attributeInfo instanceof ConstantValueAttribute ) { if (attributeInfo instanceof ConstantValueAttribute) {
return (ConstantValueAttribute) attributeInfo; return (ConstantValueAttribute) attributeInfo;
} }
} }
@ -152,17 +152,17 @@ public class FieldInfoJava implements StructConverter {
@Override @Override
public DataType toDataType() throws DuplicateNameException, IOException { 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, "access_flags", null);
structure.add( WORD, "name_index", null ); structure.add(WORD, "name_index", null);
structure.add( WORD, "descriptor_index", null ); structure.add(WORD, "descriptor_index", null);
structure.add( WORD, "attributes_count", null ); structure.add(WORD, "attributes_count", null);
for ( int i = 0 ; i < attributes.length ; ++i ) { for (int i = 0; i < attributes.length; ++i) {
structure.add( attributes[ i ].toDataType(), "attributes_" + i, null ); structure.add(attributes[i].toDataType(), "attributes_" + i, null);
} }
return structure; return structure;

View file

@ -15,13 +15,13 @@
*/ */
package ghidra.javaclass.format; 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.address.*;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.Msg; import ghidra.util.Msg;
import java.util.Arrays;
public class JavaClassUtil { public class JavaClassUtil {
public final static long LOOKUP_ADDRESS = 0xE0000000L; public final static long LOOKUP_ADDRESS = 0xE0000000L;
@ -29,28 +29,24 @@ public class JavaClassUtil {
public static final long METHOD_INDEX_SIZE = 65536 * 4; public static final long METHOD_INDEX_SIZE = 65536 * 4;
public final static boolean isClassFile(Program program) { 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") || byte[] bytes = new byte[4];
firmwarePath.toLowerCase().endsWith(".class")) { try {
byte[] bytes = new byte[4]; Address address = program.getAddressFactory().getAddressSpace(
try { JavaLoader.CONSTANT_POOL).getMinAddress();
Address address = program.getAddressFactory().getAddressSpace("constantPool").getMinAddress(); program.getMemory().getBytes(address, bytes);
program.getMemory().getBytes(address, bytes);
}
catch (Exception e) {
Msg.info(JavaClassUtil.class, e.getLocalizedMessage());
}
return Arrays.equals(bytes, JavaClassConstants.MAGIC_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 ) { public static Address toLookupAddress(Program program, int methodIndex) {
AddressFactory addressFactory = program.getAddressFactory( ); AddressFactory addressFactory = program.getAddressFactory();
AddressSpace defaultAddressSpace = addressFactory.getDefaultAddressSpace( ); AddressSpace defaultAddressSpace = addressFactory.getDefaultAddressSpace();
return defaultAddressSpace.getAddress( JavaClassUtil.LOOKUP_ADDRESS + ( methodIndex * 4 ) ); return defaultAddressSpace.getAddress(JavaClassUtil.LOOKUP_ADDRESS + (methodIndex * 4));
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -15,90 +15,82 @@
*/ */
package ghidra.javaclass.format.attributes; package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava; import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info; import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
import java.io.IOException;
public class AttributeFactory { public class AttributeFactory {
public static AbstractAttributeInfo get( BinaryReader reader, AbstractConstantPoolInfoJava [] constantPool ) throws IOException { public static AbstractAttributeInfo get(BinaryReader reader,
AbstractConstantPoolInfoJava[] constantPool) throws IOException {
int attributeNameIndex = reader.readShort( reader.getPointerIndex() ); int attributeNameIndex = reader.readShort(reader.getPointerIndex());
if ( attributeNameIndex < 1 || attributeNameIndex >= constantPool.length ) { if (attributeNameIndex < 1 || attributeNameIndex >= constantPool.length) {
throw new RuntimeException( "invalid index"); throw new RuntimeException("invalid index");
} }
if ( !( constantPool[ attributeNameIndex ] instanceof ConstantPoolUtf8Info ) ) { if (!(constantPool[attributeNameIndex] instanceof ConstantPoolUtf8Info)) {
throw new RuntimeException(); throw new RuntimeException();
} }
ConstantPoolUtf8Info utf8 = (ConstantPoolUtf8Info) constantPool[ attributeNameIndex ]; ConstantPoolUtf8Info utf8 = (ConstantPoolUtf8Info) constantPool[attributeNameIndex];
if ( utf8.getString().equals( AttributesConstants.ConstantValue ) ) { switch (utf8.getString()) {
return new ConstantValueAttribute( reader ); 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 * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 Deprecated = "Deprecated";
public final static String RuntimeVisibleAnnotations = "RuntimeVisibleAnnotations"; public final static String RuntimeVisibleAnnotations = "RuntimeVisibleAnnotations";
public final static String RuntimeInvisibleAnnotations = "RuntimeInvisibleAnnotations"; public final static String RuntimeInvisibleAnnotations = "RuntimeInvisibleAnnotations";
public final static String RuntimeVisibleParameterAnnotations = "RuntimeVisibleParameterAnnotations"; public final static String RuntimeVisibleParameterAnnotations =
public final static String RuntimeInvisibleParameterAnnotations = "RuntimeInvisibleParameterAnnotations"; "RuntimeVisibleParameterAnnotations";
public final static String RuntimeInvisibleParameterAnnotations =
"RuntimeInvisibleParameterAnnotations";
public final static String AnnotationDefault = "AnnotationDefault"; public final static String AnnotationDefault = "AnnotationDefault";
public final static String BootstrapMethods = "BootstrapMethods"; 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 * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.BinaryReader;
import ghidra.app.util.bin.StructConverter; import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.ArrayDataType; import ghidra.program.model.data.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
/** /**
@ -34,12 +31,12 @@ public class BootstrapMethods implements StructConverter {
private short bootstrapMethodsReference; private short bootstrapMethodsReference;
private short numberOfBootstrapArguments; private short numberOfBootstrapArguments;
private short [] bootstrapArguments; private short[] bootstrapArguments;
public BootstrapMethods( BinaryReader reader ) throws IOException { public BootstrapMethods(BinaryReader reader) throws IOException {
bootstrapMethodsReference = reader.readNextShort(); bootstrapMethodsReference = reader.readNextShort();
numberOfBootstrapArguments = 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 * @return a valid index into the constant_pool table
*/ */
public short getBootstrapMethodsReference() { public int getBootstrapMethodsReference() {
return bootstrapMethodsReference; return bootstrapMethodsReference & 0xffff;
} }
/** /**
@ -64,8 +61,8 @@ public class BootstrapMethods implements StructConverter {
* items in the bootstrap_arguments array. * items in the bootstrap_arguments array.
* @return the number of items in the bootstrap_arguments array * @return the number of items in the bootstrap_arguments array
*/ */
public short getNumberOfBootstrapArguments() { public int getNumberOfBootstrapArguments() {
return numberOfBootstrapArguments; return numberOfBootstrapArguments & 0xffff;
} }
/** /**
@ -80,20 +77,21 @@ public class BootstrapMethods implements StructConverter {
* CONSTANT_Double_info, * CONSTANT_Double_info,
* CONSTANT_MethodHandle_info, or * CONSTANT_MethodHandle_info, or
* CONSTANT_MethodType_info structure. * CONSTANT_MethodType_info structure.
* @return * @param i entry
* @return index
*/ */
public short [] getBootstrapArguments() { public int getBootstrapArgumentsEntry(int i) {
return bootstrapArguments; return bootstrapArguments[i] & 0xffff;
} }
@Override @Override
public DataType toDataType() throws DuplicateNameException, IOException { public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType structure = new StructureDataType( "bootstrap_methods", 0 ); StructureDataType structure = new StructureDataType("bootstrap_methods", 0);
structure.add( WORD, "bootstrap_method_ref", null ); structure.add(WORD, "bootstrap_method_ref", null);
structure.add( WORD, "num_bootstrap_arguments", null ); structure.add(WORD, "num_bootstrap_arguments", null);
if ( numberOfBootstrapArguments > 0 ) { if (numberOfBootstrapArguments > 0) {
DataType array = new ArrayDataType( WORD, numberOfBootstrapArguments, WORD.getLength() ); DataType array = new ArrayDataType(WORD, numberOfBootstrapArguments, WORD.getLength());
structure.add( array, "bootstrapArguments", null ); structure.add(array, "bootstrapArguments", null);
} }
return structure; return structure;
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -18,9 +18,7 @@ package ghidra.javaclass.format.constantpool;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.*;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
/** /**
@ -47,8 +45,8 @@ public class ConstantPoolClassInfo extends AbstractConstantPoolInfoJava {
private short nameIndex; private short nameIndex;
public ConstantPoolClassInfo( BinaryReader reader ) throws IOException { public ConstantPoolClassInfo(BinaryReader reader) throws IOException {
super( reader ); super(reader);
nameIndex = reader.readNextShort(); nameIndex = reader.readNextShort();
} }
@ -60,16 +58,16 @@ public class ConstantPoolClassInfo extends AbstractConstantPoolInfoJava {
* interface name encoded in internal form (?4.2.1). * interface name encoded in internal form (?4.2.1).
* @return a valid index into the constant_pool table * @return a valid index into the constant_pool table
*/ */
public short getNameIndex() { public int getNameIndex() {
return nameIndex; return nameIndex & 0xffff;
} }
@Override @Override
public DataType toDataType() throws DuplicateNameException, IOException { public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_Class_info"; String name = "CONSTANT_Class_info";
Structure structure = new StructureDataType( name, 0 ); Structure structure = new StructureDataType(name, 0);
structure.add( BYTE, "tag", null ); structure.add(BYTE, "tag", null);
structure.add( WORD, "name_index", null ); structure.add(WORD, "name_index", null);
return structure; 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; package ghidra.javaclass.format.constantpool;
import ghidra.app.util.bin.BinaryReader;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
public class ConstantPoolFactory { 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: case ConstantPoolTagsJava.CONSTANT_Class:
return new ConstantPoolClassInfo( reader ); return new ConstantPoolClassInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Double: case ConstantPoolTagsJava.CONSTANT_Double:
return new ConstantPoolDoubleInfo( reader ); return new ConstantPoolDoubleInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Fieldref: case ConstantPoolTagsJava.CONSTANT_Fieldref:
return new ConstantPoolFieldReferenceInfo( reader ); return new ConstantPoolFieldReferenceInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Float: case ConstantPoolTagsJava.CONSTANT_Float:
return new ConstantPoolFloatInfo( reader ); return new ConstantPoolFloatInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Integer: case ConstantPoolTagsJava.CONSTANT_Integer:
return new ConstantPoolIntegerInfo( reader ); return new ConstantPoolIntegerInfo(reader);
case ConstantPoolTagsJava.CONSTANT_InterfaceMethodref: case ConstantPoolTagsJava.CONSTANT_InterfaceMethodref:
return new ConstantPoolInterfaceMethodReferenceInfo( reader ); return new ConstantPoolInterfaceMethodReferenceInfo(reader);
case ConstantPoolTagsJava.CONSTANT_InvokeDynamic: case ConstantPoolTagsJava.CONSTANT_InvokeDynamic:
return new ConstantPoolInvokeDynamicInfo( reader ); return new ConstantPoolInvokeDynamicInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Long: case ConstantPoolTagsJava.CONSTANT_Long:
return new ConstantPoolLongInfo( reader ); return new ConstantPoolLongInfo(reader);
case ConstantPoolTagsJava.CONSTANT_MethodHandle: case ConstantPoolTagsJava.CONSTANT_MethodHandle:
return new ConstantPoolMethodHandleInfo( reader ); return new ConstantPoolMethodHandleInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Methodref: case ConstantPoolTagsJava.CONSTANT_Methodref:
return new ConstantPoolMethodReferenceInfo( reader ); return new ConstantPoolMethodReferenceInfo(reader);
case ConstantPoolTagsJava.CONSTANT_MethodType: case ConstantPoolTagsJava.CONSTANT_MethodType:
return new ConstantPoolMethodTypeInfo( reader ); return new ConstantPoolMethodTypeInfo(reader);
case ConstantPoolTagsJava.CONSTANT_NameAndType: case ConstantPoolTagsJava.CONSTANT_NameAndType:
return new ConstantPoolNameAndTypeInfo( reader ); return new ConstantPoolNameAndTypeInfo(reader);
case ConstantPoolTagsJava.CONSTANT_String: case ConstantPoolTagsJava.CONSTANT_String:
return new ConstantPoolStringInfo( reader ); return new ConstantPoolStringInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Utf8: 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: case 0:
return null; 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; 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 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 * NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p> * <p>
* The CONSTANT_InvokeDynamic_info structure is used by an invokedynamic * 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 * invocation name, the argument and return types of the call, and optionally, a
* sequence of additional constants called static arguments to the bootstrap method. * sequence of additional constants called static arguments to the bootstrap method.
* <pre> * <pre>
@ -43,8 +41,8 @@ public class ConstantPoolInvokeDynamicInfo extends AbstractConstantPoolInfoJava
private short bootstrapMethodAttrIndex; private short bootstrapMethodAttrIndex;
private short nameAndTypeIndex; private short nameAndTypeIndex;
public ConstantPoolInvokeDynamicInfo( BinaryReader reader ) throws IOException { public ConstantPoolInvokeDynamicInfo(BinaryReader reader) throws IOException {
super( reader ); super(reader);
bootstrapMethodAttrIndex = reader.readNextShort(); bootstrapMethodAttrIndex = reader.readNextShort();
nameAndTypeIndex = reader.readNextShort(); nameAndTypeIndex = reader.readNextShort();
} }
@ -55,8 +53,8 @@ public class ConstantPoolInvokeDynamicInfo extends AbstractConstantPoolInfoJava
* this class file. * this class file.
* @return a valid index into the bootstrap_methods array * @return a valid index into the bootstrap_methods array
*/ */
public short getBootstrapMethodAttrIndex() { public int getBootstrapMethodAttrIndex() {
return bootstrapMethodAttrIndex; return bootstrapMethodAttrIndex & 0xffff;
} }
/** /**
@ -66,17 +64,17 @@ public class ConstantPoolInvokeDynamicInfo extends AbstractConstantPoolInfoJava
* and method descriptor. * and method descriptor.
* @return a valid index into the constant_pool table * @return a valid index into the constant_pool table
*/ */
public short getNameAndTypeIndex() { public int getNameAndTypeIndex() {
return nameAndTypeIndex; return nameAndTypeIndex & 0xffff;
} }
@Override @Override
public DataType toDataType() throws DuplicateNameException, IOException { public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_InvokeDynamic_info"; String name = "CONSTANT_InvokeDynamic_info";
Structure structure = new StructureDataType( name, 0 ); Structure structure = new StructureDataType(name, 0);
structure.add( BYTE, "tag", null ); structure.add(BYTE, "tag", null);
structure.add( WORD, "bootstrap_method_attr_index", null ); structure.add(WORD, "bootstrap_method_attr_index", null);
structure.add( WORD, "name_and_type_index", null ); structure.add(WORD, "name_and_type_index", null);
return structure; return structure;
} }

View file

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

View file

@ -18,9 +18,7 @@ package ghidra.javaclass.format.constantpool;
import java.io.IOException; import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.*;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
/** /**
@ -38,8 +36,8 @@ public class ConstantPoolMethodTypeInfo extends AbstractConstantPoolInfoJava {
private short descriptorIndex; private short descriptorIndex;
public ConstantPoolMethodTypeInfo( BinaryReader reader ) throws IOException { public ConstantPoolMethodTypeInfo(BinaryReader reader) throws IOException {
super( reader ); super(reader);
descriptorIndex = reader.readNextShort(); descriptorIndex = reader.readNextShort();
} }
@ -49,16 +47,16 @@ public class ConstantPoolMethodTypeInfo extends AbstractConstantPoolInfoJava {
* CONSTANT_Utf8_info structure representing a method descriptor. * CONSTANT_Utf8_info structure representing a method descriptor.
* @return a valid index into the constant_pool table * @return a valid index into the constant_pool table
*/ */
public short getDescriptorIndex() { public int getDescriptorIndex() {
return descriptorIndex; return descriptorIndex & 0xffff;
} }
@Override @Override
public DataType toDataType() throws DuplicateNameException, IOException { public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_MethodType_info"; String name = "CONSTANT_MethodType_info";
Structure structure = new StructureDataType( name, 0 ); Structure structure = new StructureDataType(name, 0);
structure.add( BYTE, "tag", null ); structure.add(BYTE, "tag", null);
structure.add( WORD, "descriptor_index", null ); structure.add(WORD, "descriptor_index", null);
return structure; 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; 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 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 * NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p> * <p>
@ -41,8 +39,8 @@ public class ConstantPoolNameAndTypeInfo extends AbstractConstantPoolInfoJava {
private short nameIndex; private short nameIndex;
private short descriptorIndex; private short descriptorIndex;
public ConstantPoolNameAndTypeInfo( BinaryReader reader ) throws IOException { public ConstantPoolNameAndTypeInfo(BinaryReader reader) throws IOException {
super( reader ); super(reader);
nameIndex = reader.readNextShort(); nameIndex = reader.readNextShort();
descriptorIndex = reader.readNextShort(); descriptorIndex = reader.readNextShort();
} }
@ -55,8 +53,8 @@ public class ConstantPoolNameAndTypeInfo extends AbstractConstantPoolInfoJava {
* method. * method.
* @return a valid index into the constant_pool table to the name * @return a valid index into the constant_pool table to the name
*/ */
public short getNameIndex() { public int getNameIndex() {
return nameIndex; return nameIndex & 0xffff;
} }
/** /**
@ -66,17 +64,17 @@ public class ConstantPoolNameAndTypeInfo extends AbstractConstantPoolInfoJava {
* or method descriptor. * or method descriptor.
* @return a valid index into the constant_pool table to the descriptor * @return a valid index into the constant_pool table to the descriptor
*/ */
public short getDescriptorIndex() { public int getDescriptorIndex() {
return descriptorIndex; return descriptorIndex & 0xffff;
} }
@Override @Override
public DataType toDataType() throws DuplicateNameException, IOException { public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_NameAndType_info"; String name = "CONSTANT_NameAndType_info";
Structure structure = new StructureDataType( name, 0 ); Structure structure = new StructureDataType(name, 0);
structure.add( BYTE, "tag", null ); structure.add(BYTE, "tag", null);
structure.add( WORD, "name_index", null ); structure.add(WORD, "name_index", null);
structure.add( WORD, "descriptor_index", null ); structure.add(WORD, "descriptor_index", null);
return structure; 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 java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.*;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
/** /**
@ -39,7 +37,7 @@ public class ConstantPoolStringInfo extends AbstractConstantPoolInfoJava {
private short stringIndex; private short stringIndex;
public ConstantPoolStringInfo( BinaryReader reader ) throws IOException { public ConstantPoolStringInfo(BinaryReader reader) throws IOException {
super(reader); super(reader);
stringIndex = reader.readNextShort(); stringIndex = reader.readNextShort();
} }
@ -51,16 +49,16 @@ public class ConstantPoolStringInfo extends AbstractConstantPoolInfoJava {
* code points to which the String object is to be initialized. * code points to which the String object is to be initialized.
* @return a valid index into the constant_pool table * @return a valid index into the constant_pool table
*/ */
public short getStringIndex() { public int getStringIndex() {
return stringIndex; return stringIndex & 0xffff;
} }
@Override @Override
public DataType toDataType() throws DuplicateNameException, IOException { public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_String_info"; String name = "CONSTANT_String_info";
Structure structure = new StructureDataType( name, 0 ); Structure structure = new StructureDataType(name, 0);
structure.add( BYTE, "tag", null ); structure.add(BYTE, "tag", null);
structure.add( WORD, "string_index", null ); structure.add(WORD, "string_index", null);
return structure; return structure;
} }

View file

@ -17,19 +17,22 @@ package ghidra.javaclass.format.constantpool;
public final class ConstantPoolTagsJava { public final class ConstantPoolTagsJava {
public final static byte CONSTANT_Class = 7; public final static byte CONSTANT_Class = 7;
public final static byte CONSTANT_Fieldref = 9; public final static byte CONSTANT_Fieldref = 9;
public final static byte CONSTANT_Methodref = 10; public final static byte CONSTANT_Methodref = 10;
public final static byte CONSTANT_InterfaceMethodref = 11; public final static byte CONSTANT_InterfaceMethodref = 11;
public final static byte CONSTANT_String = 8; public final static byte CONSTANT_String = 8;
public final static byte CONSTANT_Integer = 3; public final static byte CONSTANT_Integer = 3;
public final static byte CONSTANT_Float = 4; public final static byte CONSTANT_Float = 4;
public final static byte CONSTANT_Long = 5; public final static byte CONSTANT_Long = 5;
public final static byte CONSTANT_Double = 6; public final static byte CONSTANT_Double = 6;
public final static byte CONSTANT_NameAndType = 12; public final static byte CONSTANT_NameAndType = 12;
public final static byte CONSTANT_Utf8 = 1; public final static byte CONSTANT_Utf8 = 1;
public final static byte CONSTANT_MethodHandle = 15; public final static byte CONSTANT_MethodHandle = 15;
public final static byte CONSTANT_MethodType = 16; public final static byte CONSTANT_MethodType = 16;
public final static byte CONSTANT_InvokeDynamic = 18; 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 { public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
private short length; private short length;
private byte [] bytes; private byte[] bytes;
public ConstantPoolUtf8Info( BinaryReader reader ) throws IOException { public ConstantPoolUtf8Info(BinaryReader reader) throws IOException {
super( reader ); super(reader);
length = reader.readNextShort(); 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. * structure are not null-terminated.
* @return the number of bytes in the bytes array * @return the number of bytes in the bytes array
*/ */
public short getLength() { public int getLength() {
return length; return length & 0xffff;
} }
/** /**
@ -65,7 +65,7 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
* range (byte)0xf0 - (byte)0xff. * range (byte)0xf0 - (byte)0xff.
* @return the bytes of the string * @return the bytes of the string
*/ */
public byte [] getBytes() { public byte[] getBytes() {
return bytes; return bytes;
} }
@ -75,7 +75,7 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
* @return the byte array translated into a string * @return the byte array translated into a string
*/ */
public String getString() { public String getString() {
return new String( bytes ); return new String(bytes);
} }
@Override @Override
@ -86,10 +86,10 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
@Override @Override
public DataType toDataType() throws DuplicateNameException, IOException { public DataType toDataType() throws DuplicateNameException, IOException {
String name = "CONSTANT_Utf8_info" + "|" + length + "|"; String name = "CONSTANT_Utf8_info" + "|" + length + "|";
Structure structure = new StructureDataType( name, 0 ); Structure structure = new StructureDataType(name, 0);
structure.add( BYTE, "tag", null ); structure.add(BYTE, "tag", null);
structure.add( WORD, "length", null ); structure.add(WORD, "length", null);
if ( length > 0 ) { if (length > 0) {
structure.add(UTF8, length, "data", null); structure.add(UTF8, length, "data", null);
} }
return structure; return structure;

View file

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

View file

@ -22,35 +22,35 @@ import org.junit.Test;
public class PcodeTextEmitterTest { public class PcodeTextEmitterTest {
@Test @Test
public void testEmitPushType1Value(){ public void testEmitPushType1Value() {
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitPushCat1Value(pCode, "x"); PcodeTextEmitter.emitPushCat1Value(pCode, "x");
assertTrue(pCode.toString().equals("SP = SP - 4;\n*:4 SP = x;\n")); assertTrue(pCode.toString().equals("SP = SP - 4;\n*:4 SP = x;\n"));
} }
@Test @Test
public void testEmitPushType2Value(){ public void testEmitPushType2Value() {
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitPushCat2Value(pCode, "x"); PcodeTextEmitter.emitPushCat2Value(pCode, "x");
assertTrue(pCode.toString().equals("SP = SP - 8;\n*:8 SP = x;\n")); assertTrue(pCode.toString().equals("SP = SP - 8;\n*:8 SP = x;\n"));
} }
@Test @Test
public void testEmitPopType1Value(){ public void testEmitPopType1Value() {
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitPopCat1Value(pCode, "x"); PcodeTextEmitter.emitPopCat1Value(pCode, "x");
assertTrue(pCode.toString().equals("x:4 = *:4 SP;\nSP = SP + 4;\n")); assertTrue(pCode.toString().equals("x:4 = *:4 SP;\nSP = SP + 4;\n"));
} }
@Test @Test
public void testEmitPopType2Value(){ public void testEmitPopType2Value() {
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitPopCat2Value(pCode, "x"); PcodeTextEmitter.emitPopCat2Value(pCode, "x");
assertTrue(pCode.toString().equals("x:8 = *:8 SP;\nSP = SP + 8;\n")); assertTrue(pCode.toString().equals("x:8 = *:8 SP;\nSP = SP + 8;\n"));
} }
@Test @Test
public void testEmitVarnodeBytesFromPcodeOpCall(){ public void testEmitVarnodeBytesFromPcodeOpCall() {
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
//test no args //test no args
@ -64,10 +64,10 @@ public class PcodeTextEmitterTest {
//two args //two args
pCode = new StringBuilder(); pCode = new StringBuilder();
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 4, "PCODEOP", "ARG1", "ARG2"); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 4, "PCODEOP", "ARG1",
"ARG2");
assertTrue(pCode.toString().equals("LHS:4 = PCODEOP(ARG1,ARG2);\n")); assertTrue(pCode.toString().equals("LHS:4 = PCODEOP(ARG1,ARG2);\n"));
//test no args //test no args
pCode = new StringBuilder(); pCode = new StringBuilder();
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 8, "PCODEOP"); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 8, "PCODEOP");
@ -80,12 +80,13 @@ public class PcodeTextEmitterTest {
//two args //two args
pCode = new StringBuilder(); pCode = new StringBuilder();
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 8, "PCODEOP", "ARG1", "ARG2"); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 8, "PCODEOP", "ARG1",
"ARG2");
assertTrue(pCode.toString().equals("LHS:8 = PCODEOP(ARG1,ARG2);\n")); assertTrue(pCode.toString().equals("LHS:8 = PCODEOP(ARG1,ARG2);\n"));
} }
@Test @Test
public void testEmitVoidPcodeOpCall(){ public void testEmitVoidPcodeOpCall() {
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
//test no args //test no args
@ -94,17 +95,17 @@ public class PcodeTextEmitterTest {
//one arg //one arg
pCode = new StringBuilder(); pCode = new StringBuilder();
PcodeTextEmitter.emitVoidPcodeOpCall(pCode,"PCODEOP", "ARG1"); PcodeTextEmitter.emitVoidPcodeOpCall(pCode, "PCODEOP", "ARG1");
assertTrue(pCode.toString().equals("PCODEOP(ARG1);\n")); assertTrue(pCode.toString().equals("PCODEOP(ARG1);\n"));
//two args //two args
pCode = new StringBuilder(); pCode = new StringBuilder();
PcodeTextEmitter.emitVoidPcodeOpCall(pCode,"PCODEOP", "ARG1", "ARG2"); PcodeTextEmitter.emitVoidPcodeOpCall(pCode, "PCODEOP", "ARG1", "ARG2");
assertTrue(pCode.toString().equals("PCODEOP(ARG1,ARG2);\n")); assertTrue(pCode.toString().equals("PCODEOP(ARG1,ARG2);\n"));
} }
@Test @Test
public void testEmitAssignRegisterFromPcodeOpCall(){ public void testEmitAssignRegisterFromPcodeOpCall() {
//void call //void call
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, "REG", "TEST"); PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, "REG", "TEST");
@ -122,38 +123,59 @@ public class PcodeTextEmitterTest {
} }
@Test @Test
public void testEmitAssignConstantToRegister(){ public void testEmitAssignConstantToRegister() {
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitAssignConstantToRegister(pCode, "REGISTER", 0); PcodeTextEmitter.emitAssignConstantToRegister(pCode, "REGISTER", 0);
assertTrue(pCode.toString().equals("REGISTER = 0x0;\n")); assertTrue(pCode.toString().equals("REGISTER = 0x0;\n"));
} }
@Test @Test
public void testEmitLabelDef(){ public void testEmitLabelDef() {
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitLabelDefinition(pCode, "LABEL"); PcodeTextEmitter.emitLabelDefinition(pCode, "LABEL");
assertEquals("bad label definition emitted", "<LABEL>\n", pCode.toString()); assertEquals("bad label definition emitted", "<LABEL>\n", pCode.toString());
} }
@Test @Test
public void testEmitAddToStackPointer(){ public void testEmitIndirectCall() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitAddToStackPointer(pCode, 4);
assertEquals("SP = SP + 4;\n", pCode.toString());
}
@Test
public void testEmitIndirectCall(){
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitIndirectCall(pCode, "call_target"); PcodeTextEmitter.emitIndirectCall(pCode, "call_target");
assertEquals("call [call_target];\n", pCode.toString()); assertEquals("call [call_target];\n", pCode.toString());
} }
@Test @Test
public void testEmitWriteToMemory(){ public void testEmitWriteToMemory() {
StringBuilder pCode = new StringBuilder(); StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitWriteToMemory(pCode, "ram", 4, "offset", "test"); PcodeTextEmitter.emitWriteToMemory(pCode, "ram", 4, "offset", "test");
assertEquals("*[ram]:4 offset = test;\n", pCode.toString()); 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; package ghidra.app.util.pcodeInject;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -27,9 +26,7 @@ import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
public class ReferenceMethodsTest { public class ReferenceMethodsTest {
public ReferenceMethodsTest() {
public ReferenceMethodsTest(){
} }
@ -39,23 +36,26 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendMagic(classFile); TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile); TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7); 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.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3 TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4 TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5 TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"I"); //6 (descriptor) TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile); byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForGetStatic(1, constantPool); String pCode = ReferenceMethods.getPcodeForGetStatic(1, constantPool);
StringBuilder expected = new StringBuilder(); 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); PcodeTextEmitter.emitPushCat1Value(expected, ReferenceMethods.VALUE);
assertTrue(pCode.equals(expected.toString())); assertTrue(pCode.equals(expected.toString()));
} }
@Test @Test
@ -64,23 +64,27 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendMagic(classFile); TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile); TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7); 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.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3 TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4 TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5 TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"J"); //6 (descriptor) TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile); byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForGetStatic(1, constantPool); String pCode = ReferenceMethods.getPcodeForGetStatic(1, constantPool);
StringBuilder expected = new StringBuilder(); 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); PcodeTextEmitter.emitPushCat2Value(expected, ReferenceMethods.VALUE);
assertEquals(pCode,expected.toString()); assertEquals(pCode, expected.toString());
} }
@Test @Test
@ -89,22 +93,25 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendMagic(classFile); TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile); TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7); 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.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3 TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4 TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5 TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"I"); //6 (descriptor) TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile); byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForPutStatic(1, constantPool); String pCode = ReferenceMethods.getPcodeForPutStatic(1, constantPool);
StringBuilder expected = new StringBuilder(); StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET,
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 4, ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE); 4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC);
assertEquals(pCode,expected.toString()); PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 4,
ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE);
assertEquals(pCode, expected.toString());
} }
@Test @Test
@ -113,23 +120,25 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendMagic(classFile); TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile); TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7); 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.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3 TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4 TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5 TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"J"); //6 (descriptor) TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile); byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForPutStatic(1, constantPool); String pCode = ReferenceMethods.getPcodeForPutStatic(1, constantPool);
StringBuilder expected = new StringBuilder(); StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat2Value(expected, ReferenceMethods.NEW_VALUE); PcodeTextEmitter.emitPopCat2Value(expected, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET,
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 8, ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE); 4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC);
assertEquals(pCode,expected.toString()); PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 8,
ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE);
assertEquals(pCode, expected.toString());
} }
@ -139,22 +148,27 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendMagic(classFile); TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile); TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7); 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.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3 TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4 TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5 TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"I"); //6 (descriptor) TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile); byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForGetField(1, constantPool); String pCode = ReferenceMethods.getPcodeForGetField(1, constantPool);
StringBuilder expected = new StringBuilder(); StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF); 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); PcodeTextEmitter.emitPushCat1Value(expected, ReferenceMethods.VALUE);
assertEquals(pCode,expected.toString()); assertEquals(pCode, expected.toString());
} }
@ -164,22 +178,27 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendMagic(classFile); TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile); TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7); 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.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3 TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4 TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5 TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"J"); //6 (descriptor) TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile); byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForGetField(1, constantPool); String pCode = ReferenceMethods.getPcodeForGetField(1, constantPool);
StringBuilder expected = new StringBuilder(); StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF); 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); PcodeTextEmitter.emitPushCat2Value(expected, ReferenceMethods.VALUE);
assertEquals(pCode,expected.toString()); assertEquals(pCode, expected.toString());
} }
@ -189,24 +208,28 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendMagic(classFile); TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile); TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7); 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.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3 TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4 TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5 TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"I"); //6 (descriptor) TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile); byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForPutField(1, constantPool); String pCode = ReferenceMethods.getPcodeForPutField(1, constantPool);
StringBuilder expected = new StringBuilder(); StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF); PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1", ConstantPoolJava.CPOOL_PUTFIELD); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET,
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 4, ReferenceMethods.FIELD_OFFSET, ReferenceMethods.NEW_VALUE); 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()); assertEquals(pCode, expected.toString());
} }
@ -216,28 +239,29 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendMagic(classFile); TestClassFileCreator.appendMagic(classFile);
TestClassFileCreator.appendVersions(classFile); TestClassFileCreator.appendVersions(classFile);
TestClassFileCreator.appendCount(classFile, (short) 7); 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.appendClass(classFile, (short) 4); //2
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3 TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
TestClassFileCreator.appendUtf8(classFile, "className"); //4 TestClassFileCreator.appendUtf8(classFile, "className"); //4
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5 TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
TestClassFileCreator.appendUtf8(classFile,"J"); //6 (descriptor) TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile); byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForPutField(1, constantPool); String pCode = ReferenceMethods.getPcodeForPutField(1, constantPool);
StringBuilder expected = new StringBuilder(); StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat2Value(expected, ReferenceMethods.NEW_VALUE); PcodeTextEmitter.emitPopCat2Value(expected, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF); PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1", ConstantPoolJava.CPOOL_PUTFIELD); PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET,
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 8, ReferenceMethods.FIELD_OFFSET, ReferenceMethods.NEW_VALUE); 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()); assertEquals(pCode, expected.toString());
} }
} }

View file

@ -15,8 +15,7 @@
*/ */
package ghidra.javaclass.test; package ghidra.javaclass.test;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -437,4 +436,78 @@ public class DescriptorDecoderTest extends AbstractGenericTest {
assertEquals("Integer[][][]", typeNames.get(3)); 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));
}
}