mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-18 00:20:10 +00:00
GT_2757 fixed java stream decompile bug
This commit is contained in:
parent
96cb3f4d37
commit
e3ae5a0370
@ -26,15 +26,15 @@ import ghidra.util.xml.SpecXmlUtils;
|
||||
*
|
||||
*/
|
||||
public abstract class ConstantPool {
|
||||
public static final int PRIMITIVE = 0; // Constant -value- of datatype -type-
|
||||
public static final int STRING_LITERAL = 1; // Constant reference to string in -token-
|
||||
public static final int CLASS_REFERENCE = 2; // Reference to (system level) class object
|
||||
public static final int POINTER_METHOD = 3; // Pointer to a method, name in -token-, signature in -type-
|
||||
public static final int POINTER_FIELD = 4; // Pointer to a field, name in -token-, datatype in -type-
|
||||
public static final int ARRAY_LENGTH = 5; // Integer length, -token- is language specific indicator, -type- is integral type
|
||||
public static final int INSTANCE_OF = 6; // boolean value, -token- is language specific indicator, -type- is boolean type
|
||||
public static final int CHECK_CAST = 7; // Pointer to object, new name in -token-, new datatype in -type-
|
||||
|
||||
public static final int PRIMITIVE = 0; // Constant -value- of datatype -type-
|
||||
public static final int STRING_LITERAL = 1; // Constant reference to string in -token-
|
||||
public static final int CLASS_REFERENCE = 2; // Reference to (system level) class object
|
||||
public static final int POINTER_METHOD = 3; // Pointer to a method, name in -token-, signature in -type-
|
||||
public static final int POINTER_FIELD = 4; // Pointer to a field, name in -token-, datatype in -type-
|
||||
public static final int ARRAY_LENGTH = 5; // Integer length, -token- is language specific indicator, -type- is integral type
|
||||
public static final int INSTANCE_OF = 6; // boolean value, -token- is language specific indicator, -type- is boolean type
|
||||
public static final int CHECK_CAST = 7; // Pointer to object, new name in -token-, new datatype in -type-
|
||||
|
||||
public static class Record {
|
||||
public int tag; // The type of the record
|
||||
public String token; // Name or token associated with object
|
||||
@ -43,31 +43,41 @@ public abstract class ConstantPool {
|
||||
public DataType type;
|
||||
public boolean hasThisPtr = false;
|
||||
public boolean isConstructor = false;
|
||||
|
||||
public StringBuilder build(long ref,PcodeDataTypeManager dtmanage) {
|
||||
|
||||
public StringBuilder build(long ref, PcodeDataTypeManager dtmanage) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("<cpoolrec");
|
||||
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "ref", ref);
|
||||
if (tag == STRING_LITERAL)
|
||||
if (tag == STRING_LITERAL) {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "string");
|
||||
else if (tag == CLASS_REFERENCE)
|
||||
}
|
||||
else if (tag == CLASS_REFERENCE) {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "classref");
|
||||
else if (tag == POINTER_METHOD)
|
||||
}
|
||||
else if (tag == POINTER_METHOD) {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "method");
|
||||
else if (tag == POINTER_FIELD)
|
||||
}
|
||||
else if (tag == POINTER_FIELD) {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "field");
|
||||
else if (tag == ARRAY_LENGTH)
|
||||
}
|
||||
else if (tag == ARRAY_LENGTH) {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "arraylength");
|
||||
else if (tag == INSTANCE_OF)
|
||||
}
|
||||
else if (tag == INSTANCE_OF) {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "instanceof");
|
||||
else if (tag == CHECK_CAST)
|
||||
}
|
||||
else if (tag == CHECK_CAST) {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "checkcast");
|
||||
else
|
||||
}
|
||||
else {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "primitive");
|
||||
if (hasThisPtr)
|
||||
}
|
||||
if (hasThisPtr) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(buf, "hasthis", true);
|
||||
if (isConstructor)
|
||||
}
|
||||
if (isConstructor) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(buf, "constructor", true);
|
||||
}
|
||||
buf.append(">\n");
|
||||
if (tag == PRIMITIVE) {
|
||||
buf.append("<value>");
|
||||
|
@ -99,15 +99,7 @@
|
||||
<input name="cpool_index_ldc2_w"/>
|
||||
</pcode>
|
||||
</callotherfixup>
|
||||
|
||||
<callotherfixup targetop="lookupswitchCallOther">
|
||||
<pcode dynamic="true">
|
||||
<input name="default"/>
|
||||
<input name="numPairs"/>
|
||||
<input name ="padding"/>
|
||||
</pcode>
|
||||
</callotherfixup>
|
||||
|
||||
|
||||
<callotherfixup targetop="multianewarrayCallOther">
|
||||
<pcode dynamic="true">
|
||||
<input name="cpool_index_multianewarray"/>
|
||||
|
@ -66,7 +66,6 @@ define pcodeop invokeinterfaceCallOther;
|
||||
define pcodeop invokespecialCallOther;
|
||||
define pcodeop invokestaticCallOther;
|
||||
define pcodeop invokevirtualCallOther;
|
||||
define pcodeop lookupswitchCallOther;
|
||||
define pcodeop multianewarrayCallOther;
|
||||
define pcodeop putStaticCallOther;
|
||||
define pcodeop putFieldCallOther;
|
||||
@ -418,8 +417,8 @@ Default:"default" addr is defaultbyte1; defaultbyte2; defaultbyte3; defaultbyte4
|
||||
|
||||
:checkcast index is (in_table_switch=0 & in_lookup_switch=0 & op=0xc0); indexbyte1; indexbyte2 [ index = indexbyte1<<8 | indexbyte2; ]
|
||||
{
|
||||
_object: $(SIZE) = *:$(SIZE) SP;
|
||||
throwExceptionOp(_object);
|
||||
#_object: $(SIZE) = *:$(SIZE) SP;
|
||||
#throwExceptionOp(_object);
|
||||
|
||||
#_res:1 = cpool(_object,index,$(CPOOL_CHECKCAST));
|
||||
#throwExceptionOp(_res);
|
||||
@ -428,9 +427,12 @@ Default:"default" addr is defaultbyte1; defaultbyte2; defaultbyte3; defaultbyte4
|
||||
#_ref: $(SIZE) = cpool(0:4,index,$(CPOOL_CHECKCAST));
|
||||
#checkcastOp(_object,_ref);
|
||||
|
||||
#_object:$(SIZE) = 0;
|
||||
#pop(_object);
|
||||
#_res:1 = cpool(_object,index,$(CPOOL_INSTANCEOF));
|
||||
_object:$(SIZE) = 0;
|
||||
pop(_object);
|
||||
_object = cpool(_object,index,$(CPOOL_CHECKCAST));
|
||||
push(_object);
|
||||
|
||||
#_res:1 = cpool(_object,index,$(CPOOL_CHECKCAST));
|
||||
#_result:$(SIZE) = zext(_res);
|
||||
#push(_result);
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import ghidra.javaclass.format.attributes.CodeAttribute;
|
||||
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.PointerDataType;
|
||||
import ghidra.program.model.lang.LanguageCompilerSpecPair;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.listing.Program;
|
||||
@ -43,6 +44,8 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
|
||||
private static final String JAVA_NAME = "Java Class File";
|
||||
private Register alignmentReg;
|
||||
public static final long CODE_OFFSET = 0x10000L;
|
||||
public static final String CONSTANT_POOL = "constantPool";
|
||||
|
||||
@Override
|
||||
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
|
||||
@ -61,22 +64,24 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
return loadSpecs;
|
||||
}
|
||||
|
||||
private boolean checkClass(ByteProvider provider) {
|
||||
private boolean checkClass(ByteProvider provider) throws IOException {
|
||||
BinaryReader reader = new BinaryReader(provider, false);
|
||||
ClassFileJava classFile;
|
||||
int magic = reader.peekNextInt();
|
||||
//if it doesn't begin with the 0xCAFEBABE it's not a class file
|
||||
if (magic != JavaClassConstants.MAGIC) {
|
||||
return false;
|
||||
}
|
||||
//attempt to parse the header, if successful count it as a class file.
|
||||
try {
|
||||
classFile = new ClassFileJava(reader);
|
||||
new ClassFileJava(reader);
|
||||
}
|
||||
catch (IOException e) {
|
||||
return false;
|
||||
} catch (RuntimeException re) {
|
||||
}
|
||||
catch (RuntimeException re) {
|
||||
return false;
|
||||
}
|
||||
int magic = classFile.getMagic();
|
||||
if (magic == 0xCAFEBABE) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -117,7 +122,7 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
throws LockException, MemoryConflictException, AddressOverflowException,
|
||||
CancelledException, DuplicateNameException, IOException {
|
||||
AddressFactory af = program.getAddressFactory();
|
||||
AddressSpace space = af.getAddressSpace("constantPool");
|
||||
AddressSpace space = af.getAddressSpace(CONSTANT_POOL);
|
||||
Memory memory = program.getMemory();
|
||||
alignmentReg = program.getRegister("alignmentPad");
|
||||
|
||||
@ -130,28 +135,27 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
memory.createInitializedBlock("_" + provider.getName() + "_", address,
|
||||
provider.getInputStream(0), provider.length(), monitor, false);
|
||||
|
||||
createMethodLookupMemoryBlock( program, monitor );
|
||||
createMethodLookupMemoryBlock(program, monitor);
|
||||
createMethodMemoryBlocks(program, provider, classFile, monitor);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void createMethodLookupMemoryBlock(Program program, TaskMonitor monitor) {
|
||||
Address address = toAddr( program, JavaClassUtil.LOOKUP_ADDRESS );
|
||||
Address address = toAddr(program, JavaClassUtil.LOOKUP_ADDRESS);
|
||||
MemoryBlock block = null;
|
||||
Memory memory = program.getMemory();
|
||||
try {
|
||||
block = memory.createInitializedBlock( "method_lookup", address, JavaClassUtil.METHOD_INDEX_SIZE, (byte) 0xff, monitor, false );
|
||||
block = memory.createInitializedBlock("method_lookup", address,
|
||||
JavaClassUtil.METHOD_INDEX_SIZE, (byte) 0xff, monitor, false);
|
||||
}
|
||||
catch (LockException | DuplicateNameException | MemoryConflictException
|
||||
| AddressOverflowException | CancelledException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
block.setRead( true );
|
||||
block.setWrite( false );
|
||||
block.setExecute( false );
|
||||
block.setRead(true);
|
||||
block.setWrite(false);
|
||||
block.setExecute(false);
|
||||
|
||||
}
|
||||
|
||||
@ -164,12 +168,11 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
monitor.setProgress(0);
|
||||
monitor.setMaximum(methods.length);
|
||||
|
||||
long codeOffset = 0x10000;
|
||||
Address start = toAddr(program, codeOffset);
|
||||
Address start = toAddr(program, CODE_OFFSET);
|
||||
try {
|
||||
//program.setImageBase(start, true);
|
||||
//for (MethodInfoJava method : methods) {
|
||||
for (int i = 0, max = methods.length; i < max; ++i){
|
||||
for (int i = 0, max = methods.length; i < max; ++i) {
|
||||
MethodInfoJava method = methods[i];
|
||||
monitor.incrementProgress(1);
|
||||
CodeAttribute code = method.getCodeAttribute();
|
||||
@ -180,18 +183,19 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
long offset = code.getCodeOffset();
|
||||
|
||||
Memory memory = program.getMemory();
|
||||
short nameIndex = method.getNameIndex();
|
||||
short descriptorIndex = method.getDescriptorIndex();
|
||||
ConstantPoolUtf8Info methodNameInfo = (ConstantPoolUtf8Info) constantPool[nameIndex];
|
||||
int nameIndex = method.getNameIndex();
|
||||
int descriptorIndex = method.getDescriptorIndex();
|
||||
ConstantPoolUtf8Info methodNameInfo =
|
||||
(ConstantPoolUtf8Info) constantPool[nameIndex];
|
||||
ConstantPoolUtf8Info methodDescriptorInfo =
|
||||
(ConstantPoolUtf8Info) constantPool[descriptorIndex];
|
||||
(ConstantPoolUtf8Info) constantPool[descriptorIndex];
|
||||
String methodName = methodNameInfo.getString() + methodDescriptorInfo.getString();
|
||||
|
||||
MemoryBlock memoryBlock =
|
||||
memory.createInitializedBlock(methodName, start,
|
||||
provider.getInputStream(offset), length, monitor, false);
|
||||
Address methodIndexAddress = JavaClassUtil.toLookupAddress( program, i );
|
||||
program.getMemory( ).setInt( methodIndexAddress, (int) start.getOffset() );
|
||||
MemoryBlock memoryBlock = memory.createInitializedBlock(methodName, start,
|
||||
provider.getInputStream(offset), length, monitor, false);
|
||||
Address methodIndexAddress = JavaClassUtil.toLookupAddress(program, i);
|
||||
program.getMemory().setInt(methodIndexAddress, (int) start.getOffset());
|
||||
program.getListing().createData(methodIndexAddress, PointerDataType.dataType);
|
||||
|
||||
setAlignmentInfo(program,
|
||||
new AddressSet(memoryBlock.getStart(), memoryBlock.getEnd()));
|
||||
@ -200,10 +204,9 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
start = start.add(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
} catch (Exception e1) {
|
||||
}
|
||||
catch (Exception e1) {
|
||||
// TODO Auto-generated catch block
|
||||
e1.printStackTrace();
|
||||
}
|
||||
@ -214,9 +217,8 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
int alignmentValue = 3;
|
||||
while (addressIterator.hasNext()) {
|
||||
Address address = addressIterator.next();
|
||||
SetRegisterCmd cmd =
|
||||
new SetRegisterCmd(alignmentReg, address, address,
|
||||
BigInteger.valueOf(alignmentValue));
|
||||
SetRegisterCmd cmd = new SetRegisterCmd(alignmentReg, address, address,
|
||||
BigInteger.valueOf(alignmentValue));
|
||||
cmd.applyTo(program);
|
||||
if (alignmentValue == 0) {
|
||||
alignmentValue = 3;
|
||||
|
@ -32,24 +32,24 @@ public class ConstantPoolJava extends ConstantPool {
|
||||
private DataTypeManager dtManager = null;
|
||||
|
||||
//the following constants must agree with the definitions in JVM.slaspec
|
||||
public static final String CPOOL_ANEWARRAY = "0";
|
||||
public static final String CPOOL_CHECKCAST = "1";
|
||||
public static final String CPOOL_GETFIELD = "2";
|
||||
public static final String CPOOL_GETSTATIC = "3";
|
||||
public static final String CPOOL_LDC = "4"; //also used for ldc_w
|
||||
public static final String CPOOL_LDC2_W = "5";
|
||||
public static final String CPOOL_INSTANCEOF = "6";
|
||||
public static final String CPOOL_INVOKEDYNAMIC = "7";
|
||||
public static final String CPOOL_ANEWARRAY = "0";
|
||||
public static final String CPOOL_CHECKCAST = "1";
|
||||
public static final String CPOOL_GETFIELD = "2";
|
||||
public static final String CPOOL_GETSTATIC = "3";
|
||||
public static final String CPOOL_LDC = "4"; //also used for ldc_w
|
||||
public static final String CPOOL_LDC2_W = "5";
|
||||
public static final String CPOOL_INSTANCEOF = "6";
|
||||
public static final String CPOOL_INVOKEDYNAMIC = "7";
|
||||
public static final String CPOOL_INVOKEINTERFACE = "8";
|
||||
public static final String CPOOL_INVOKESPECIAL = "9";
|
||||
public static final String CPOOL_INVOKESTATIC = "10";
|
||||
public static final String CPOOL_INVOKEVIRTUAL = "11";
|
||||
public static final String CPOOL_MULTIANEWARRAY = "12";
|
||||
public static final String CPOOL_NEW = "13";
|
||||
public static final String CPOOL_NEWARRAY = "14";
|
||||
public static final String CPOOL_PUTSTATIC = "15";
|
||||
public static final String CPOOL_PUTFIELD = "16";
|
||||
public static final String CPOOL_ARRAYLENGTH = "17";
|
||||
public static final String CPOOL_INVOKESPECIAL = "9";
|
||||
public static final String CPOOL_INVOKESTATIC = "10";
|
||||
public static final String CPOOL_INVOKEVIRTUAL = "11";
|
||||
public static final String CPOOL_MULTIANEWARRAY = "12";
|
||||
public static final String CPOOL_NEW = "13";
|
||||
public static final String CPOOL_NEWARRAY = "14";
|
||||
public static final String CPOOL_PUTSTATIC = "15";
|
||||
public static final String CPOOL_PUTFIELD = "16";
|
||||
public static final String CPOOL_ARRAYLENGTH = "17";
|
||||
|
||||
public ConstantPoolJava(Program program) throws IOException {
|
||||
ClassFileAnalysisState analysisState = ClassFileAnalysisState.getState(program);
|
||||
@ -58,43 +58,68 @@ public class ConstantPoolJava extends ConstantPool {
|
||||
dtManager = program.getDataTypeManager();
|
||||
}
|
||||
|
||||
private void fillinMethod(int name_and_type_index, Record res,JavaInvocationType methodType) {
|
||||
ConstantPoolNameAndTypeInfo methodNameAndType = (ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index];
|
||||
private void fillinMethod(int index, int name_and_type_index, Record res,
|
||||
JavaInvocationType methodType) {
|
||||
ConstantPoolNameAndTypeInfo methodNameAndType =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index];
|
||||
int name_index = methodNameAndType.getNameIndex();
|
||||
res.tag = ConstantPool.POINTER_METHOD;
|
||||
res.token = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
|
||||
|
||||
if (methodType.equals(JavaInvocationType.INVOKE_STATIC)) {
|
||||
AbstractConstantPoolReferenceInfo poolRef =
|
||||
(AbstractConstantPoolReferenceInfo) constantPool[index];
|
||||
ConstantPoolClassInfo classInfo =
|
||||
(ConstantPoolClassInfo) constantPool[poolRef.getClassIndex()];
|
||||
int classNameIndex = classInfo.getNameIndex();
|
||||
String fullyQualifiedName =
|
||||
((ConstantPoolUtf8Info) constantPool[classNameIndex]).getString();
|
||||
String className = getClassName(fullyQualifiedName);
|
||||
res.token =
|
||||
className + "." + ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
}
|
||||
else {
|
||||
res.token = ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
}
|
||||
|
||||
int descriptor_index = methodNameAndType.getDescriptorIndex();
|
||||
ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
|
||||
String descriptor = descriptorInfo.getString();
|
||||
FunctionDefinitionDataType funcDef = new FunctionDefinitionDataType(res.token);
|
||||
res.type = new PointerDataType(funcDef);
|
||||
DataType returnType = DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor, dtManager);
|
||||
|
||||
String uniqueifier = Integer.toHexString(index);
|
||||
FunctionDefinitionDataType funcDef =
|
||||
new FunctionDefinitionDataType(uniqueifier + "_" + res.token);
|
||||
DataType returnType =
|
||||
DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor, dtManager);
|
||||
funcDef.setReturnType(returnType);
|
||||
List<DataType> params = DescriptorDecoder.getDataTypeList(descriptor, dtManager);
|
||||
ParameterDefinitionImpl[] paramDefs;
|
||||
|
||||
//invokestatic and invokedynamic don't have a this pointer on the stack
|
||||
if (methodType.equals(JavaInvocationType.INVOKE_STATIC) || methodType.equals(JavaInvocationType.INVOKE_DYNAMIC)){
|
||||
if (methodType.equals(JavaInvocationType.INVOKE_STATIC) ||
|
||||
methodType.equals(JavaInvocationType.INVOKE_DYNAMIC)) {
|
||||
paramDefs = new ParameterDefinitionImpl[params.size()];
|
||||
for (int i = 0, max = params.size(); i < max; ++i){
|
||||
ParameterDefinitionImpl currentParam = new ParameterDefinitionImpl("", params.get(i), null);
|
||||
paramDefs[i]= currentParam;
|
||||
for (int i = 0, max = params.size(); i < max; ++i) {
|
||||
ParameterDefinitionImpl currentParam =
|
||||
new ParameterDefinitionImpl("", params.get(i), null);
|
||||
paramDefs[i] = currentParam;
|
||||
}
|
||||
res.hasThisPtr = false;
|
||||
}
|
||||
//invokeinterface, invokespecial, and invokevirtual do have a this pointer
|
||||
else {
|
||||
paramDefs = new ParameterDefinitionImpl[params.size() + 1];
|
||||
ParameterDefinitionImpl thisParam = new ParameterDefinitionImpl("objectRef", new Pointer32DataType(DataType.VOID), null);
|
||||
ParameterDefinitionImpl thisParam = new ParameterDefinitionImpl("objectRef",
|
||||
new Pointer32DataType(DataType.VOID), null);
|
||||
paramDefs[0] = thisParam;
|
||||
for (int i = 1, max = params.size(); i <= max; ++i){
|
||||
ParameterDefinitionImpl currentParam = new ParameterDefinitionImpl("", params.get(i-1), null);
|
||||
paramDefs[i]= currentParam;
|
||||
for (int i = 1, max = params.size(); i <= max; ++i) {
|
||||
ParameterDefinitionImpl currentParam =
|
||||
new ParameterDefinitionImpl("", params.get(i - 1), null);
|
||||
paramDefs[i] = currentParam;
|
||||
}
|
||||
res.hasThisPtr = true;
|
||||
}
|
||||
|
||||
funcDef.setArguments(paramDefs);
|
||||
res.type = new PointerDataType(funcDef);
|
||||
}
|
||||
|
||||
//ref array does not include the first element passed to the cpool operator.
|
||||
@ -109,38 +134,33 @@ public class ConstantPoolJava extends ConstantPool {
|
||||
* type of the elements of the new array. We use the cpool operator to
|
||||
* look up the string token corresponding to the primitive type.
|
||||
*/
|
||||
if (op.equals(CPOOL_NEWARRAY)){
|
||||
if (op.equals(CPOOL_NEWARRAY)) {
|
||||
res.tag = ConstantPool.POINTER_METHOD;
|
||||
res.token = ArrayMethods.getPrimitiveArrayToken((int)ref[0]);
|
||||
res.token = ArrayMethods.getPrimitiveArrayToken((int) ref[0]);
|
||||
DataType elementType = ArrayMethods.getArrayBaseType((int) ref[0], dtManager);
|
||||
res.type = dtManager.getPointer(elementType);
|
||||
return res;
|
||||
}
|
||||
/*arraylength instruction does not reference the constant pool */
|
||||
if (op.equals(CPOOL_ARRAYLENGTH)){
|
||||
if (op.equals(CPOOL_ARRAYLENGTH)) {
|
||||
res.tag = ConstantPool.ARRAY_LENGTH;
|
||||
res.token = "length";
|
||||
res.type = new PointerDataType(DWordDataType.dataType);
|
||||
res.type = IntegerDataType.dataType;
|
||||
return res;
|
||||
}
|
||||
|
||||
AbstractConstantPoolInfoJava poolRef = constantPool[(int)ref[0]];
|
||||
short name_and_type_index;
|
||||
ConstantPoolNameAndTypeInfo fieldNameAndType;
|
||||
short descriptor_index;
|
||||
ConstantPoolUtf8Info descriptorInfo;
|
||||
String descriptor;
|
||||
StringBuilder sb = null;
|
||||
String[] parts = null;
|
||||
switch(op){
|
||||
AbstractConstantPoolInfoJava poolRef = constantPool[(int) ref[0]];
|
||||
int name_and_type_index;
|
||||
switch (op) {
|
||||
case CPOOL_ANEWARRAY:
|
||||
case CPOOL_NEW:
|
||||
res.tag = ConstantPool.CLASS_REFERENCE;
|
||||
int name_index = ((ConstantPoolClassInfo)poolRef).getNameIndex();
|
||||
String fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
|
||||
parts = fullyQualifiedName.split("/");
|
||||
res.token = parts[parts.length-1];
|
||||
sb = new StringBuilder();
|
||||
int name_index = ((ConstantPoolClassInfo) poolRef).getNameIndex();
|
||||
String fullyQualifiedName =
|
||||
((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
String[] parts = fullyQualifiedName.split("/");
|
||||
res.token = parts[parts.length - 1];
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String part : parts) {
|
||||
sb.append(CategoryPath.DELIMITER_CHAR);
|
||||
sb.append(part);
|
||||
@ -148,12 +168,13 @@ public class ConstantPoolJava extends ConstantPool {
|
||||
DataTypePath dataPath = new DataTypePath(sb.toString(), res.token);
|
||||
res.type = new PointerDataType(dtManager.getDataType(dataPath));
|
||||
break;
|
||||
//TODO
|
||||
case CPOOL_CHECKCAST:
|
||||
res.tag = ConstantPool.CHECK_CAST;
|
||||
res.token = "checkcast";
|
||||
setTypeNameInfo(poolRef,res);
|
||||
break;
|
||||
setTypeNameInfo(poolRef, res);
|
||||
res.tag = ConstantPool.CHECK_CAST;
|
||||
PointerDataType pointerType = (PointerDataType) res.type;
|
||||
String typeName = pointerType.getDataType().getDisplayName();
|
||||
res.token = "checkcast(" + typeName + ")";
|
||||
break;
|
||||
case CPOOL_INSTANCEOF:
|
||||
res.tag = ConstantPool.INSTANCE_OF;
|
||||
res.token = "instanceof";
|
||||
@ -161,154 +182,159 @@ public class ConstantPoolJava extends ConstantPool {
|
||||
break;
|
||||
case CPOOL_GETFIELD:
|
||||
case CPOOL_PUTFIELD:
|
||||
name_and_type_index = ((ConstantPoolFieldReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
fieldNameAndType = (ConstantPoolNameAndTypeInfo)constantPool[name_and_type_index];
|
||||
name_index = fieldNameAndType.getNameIndex();
|
||||
res.tag = ConstantPool.POINTER_FIELD;
|
||||
res.token = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
|
||||
descriptor_index = fieldNameAndType.getDescriptorIndex();
|
||||
descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
|
||||
descriptor = descriptorInfo.getString();
|
||||
DataType type = DescriptorDecoder.getDataTypeOfDescriptor(descriptor, dtManager);
|
||||
res.type = new PointerDataType(type);
|
||||
break;
|
||||
//for references to static fields, we want the class name to be part of the token
|
||||
case CPOOL_GETSTATIC:
|
||||
case CPOOL_PUTSTATIC:
|
||||
name_and_type_index = ((ConstantPoolFieldReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
int class_index = ((ConstantPoolFieldReferenceInfo)poolRef).getClassIndex();
|
||||
fieldNameAndType = (ConstantPoolNameAndTypeInfo)constantPool[name_and_type_index];
|
||||
name_index = fieldNameAndType.getNameIndex();
|
||||
ConstantPoolClassInfo classInfo = (ConstantPoolClassInfo)constantPool[class_index];
|
||||
int classNameIndex = classInfo.getNameIndex();
|
||||
fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[classNameIndex]).getString();
|
||||
res.tag = ConstantPool.POINTER_FIELD;
|
||||
String className = getClassName(fullyQualifiedName);
|
||||
res.token = className + "." + ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
|
||||
descriptor_index = fieldNameAndType.getDescriptorIndex();
|
||||
descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
|
||||
descriptor = descriptorInfo.getString();
|
||||
type = DescriptorDecoder.getDataTypeOfDescriptor(descriptor, dtManager);
|
||||
res.type = new PointerDataType(type);
|
||||
//res.type = type;
|
||||
handlePutAndGetOps(poolRef, res, op);
|
||||
break;
|
||||
case CPOOL_INVOKEDYNAMIC:
|
||||
name_and_type_index = ((ConstantPoolInvokeDynamicInfo)poolRef).getNameAndTypeIndex();
|
||||
fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_DYNAMIC);
|
||||
name_and_type_index =
|
||||
((ConstantPoolInvokeDynamicInfo) poolRef).getNameAndTypeIndex();
|
||||
|
||||
fillinMethod((int) ref[0], name_and_type_index, res,
|
||||
JavaInvocationType.INVOKE_DYNAMIC);
|
||||
break;
|
||||
case CPOOL_INVOKEINTERFACE:
|
||||
name_and_type_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_INTERFACE);
|
||||
name_and_type_index =
|
||||
((ConstantPoolInterfaceMethodReferenceInfo) poolRef).getNameAndTypeIndex();
|
||||
fillinMethod((int) ref[0], name_and_type_index, res,
|
||||
JavaInvocationType.INVOKE_INTERFACE);
|
||||
break;
|
||||
case CPOOL_INVOKESPECIAL:
|
||||
if (poolRef instanceof ConstantPoolMethodReferenceInfo) {
|
||||
name_and_type_index = ((ConstantPoolMethodReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
}
|
||||
else{
|
||||
name_and_type_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
}
|
||||
fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_SPECIAL);
|
||||
|
||||
AbstractConstantPoolReferenceInfo refInfo =
|
||||
(AbstractConstantPoolReferenceInfo) poolRef;
|
||||
name_and_type_index = refInfo.getNameAndTypeIndex();
|
||||
fillinMethod((int) ref[0], name_and_type_index, res,
|
||||
JavaInvocationType.INVOKE_SPECIAL);
|
||||
break;
|
||||
case CPOOL_INVOKESTATIC:
|
||||
if (poolRef instanceof ConstantPoolMethodReferenceInfo) {
|
||||
name_and_type_index = ((ConstantPoolMethodReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
class_index = ((ConstantPoolMethodReferenceInfo)poolRef).getClassIndex();
|
||||
|
||||
}
|
||||
else{
|
||||
name_and_type_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
class_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getClassIndex();
|
||||
}
|
||||
classInfo = (ConstantPoolClassInfo)constantPool[class_index];
|
||||
classNameIndex = classInfo.getNameIndex();
|
||||
fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[classNameIndex]).getString();
|
||||
className = getClassName(fullyQualifiedName);
|
||||
fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_STATIC);
|
||||
res.token = className + "." + res.token;
|
||||
refInfo = (AbstractConstantPoolReferenceInfo) poolRef;
|
||||
name_and_type_index = refInfo.getNameAndTypeIndex();
|
||||
fillinMethod((int) ref[0], name_and_type_index, res,
|
||||
JavaInvocationType.INVOKE_STATIC);
|
||||
break;
|
||||
case CPOOL_INVOKEVIRTUAL:
|
||||
name_and_type_index = ((ConstantPoolMethodReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_VIRTUAL);
|
||||
name_and_type_index =
|
||||
((ConstantPoolMethodReferenceInfo) poolRef).getNameAndTypeIndex();
|
||||
fillinMethod((int) ref[0], name_and_type_index, res,
|
||||
JavaInvocationType.INVOKE_VIRTUAL);
|
||||
break;
|
||||
//in this case, the constant pool entry can be a reference to:
|
||||
//int, float, string literal, or a symbolic reference to a class,
|
||||
//method type, or method handle
|
||||
|
||||
//in this case, the constant pool entry can be a reference to:
|
||||
//int, float, string literal, or a symbolic reference to a class,
|
||||
//method type, or method handle
|
||||
case CPOOL_LDC:
|
||||
if (poolRef instanceof ConstantPoolIntegerInfo) {
|
||||
res.tag = ConstantPool.PRIMITIVE;
|
||||
res.token = "int";
|
||||
res.value = ((ConstantPoolIntegerInfo)poolRef).getValue();
|
||||
res.value = ((ConstantPoolIntegerInfo) poolRef).getValue();
|
||||
res.type = IntegerDataType.dataType;
|
||||
}
|
||||
else if (poolRef instanceof ConstantPoolFloatInfo) {
|
||||
res.tag = ConstantPool.PRIMITIVE;
|
||||
res.token = "float";
|
||||
res.value = ((ConstantPoolFloatInfo)poolRef).getRawBytes() & 0xffffffffL;
|
||||
res.value = ((ConstantPoolFloatInfo) poolRef).getRawBytes() & 0xffffffffL;
|
||||
res.type = FloatDataType.dataType;
|
||||
}
|
||||
else if (poolRef instanceof ConstantPoolStringInfo) {
|
||||
int string_index = ((ConstantPoolStringInfo)poolRef).getStringIndex();
|
||||
int string_index = ((ConstantPoolStringInfo) poolRef).getStringIndex();
|
||||
res.tag = ConstantPool.STRING_LITERAL;
|
||||
res.byteData = ((ConstantPoolUtf8Info) constantPool[string_index]).getBytes();
|
||||
res.type = DescriptorDecoder.getReferenceTypeOfDescriptor("java/lang/String", dtManager, false);
|
||||
res.type = DescriptorDecoder.getReferenceTypeOfDescriptor("java/lang/String",
|
||||
dtManager, false);
|
||||
}
|
||||
else if (poolRef instanceof ConstantPoolClassInfo){
|
||||
else if (poolRef instanceof ConstantPoolClassInfo) {
|
||||
res.tag = ConstantPool.CLASS_REFERENCE;
|
||||
name_index = ((ConstantPoolClassInfo)poolRef).getNameIndex();
|
||||
fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
|
||||
className = getClassName(fullyQualifiedName);
|
||||
res.token = className + ".class";
|
||||
res.type = DescriptorDecoder.getReferenceTypeOfDescriptor(fullyQualifiedName, dtManager, false);
|
||||
name_index = ((ConstantPoolClassInfo) poolRef).getNameIndex();
|
||||
fullyQualifiedName =
|
||||
((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
String className = getClassName(fullyQualifiedName);
|
||||
res.token = className + ".class";
|
||||
res.type = DescriptorDecoder.getReferenceTypeOfDescriptor(fullyQualifiedName,
|
||||
dtManager, false);
|
||||
}
|
||||
//standard java compilers don't seem to emit the following two
|
||||
else if (poolRef instanceof ConstantPoolMethodTypeInfo){
|
||||
else if (poolRef instanceof ConstantPoolMethodTypeInfo) {
|
||||
res.tag = ConstantPool.POINTER_METHOD;
|
||||
name_index = ((ConstantPoolMethodTypeInfo)poolRef).getDescriptorIndex();
|
||||
res.token = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
|
||||
name_index = ((ConstantPoolMethodTypeInfo) poolRef).getDescriptorIndex();
|
||||
res.token = ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
res.type = dtManager.getPointer(DWordDataType.dataType);
|
||||
}
|
||||
//TODO set the token?
|
||||
else if (poolRef instanceof ConstantPoolMethodHandleInfo){
|
||||
else if (poolRef instanceof ConstantPoolMethodHandleInfo) {
|
||||
res.tag = ConstantPool.POINTER_METHOD;
|
||||
res.type = dtManager.getPointer(DWordDataType.dataType);
|
||||
}
|
||||
break;
|
||||
//must be a constant of type long or double
|
||||
//according to JVM spec
|
||||
//must be a constant of type long or double
|
||||
//according to JVM spec
|
||||
case CPOOL_LDC2_W:
|
||||
if (poolRef instanceof ConstantPoolLongInfo) {
|
||||
res.tag = ConstantPool.PRIMITIVE;
|
||||
res.token = "long";
|
||||
res.value = ((ConstantPoolLongInfo)poolRef).getValue();
|
||||
res.value = ((ConstantPoolLongInfo) poolRef).getValue();
|
||||
res.type = LongDataType.dataType;
|
||||
}
|
||||
else {
|
||||
res.tag = ConstantPool.PRIMITIVE;
|
||||
res.token = "double";
|
||||
res.value = ((ConstantPoolDoubleInfo)poolRef).getRawBytes();
|
||||
res.value = ((ConstantPoolDoubleInfo) poolRef).getRawBytes();
|
||||
res.type = DoubleDataType.dataType;
|
||||
}
|
||||
break;
|
||||
case CPOOL_MULTIANEWARRAY:
|
||||
res.tag = ConstantPool.POINTER_METHOD;
|
||||
res.tag = ConstantPool.CLASS_REFERENCE;
|
||||
res.type = new PointerDataType(DataType.VOID);
|
||||
int nameIndex = ((ConstantPoolClassInfo) poolRef).getNameIndex();
|
||||
ConstantPoolUtf8Info utf8Info = (ConstantPoolUtf8Info) constantPool[nameIndex];
|
||||
String classNameWithSemicolon = utf8Info.getString();
|
||||
res.token = DescriptorDecoder.getTypeNameFromDescriptor(classNameWithSemicolon, false, false);
|
||||
res.token = DescriptorDecoder.getTypeNameFromDescriptor(classNameWithSemicolon,
|
||||
false, false);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private void handlePutAndGetOps(AbstractConstantPoolInfoJava poolRef, Record res, String op) {
|
||||
|
||||
int name_and_type_index = ((ConstantPoolFieldReferenceInfo) poolRef).getNameAndTypeIndex();
|
||||
ConstantPoolNameAndTypeInfo fieldNameAndType =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index];
|
||||
int name_index = fieldNameAndType.getNameIndex();
|
||||
switch (op) {
|
||||
case CPOOL_GETFIELD:
|
||||
case CPOOL_PUTFIELD:
|
||||
res.token = ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
break;
|
||||
case CPOOL_GETSTATIC:
|
||||
case CPOOL_PUTSTATIC:
|
||||
int class_index = ((ConstantPoolFieldReferenceInfo) poolRef).getClassIndex();
|
||||
ConstantPoolClassInfo classInfo = (ConstantPoolClassInfo) constantPool[class_index];
|
||||
int classNameIndex = classInfo.getNameIndex();
|
||||
String fullyQualifiedName =
|
||||
((ConstantPoolUtf8Info) constantPool[classNameIndex]).getString();
|
||||
String className = getClassName(fullyQualifiedName);
|
||||
res.token =
|
||||
className + "." + ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid op: " + op);
|
||||
}
|
||||
|
||||
res.tag = ConstantPool.POINTER_FIELD;
|
||||
|
||||
int descriptor_index = fieldNameAndType.getDescriptorIndex();
|
||||
ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
|
||||
String descriptor = descriptorInfo.getString();
|
||||
DataType type = DescriptorDecoder.getDataTypeOfDescriptor(descriptor, dtManager);
|
||||
res.type = new PointerDataType(type);
|
||||
}
|
||||
|
||||
private void setTypeNameInfo(AbstractConstantPoolInfoJava poolRef, Record res) {
|
||||
int name_index = ((ConstantPoolClassInfo)poolRef).getNameIndex();
|
||||
String fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
|
||||
int name_index = ((ConstantPoolClassInfo) poolRef).getNameIndex();
|
||||
String fullyQualifiedName = ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
String[] parts = null;
|
||||
StringBuilder sb = null;
|
||||
if (fullyQualifiedName.startsWith("[")){
|
||||
if (fullyQualifiedName.startsWith("[")) {
|
||||
//TODO: how to get instanceof X to display, where X is an array type?
|
||||
//need to decide how to handle multidimensional arrays
|
||||
//remove the brackets
|
||||
@ -318,7 +344,7 @@ public class ConstantPoolJava extends ConstantPool {
|
||||
for (String part : parts) {
|
||||
sb.append(CategoryPath.DELIMITER_CHAR);
|
||||
sb.append(part);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
parts = fullyQualifiedName.split("/");
|
||||
@ -328,17 +354,17 @@ public class ConstantPoolJava extends ConstantPool {
|
||||
sb.append(part);
|
||||
}
|
||||
}
|
||||
DataTypePath dataPath = new DataTypePath(sb.toString(), parts[parts.length-1]);
|
||||
DataTypePath dataPath = new DataTypePath(sb.toString(), parts[parts.length - 1]);
|
||||
res.type = new PointerDataType(dtManager.getDataType(dataPath));
|
||||
|
||||
|
||||
}
|
||||
|
||||
private String getClassName(String fullyQualifiedName){
|
||||
private String getClassName(String fullyQualifiedName) {
|
||||
int lastSlash = fullyQualifiedName.lastIndexOf("/");
|
||||
return fullyQualifiedName.substring(lastSlash+1, fullyQualifiedName.length());
|
||||
return fullyQualifiedName.substring(lastSlash + 1, fullyQualifiedName.length());
|
||||
}
|
||||
|
||||
public AbstractConstantPoolInfoJava[] getConstantPool(){
|
||||
public AbstractConstantPoolInfoJava[] getConstantPool() {
|
||||
return constantPool;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ public class InjectInvokeDynamic extends InjectPayloadJava {
|
||||
InjectContext injectContext = getInjectContext(program, context);
|
||||
AbstractConstantPoolInfoJava[] constantPool = getConstantPool(program);
|
||||
int constantPoolIndex = (int) injectContext.inputlist.get(0).getOffset();
|
||||
String pcodeText = InvokeMethods.getPcodeForInvoke(constantPoolIndex, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
|
||||
String pcodeText = InvokeMethods.getPcodeForInvokeDynamic(constantPoolIndex, constantPool);
|
||||
return pcodeText;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -38,7 +38,7 @@ public class InvokeMethods {
|
||||
static final String PARAM_SPACE = "parameterSpace";
|
||||
|
||||
//private constructor to enforce noninstantiability
|
||||
private InvokeMethods(){
|
||||
private InvokeMethods() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@ -50,24 +50,28 @@ public class InvokeMethods {
|
||||
* @param type - the JavaInvocationType of the invocation
|
||||
* @return - the pcode as a string
|
||||
*/
|
||||
|
||||
public static String getPcodeForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) {
|
||||
public static String getPcodeForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool,
|
||||
JavaInvocationType type) {
|
||||
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
String descriptor = DescriptorDecoder.getDescriptorForInvoke(offset, constantPool, type);
|
||||
List<JavaComputationalCategory> categories = DescriptorDecoder.getParameterCategories(descriptor);
|
||||
boolean includeThisPointer = type.equals(JavaInvocationType.INVOKE_VIRTUAL) || type.equals(JavaInvocationType.INVOKE_SPECIAL) || type.equals(JavaInvocationType.INVOKE_INTERFACE);
|
||||
|
||||
String descriptor = DescriptorDecoder.getDescriptorForInvoke(offset, constantPool, type);
|
||||
List<JavaComputationalCategory> categories =
|
||||
DescriptorDecoder.getParameterCategories(descriptor);
|
||||
boolean includeThisPointer = type.equals(JavaInvocationType.INVOKE_VIRTUAL) ||
|
||||
type.equals(JavaInvocationType.INVOKE_SPECIAL) ||
|
||||
type.equals(JavaInvocationType.INVOKE_INTERFACE);
|
||||
|
||||
int stackPurge = DescriptorDecoder.getStackPurge(descriptor);
|
||||
if (includeThisPointer){
|
||||
if (includeThisPointer) {
|
||||
stackPurge += 4;
|
||||
}
|
||||
emitPcodeToMoveParams(pCode, categories, includeThisPointer, stackPurge);
|
||||
emitPcodeToResolveMethodReference(pCode, offset, constantPool, type);
|
||||
PcodeTextEmitter.emitIndirectCall(pCode, CALL_TARGET);
|
||||
|
||||
JavaComputationalCategory retType = DescriptorDecoder.getReturnCategoryOfMethodDescriptor(descriptor);
|
||||
switch (retType){
|
||||
|
||||
JavaComputationalCategory retType =
|
||||
DescriptorDecoder.getReturnCategoryOfMethodDescriptor(descriptor);
|
||||
switch (retType) {
|
||||
case CAT_1:
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, CAT_1_RETURN);
|
||||
break;
|
||||
@ -80,6 +84,42 @@ public class InvokeMethods {
|
||||
return pCode.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits the pcode for an invoke instruction.
|
||||
* @param offset - the index of the constant pool element containing a symbolic reference
|
||||
* to a method or a call site specifier.
|
||||
* @param constantPool - the constant pool
|
||||
* @return - the pcode as a string
|
||||
*/
|
||||
public static String getPcodeForInvokeDynamic(int offset,
|
||||
AbstractConstantPoolInfoJava[] constantPool) {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
String invokeDynamicDescriptor = DescriptorDecoder.getDescriptorForInvoke(offset,
|
||||
constantPool, JavaInvocationType.INVOKE_DYNAMIC);
|
||||
List<JavaComputationalCategory> categories =
|
||||
DescriptorDecoder.getParameterCategories(invokeDynamicDescriptor);
|
||||
|
||||
int stackPurge = DescriptorDecoder.getStackPurge(invokeDynamicDescriptor);
|
||||
|
||||
emitPcodeToMoveParams(pCode, categories, false, stackPurge);
|
||||
emitPcodeToResolveMethodReference(pCode, offset, constantPool,
|
||||
JavaInvocationType.INVOKE_DYNAMIC);
|
||||
PcodeTextEmitter.emitIndirectCall(pCode, CALL_TARGET);
|
||||
|
||||
JavaComputationalCategory retType =
|
||||
DescriptorDecoder.getReturnCategoryOfMethodDescriptor(invokeDynamicDescriptor);
|
||||
switch (retType) {
|
||||
case CAT_1:
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, CAT_1_RETURN);
|
||||
break;
|
||||
case CAT_2:
|
||||
PcodeTextEmitter.emitPushCat2Value(pCode, CAT_2_RETURN);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return pCode.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits pcode to move the parameters from the stack to the space parameterSpace
|
||||
@ -89,21 +129,26 @@ public class InvokeMethods {
|
||||
* @param categories - the list of computational categories on the top of the stack
|
||||
* @param includeThisPointer - true if the first element on the stack is an implicit this parameter
|
||||
*/
|
||||
static void emitPcodeToMoveParams(StringBuilder pCode, List<JavaComputationalCategory> categories, boolean includeThisPointer, int totalSize){
|
||||
|
||||
static void emitPcodeToMoveParams(StringBuilder pCode,
|
||||
List<JavaComputationalCategory> categories, boolean includeThisPointer, int totalSize) {
|
||||
|
||||
//pop the parameters off of the stack
|
||||
for (int i = categories.size() - 1; i >= 0; --i){
|
||||
switch (categories.get(i)){
|
||||
for (int i = categories.size() - 1; i >= 0; --i) {
|
||||
switch (categories.get(i)) {
|
||||
case CAT_1:
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER + Integer.toString(i));
|
||||
totalSize -= 4;
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize) + ":4", PARAMETER + Integer.toString(i));
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4,
|
||||
Integer.toString(totalSize) + ":4", PARAMETER + Integer.toString(i));
|
||||
break;
|
||||
case CAT_2:
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER + Integer.toString(i));
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize-8) + ":4", PARAMETER + Integer.toString(i));
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4,
|
||||
Integer.toString(totalSize - 8) + ":4", PARAMETER + Integer.toString(i));
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER_PART2 + Integer.toString(i));
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize-4) + ":4", PARAMETER_PART2 + Integer.toString(i));
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4,
|
||||
Integer.toString(totalSize - 4) + ":4",
|
||||
PARAMETER_PART2 + Integer.toString(i));
|
||||
totalSize -= 8;
|
||||
break;
|
||||
default:
|
||||
@ -111,15 +156,15 @@ public class InvokeMethods {
|
||||
}
|
||||
}
|
||||
//pop off the this pointer if there is one
|
||||
if (includeThisPointer){
|
||||
if (includeThisPointer) {
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, THIS);
|
||||
totalSize -= 4;
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize) + ":4", THIS);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4,
|
||||
Integer.toString(totalSize) + ":4", THIS);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Emits pcode to assign the result of a cpool op to the call_target register for an invocation.
|
||||
* @param pCode - the pcode buffer
|
||||
@ -127,25 +172,37 @@ public class InvokeMethods {
|
||||
* @param constantPool - the constant pool
|
||||
* @param type - the type of the invocation
|
||||
*/
|
||||
static void emitPcodeToResolveMethodReference(StringBuilder pCode, int offset, AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type){
|
||||
switch (type){
|
||||
static void emitPcodeToResolveMethodReference(StringBuilder pCode, int offset,
|
||||
AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) {
|
||||
switch (type) {
|
||||
case INVOKE_DYNAMIC:
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
|
||||
ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset),
|
||||
ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
|
||||
break;
|
||||
case INVOKE_INTERFACE:
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKEINTERFACE);
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
|
||||
ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset),
|
||||
ConstantPoolJava.CPOOL_INVOKEINTERFACE);
|
||||
break;
|
||||
case INVOKE_SPECIAL:
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKESPECIAL);
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
|
||||
ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset),
|
||||
ConstantPoolJava.CPOOL_INVOKESPECIAL);
|
||||
break;
|
||||
case INVOKE_STATIC:
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKESTATIC);
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
|
||||
ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset),
|
||||
ConstantPoolJava.CPOOL_INVOKESTATIC);
|
||||
break;
|
||||
case INVOKE_VIRTUAL:
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
|
||||
ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset),
|
||||
ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unimplemented JavaMethodType: " + type.toString());
|
||||
throw new IllegalArgumentException(
|
||||
"Unimplemented JavaMethodType: " + type.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,18 +79,7 @@ import ghidra.program.model.listing.Program;
|
||||
* (Use/add to PcodeTextEmitter.java to actually emit pcode text)
|
||||
* See ConstantPoolJava.java for examples of the use of the CPOOL pcode op.
|
||||
*
|
||||
* TODO:
|
||||
* 1) For the lookupswitch op, the disassembly is correct but the decompilation is not.
|
||||
* There are several possible ways of modeling the instruction in pcode - either using
|
||||
* injection (SwitchMethods.java) or pcode (JVM.slaspec). In all cases, there seems to
|
||||
* be an issue with getting the decompiler to follow pointers to the various switch clauses.
|
||||
* The file LookupSwitchHex.java in the resource directory contains a class file with
|
||||
* 4 methods with switch statements. Currently the first method is modeled using a
|
||||
* pcode loop and the last three are modeled using pcode injection (which is possible because
|
||||
* there are actually 4 separate lookupswitch instructions, the only difference is the amount
|
||||
* of padding bytes).
|
||||
*
|
||||
* possible improvements:
|
||||
* possible improvements:
|
||||
*
|
||||
* 2) incorporate exceptions.
|
||||
* 6) decide how to display the information used in an invokedynamic instruction
|
||||
@ -121,7 +110,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
|
||||
public static final String LDC = "ldcCallOther";
|
||||
public static final String LDC2_W = "ldc2_wCallOther";
|
||||
public static final String LDC_W = "ldc_wCallOther";
|
||||
public static final String LOOKUP_SWITCH = "lookupswitchCallOther";
|
||||
public static final String MULTIANEWARRAY = "multianewarrayCallOther";
|
||||
|
||||
public static final String PUTFIELD = "putFieldCallOther";
|
||||
@ -149,7 +137,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
|
||||
implementedOps.add(LDC);
|
||||
implementedOps.add(LDC2_W);
|
||||
implementedOps.add(LDC_W);
|
||||
implementedOps.add(LOOKUP_SWITCH);
|
||||
implementedOps.add(MULTIANEWARRAY);
|
||||
implementedOps.add(PUTFIELD);
|
||||
implementedOps.add(PUTSTATIC);
|
||||
@ -170,8 +157,9 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
|
||||
@Override
|
||||
protected InjectPayloadSleigh allocateInject(String sourceName, String name, int tp) {
|
||||
InjectPayloadJava payload = null;
|
||||
if (tp != InjectPayload.CALLOTHERFIXUP_TYPE)
|
||||
if (tp != InjectPayload.CALLOTHERFIXUP_TYPE) {
|
||||
return super.allocateInject(sourceName, name, tp);
|
||||
}
|
||||
switch (name) {
|
||||
case GETFIELD:
|
||||
payload = new InjectGetField(sourceName, language);
|
||||
@ -199,9 +187,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
|
||||
case LDC_W:
|
||||
payload = new InjectLdc(sourceName, language);
|
||||
break;
|
||||
case LOOKUP_SWITCH:
|
||||
payload = new InjectLookupSwitch(sourceName, language);
|
||||
break;
|
||||
case MULTIANEWARRAY:
|
||||
payload = new InjectMultiANewArray(sourceName, language);
|
||||
break;
|
||||
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package ghidra.app.util.pcodeInject;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* This is a utility class containing methods to emit pcode for decompile callbacks occurring during analysis of
|
||||
@ -27,22 +26,22 @@ package ghidra.app.util.pcodeInject;
|
||||
*/
|
||||
public class PcodeTextEmitter {
|
||||
|
||||
static final String RAM = "ram";
|
||||
static final String RAM = "ram";
|
||||
|
||||
//private constructor to enforce noninstantiability
|
||||
private PcodeTextEmitter(){
|
||||
private PcodeTextEmitter() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Emits pcode to push a value of computational category 1 onto the stack.
|
||||
* @param pCode - StringBuilder to hold pcode.
|
||||
* @param valueName - name of varnode to push.
|
||||
*/
|
||||
public static void emitPushCat1Value(StringBuilder pCode, String valueName){
|
||||
public static void emitPushCat1Value(StringBuilder pCode, String valueName) {
|
||||
pCode.append("SP = SP - 4;\n*:4 SP = ");
|
||||
pCode.append(valueName);
|
||||
pCode.append(";\n");
|
||||
pCode.append(";\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,10 +49,10 @@ public class PcodeTextEmitter {
|
||||
* @param pCode - StringBuilder to hold pcode.
|
||||
* @param valueName - name of varnode to push.
|
||||
*/
|
||||
public static void emitPushCat2Value(StringBuilder pCode, String valueName){
|
||||
public static void emitPushCat2Value(StringBuilder pCode, String valueName) {
|
||||
pCode.append("SP = SP - 8;\n*:8 SP = ");
|
||||
pCode.append(valueName);
|
||||
pCode.append(";\n");
|
||||
pCode.append(";\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,9 +60,9 @@ public class PcodeTextEmitter {
|
||||
* @param pCode - StringBuilder to hold pcode.
|
||||
* @param destName - name of destination varnode.
|
||||
*/
|
||||
public static void emitPopCat2Value(StringBuilder pCode, String destName){
|
||||
public static void emitPopCat2Value(StringBuilder pCode, String destName) {
|
||||
pCode.append(destName);
|
||||
pCode.append(":8 = *:8 SP;\nSP = SP + 8;\n");
|
||||
pCode.append(":8 = *:8 SP;\nSP = SP + 8;\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,9 +70,9 @@ public class PcodeTextEmitter {
|
||||
* @param pCode - StringBuilder to hold pcode.
|
||||
* @param destName - name of destination varnode.
|
||||
*/
|
||||
public static void emitPopCat1Value(StringBuilder pCode, String destName){
|
||||
public static void emitPopCat1Value(StringBuilder pCode, String destName) {
|
||||
pCode.append(destName);
|
||||
pCode.append(":4 = *:4 SP;\nSP = SP + 4;\n");
|
||||
pCode.append(":4 = *:4 SP;\nSP = SP + 4;\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,56 +82,55 @@ public class PcodeTextEmitter {
|
||||
* @param pcodeop - name of pcodeop
|
||||
* @param args - zero or more arguments for the pcodeop
|
||||
*/
|
||||
public static void emitAssignVarnodeFromPcodeOpCall(StringBuilder pCode, String varnodeName, int size, String pcodeop, String... args){
|
||||
public static void emitAssignVarnodeFromPcodeOpCall(StringBuilder pCode, String varnodeName,
|
||||
int size, String pcodeop, String... args) {
|
||||
pCode.append(varnodeName);
|
||||
pCode.append(":");
|
||||
pCode.append(":");
|
||||
pCode.append(Integer.toString(size));
|
||||
pCode.append(" = ");
|
||||
pCode.append(" = ");
|
||||
pCode.append(pcodeop);
|
||||
pCode.append("(");
|
||||
for (int i = 0, numArgs = args.length; i < numArgs; ++i){
|
||||
for (int i = 0, numArgs = args.length; i < numArgs; ++i) {
|
||||
pCode.append(args[i]);
|
||||
if (i < numArgs - 1){
|
||||
if (i < numArgs - 1) {
|
||||
pCode.append(",");
|
||||
}
|
||||
}
|
||||
pCode.append(");\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Emits pcode to call a void black-box pcodeop
|
||||
* @param pCode StringBuilder to hold the pcode
|
||||
* @param pcodeop - name of pcodeop
|
||||
* @param args - zero or more arguments for the pcodeop
|
||||
*/
|
||||
public static void emitVoidPcodeOpCall(StringBuilder pCode, String pcodeop, String... args){
|
||||
public static void emitVoidPcodeOpCall(StringBuilder pCode, String pcodeop, String... args) {
|
||||
pCode.append(pcodeop);
|
||||
pCode.append("(");
|
||||
for (int i = 0, numArgs = args.length; i < numArgs; ++i){
|
||||
for (int i = 0, numArgs = args.length; i < numArgs; ++i) {
|
||||
pCode.append(args[i]);
|
||||
if (i < numArgs - 1){
|
||||
if (i < numArgs - 1) {
|
||||
pCode.append(",");
|
||||
}
|
||||
}
|
||||
pCode.append(");\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appends the pcode to assign an integer constant to a register
|
||||
* @param pCode
|
||||
* @param constantPool
|
||||
* @param index
|
||||
*/
|
||||
public static void emitAssignConstantToRegister(StringBuilder pCode, String register, int constant){
|
||||
public static void emitAssignConstantToRegister(StringBuilder pCode, String register,
|
||||
int constant) {
|
||||
pCode.append(register);
|
||||
pCode.append(" = 0x");
|
||||
pCode.append(Integer.toHexString(constant));
|
||||
pCode.append(";\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Appends the pcode to assign a register to the result of a pcode op call with arguments args
|
||||
* @param pCode
|
||||
@ -140,32 +138,42 @@ public class PcodeTextEmitter {
|
||||
* @param pcodeop
|
||||
* @param args
|
||||
*/
|
||||
public static void emitAssignRegisterFromPcodeOpCall(StringBuilder pCode, String register, String pcodeop, String... args){
|
||||
public static void emitAssignRegisterFromPcodeOpCall(StringBuilder pCode, String register,
|
||||
String pcodeop, String... args) {
|
||||
pCode.append(register);
|
||||
pCode.append(" = ");
|
||||
pCode.append(pcodeop);
|
||||
pCode.append("(");
|
||||
for (int i = 0, numArgs = args.length; i < numArgs; ++i){
|
||||
for (int i = 0, numArgs = args.length; i < numArgs; ++i) {
|
||||
pCode.append(args[i]);
|
||||
if (i < numArgs - 1){
|
||||
if (i < numArgs - 1) {
|
||||
pCode.append(",");
|
||||
}
|
||||
}
|
||||
pCode.append(");\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appends the pcode to emit a label definition.
|
||||
* @param pCode
|
||||
* @param caseName
|
||||
*/
|
||||
public static void emitLabelDefinition(StringBuilder pCode, String caseName){
|
||||
public static void emitLabelDefinition(StringBuilder pCode, String caseName) {
|
||||
pCode.append("<");
|
||||
pCode.append(caseName);
|
||||
pCode.append(">\n");
|
||||
}
|
||||
|
||||
public static void emitWriteToMemory(StringBuilder pCode, String space, int size, String offset, String value){
|
||||
|
||||
/**
|
||||
* Appends the pcode to write to a value at an offset of a memory space
|
||||
* @param pCode buffer to append pcode
|
||||
* @param space name of space
|
||||
* @param size size of write
|
||||
* @param offset offset in space
|
||||
* @param value value to write
|
||||
*/
|
||||
public static void emitWriteToMemory(StringBuilder pCode, String space, int size, String offset,
|
||||
String value) {
|
||||
pCode.append("*[");
|
||||
pCode.append(space);
|
||||
pCode.append("]:");
|
||||
@ -177,19 +185,25 @@ public class PcodeTextEmitter {
|
||||
pCode.append(";\n");
|
||||
}
|
||||
|
||||
public static void emitIndirectCall(StringBuilder pCode, String target){
|
||||
/**
|
||||
* Appends the pcode to emit an indirect call
|
||||
* @param pCode buffer to append to
|
||||
* @param target varnode to call indirectly
|
||||
*/
|
||||
public static void emitIndirectCall(StringBuilder pCode, String target) {
|
||||
pCode.append("call [");
|
||||
pCode.append(target);
|
||||
pCode.append("];\n");
|
||||
}
|
||||
|
||||
public static void emitAddToStackPointer(StringBuilder pCode, int amount){
|
||||
pCode.append("SP = SP + ");
|
||||
pCode.append(Integer.toString(amount));
|
||||
pCode.append(";\n");
|
||||
}
|
||||
|
||||
public static void emitSignExtension(StringBuilder pCode, String dest, int size, String src){
|
||||
|
||||
/**
|
||||
* Appends the pcode to sign-extend the value src into dest
|
||||
* @param pCode buffer to append to
|
||||
* @param dest target varnode
|
||||
* @param size size of target varnode
|
||||
* @param src size of source varnode
|
||||
*/
|
||||
public static void emitSignExtension(StringBuilder pCode, String dest, int size, String src) {
|
||||
pCode.append(dest);
|
||||
pCode.append(":");
|
||||
pCode.append(Integer.toString(size));
|
||||
@ -197,8 +211,15 @@ public class PcodeTextEmitter {
|
||||
pCode.append(src);
|
||||
pCode.append(");\n");
|
||||
}
|
||||
|
||||
public static void emitZeroExtension(StringBuilder pCode, String dest, int size, String src){
|
||||
|
||||
/**
|
||||
* Appends the pcode to zero-extend the value src into dest
|
||||
* @param pCode buffer to append to
|
||||
* @param dest target varnode
|
||||
* @param size size of target varnode
|
||||
* @param src size of source varnode
|
||||
*/
|
||||
public static void emitZeroExtension(StringBuilder pCode, String dest, int size, String src) {
|
||||
pCode.append(dest);
|
||||
pCode.append(":");
|
||||
pCode.append(Integer.toString(size));
|
||||
@ -206,8 +227,15 @@ public class PcodeTextEmitter {
|
||||
pCode.append(src);
|
||||
pCode.append(");\n");
|
||||
}
|
||||
|
||||
public static void emitTruncate(StringBuilder pCode, String dest, int size, String src){
|
||||
|
||||
/**
|
||||
* Appends the pcode truncate src into dest
|
||||
* @param pCode buffer to append to
|
||||
* @param dest target varnode
|
||||
* @param size size of target varnode
|
||||
* @param src size of source varnode
|
||||
*/
|
||||
public static void emitTruncate(StringBuilder pCode, String dest, int size, String src) {
|
||||
pCode.append(dest);
|
||||
pCode.append(" = ");
|
||||
pCode.append(src);
|
||||
@ -215,6 +243,25 @@ public class PcodeTextEmitter {
|
||||
pCode.append(Integer.toString(size));
|
||||
pCode.append(";\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Appends the pcode to assign a varnode from a dereference of another varnode
|
||||
* @param pCode buffer to append to
|
||||
* @param lhs target varnode
|
||||
* @param size size of pointed-to value
|
||||
* @param rhs varnode to dereference
|
||||
*/
|
||||
public static void emitAssignVarnodeFromDereference(StringBuilder pCode, String lhs, int size,
|
||||
String rhs) {
|
||||
pCode.append(lhs);
|
||||
pCode.append(":");
|
||||
pCode.append(Integer.toString(size));
|
||||
pCode.append(" = ");
|
||||
pCode.append("*:");
|
||||
pCode.append(Integer.toString(size));
|
||||
pCode.append(" ");
|
||||
pCode.append(rhs);
|
||||
pCode.append(";\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,10 +16,7 @@
|
||||
package ghidra.app.util.pcodeInject;
|
||||
|
||||
import ghidra.javaclass.format.DescriptorDecoder;
|
||||
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolFieldReferenceInfo;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolNameAndTypeInfo;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
|
||||
import ghidra.javaclass.format.constantpool.*;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -37,14 +34,15 @@ import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
|
||||
public class ReferenceMethods {
|
||||
|
||||
static final String VALUE = "value";
|
||||
static final String TEMP = "temp";
|
||||
static final String TEMP_1 = "temp_1";
|
||||
static final String TEMP_2 = "temp_2";
|
||||
static final String NEW_VALUE = "newValue";
|
||||
static final String OBJECT_REF = "objectRef";
|
||||
static final String FIELD_OFFSET = "fieldOffset";
|
||||
static final String STATIC_OFFSET = "staticOffset";
|
||||
|
||||
//private constructor to enforce noninstantiability
|
||||
private ReferenceMethods(){
|
||||
private ReferenceMethods() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@ -54,44 +52,63 @@ public class ReferenceMethods {
|
||||
* @param constantPool - the constant pool of the class file
|
||||
* @return - the pcode string
|
||||
*/
|
||||
public static String getPcodeForGetStatic(int index, AbstractConstantPoolInfoJava[] constantPool) {
|
||||
public static String getPcodeForGetStatic(int index,
|
||||
AbstractConstantPoolInfoJava[] constantPool) {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
//determine the computational category and push a value of the correct size onto the operand stack
|
||||
String descriptor = getDescriptorForFieldRef(constantPool, index);
|
||||
|
||||
switch (descriptor.charAt(0)){
|
||||
|
||||
switch (descriptor.charAt(0)) {
|
||||
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_CHAR: //char
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension
|
||||
case DescriptorDecoder.BASE_TYPE_FLOAT: //float
|
||||
case DescriptorDecoder.BASE_TYPE_INT: //int
|
||||
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 4,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 4, TEMP_1);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
|
||||
case DescriptorDecoder.BASE_TYPE_LONG: //long
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 8, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitPushCat2Value(pCode,VALUE);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 8,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 8, TEMP_1);
|
||||
PcodeTextEmitter.emitPushCat2Value(pCode, VALUE);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
|
||||
}
|
||||
@ -104,49 +121,68 @@ public class ReferenceMethods {
|
||||
* @param constantPool - the constant pool of the class file
|
||||
* @return - the pcode string
|
||||
*/
|
||||
public static String getPcodeForPutStatic(int index, AbstractConstantPoolInfoJava[] constantPool){
|
||||
public static String getPcodeForPutStatic(int index,
|
||||
AbstractConstantPoolInfoJava[] constantPool) {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
String descriptor = getDescriptorForFieldRef(constantPool, index);
|
||||
|
||||
switch (descriptor.charAt(0)){
|
||||
|
||||
switch (descriptor.charAt(0)) {
|
||||
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET, TEMP);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET, TEMP);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_CHAR: //char
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET, TEMP);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET, TEMP);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension
|
||||
case DescriptorDecoder.BASE_TYPE_FLOAT: //float
|
||||
case DescriptorDecoder.BASE_TYPE_INT: //int
|
||||
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, STATIC_OFFSET, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, STATIC_OFFSET,
|
||||
NEW_VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
|
||||
case DescriptorDecoder.BASE_TYPE_LONG: //long
|
||||
PcodeTextEmitter.emitPopCat2Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, STATIC_OFFSET, NEW_VALUE);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, STATIC_OFFSET,
|
||||
NEW_VALUE);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
|
||||
}
|
||||
@ -159,50 +195,69 @@ public class ReferenceMethods {
|
||||
* @param constantPool
|
||||
* @return - the pcode string
|
||||
*/
|
||||
public static String getPcodeForGetField(int index, AbstractConstantPoolInfoJava[] constantPool) {
|
||||
public static String getPcodeForGetField(int index,
|
||||
AbstractConstantPoolInfoJava[] constantPool) {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
|
||||
String descriptor = getDescriptorForFieldRef(constantPool, index);
|
||||
|
||||
switch (descriptor.charAt(0)){
|
||||
|
||||
switch (descriptor.charAt(0)) {
|
||||
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_CHAR: //char
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension
|
||||
case DescriptorDecoder.BASE_TYPE_FLOAT: //float
|
||||
case DescriptorDecoder.BASE_TYPE_INT: //int
|
||||
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 4,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 4, TEMP_1);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
|
||||
case DescriptorDecoder.BASE_TYPE_LONG: //long
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 8, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitPushCat2Value(pCode,VALUE);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 8,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 8, TEMP_1);
|
||||
PcodeTextEmitter.emitPushCat2Value(pCode, VALUE);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
|
||||
}
|
||||
@ -215,64 +270,81 @@ public class ReferenceMethods {
|
||||
* @param constantPool - the constant pool
|
||||
* @return - the pcode
|
||||
*/
|
||||
public static String getPcodeForPutField(int index, AbstractConstantPoolInfoJava[] constantPool) {
|
||||
public static String getPcodeForPutField(int index,
|
||||
AbstractConstantPoolInfoJava[] constantPool) {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
|
||||
//determine the computational category and push a value of the correct size onto the operand stack
|
||||
String descriptor = getDescriptorForFieldRef(constantPool, index);
|
||||
|
||||
|
||||
switch (descriptor.charAt(0)){
|
||||
|
||||
switch (descriptor.charAt(0)) {
|
||||
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET, TEMP);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET, TEMP);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_CHAR: //char
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET, TEMP);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET, TEMP);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension
|
||||
case DescriptorDecoder.BASE_TYPE_FLOAT: //float
|
||||
case DescriptorDecoder.BASE_TYPE_INT: //int
|
||||
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, FIELD_OFFSET, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, FIELD_OFFSET,
|
||||
NEW_VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
|
||||
case DescriptorDecoder.BASE_TYPE_LONG: //long
|
||||
PcodeTextEmitter.emitPopCat2Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, FIELD_OFFSET, NEW_VALUE);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, FIELD_OFFSET,
|
||||
NEW_VALUE);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
|
||||
}
|
||||
return pCode.toString();
|
||||
|
||||
|
||||
|
||||
/*JavaComputationalCategory category = DescriptorDecoder.getComputationalCategoryOfDescriptor(descriptor);
|
||||
switch (category){
|
||||
case CAT_1:
|
||||
@ -295,21 +367,21 @@ public class ReferenceMethods {
|
||||
return pCode.toString();*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the descriptor of a field reference in the constant pool
|
||||
* @param constantPool
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
static String getDescriptorForFieldRef(AbstractConstantPoolInfoJava[] constantPool, int index){
|
||||
ConstantPoolFieldReferenceInfo fieldRef = (ConstantPoolFieldReferenceInfo) constantPool[index];
|
||||
static String getDescriptorForFieldRef(AbstractConstantPoolInfoJava[] constantPool, int index) {
|
||||
ConstantPoolFieldReferenceInfo fieldRef =
|
||||
(ConstantPoolFieldReferenceInfo) constantPool[index];
|
||||
int nameAndTypeIndex = fieldRef.getNameAndTypeIndex();
|
||||
ConstantPoolNameAndTypeInfo nameAndTypeInfo = (ConstantPoolNameAndTypeInfo) constantPool[nameAndTypeIndex];
|
||||
ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
|
||||
return descriptorInfo.getString();
|
||||
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[nameAndTypeIndex];
|
||||
ConstantPoolUtf8Info descriptorInfo =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
|
||||
return descriptorInfo.getString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -17,15 +17,22 @@ package ghidra.javaclass.analyzers;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.cmd.comments.SetCommentCmd;
|
||||
import ghidra.app.cmd.disassemble.DisassembleCommand;
|
||||
import ghidra.app.cmd.label.AddLabelCmd;
|
||||
import ghidra.app.cmd.refs.AssociateSymbolCmd;
|
||||
import ghidra.app.plugin.core.analysis.AnalysisWorker;
|
||||
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
||||
import ghidra.app.services.AnalysisPriority;
|
||||
import ghidra.app.services.AnalyzerType;
|
||||
import ghidra.app.util.bin.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.app.util.opinion.JavaLoader;
|
||||
import ghidra.framework.cmd.CompoundCmd;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.javaclass.flags.MethodsInfoAccessFlags;
|
||||
import ghidra.javaclass.format.*;
|
||||
import ghidra.javaclass.format.attributes.*;
|
||||
import ghidra.javaclass.format.constantpool.*;
|
||||
@ -37,10 +44,9 @@ import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.listing.Function.FunctionUpdateType;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker {
|
||||
@ -108,7 +114,7 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
|
||||
TaskMonitor monitor) throws Exception {
|
||||
|
||||
Address address =
|
||||
program.getAddressFactory().getAddressSpace("constantPool").getMinAddress();
|
||||
program.getAddressFactory().getAddressSpace(JavaLoader.CONSTANT_POOL).getMinAddress();
|
||||
|
||||
ByteProvider provider = new MemoryByteProvider(program.getMemory(), address);
|
||||
BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian());
|
||||
@ -130,7 +136,7 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
|
||||
markupFields(program, classFile, monitor);
|
||||
markupMethods(program, classFile, monitor);
|
||||
disassembleMethods(program, classFile, monitor);
|
||||
labelOperands(program, classFile);
|
||||
processInstructions(program, constantPoolData, classFile, monitor);
|
||||
recordJavaVersionInfo(program, classFile);
|
||||
BasicCompilerSpec.enableJavaLanguageDecompilation(program);
|
||||
return true;
|
||||
@ -157,10 +163,10 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
|
||||
|
||||
/**
|
||||
* Create datatypes for all classes mentioned in the constant pool
|
||||
* @param program
|
||||
* @param classFile
|
||||
* @param monitor
|
||||
* @param messageLog
|
||||
* @param program program file
|
||||
* @param classFile ClassFileJava associated with {@code program}
|
||||
* @param monitor for canceling analysis
|
||||
* @param messageLog for logging messages
|
||||
*/
|
||||
private void createProgramDataTypes(Program program, ClassFileJava classFile,
|
||||
TaskMonitor monitor, MessageLog messageLog) {
|
||||
@ -264,7 +270,19 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
|
||||
javaVersion = "1.8";
|
||||
break;
|
||||
case 53:
|
||||
javaVersion = "1.9";
|
||||
javaVersion = "9";
|
||||
break;
|
||||
case 54:
|
||||
javaVersion = "10";
|
||||
break;
|
||||
case 55:
|
||||
javaVersion = "11";
|
||||
break;
|
||||
case 56:
|
||||
javaVersion = "12";
|
||||
break;
|
||||
case 57:
|
||||
javaVersion = "13";
|
||||
break;
|
||||
default:
|
||||
javaVersion = "Unknown";
|
||||
@ -294,7 +312,7 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
|
||||
AbstractConstantPoolInfoJava[] constantPool, Map<Integer, Integer> indexMap) {
|
||||
AbstractAttributeInfo[] attributes = classFile.getAttributes();
|
||||
for (AbstractAttributeInfo attribute : attributes) {
|
||||
short nameIndex = attribute.getAttributeNameIndex();
|
||||
int nameIndex = attribute.getAttributeNameIndex();
|
||||
AbstractConstantPoolInfoJava poolEntry = classFile.getConstantPool()[nameIndex];
|
||||
if (poolEntry instanceof ConstantPoolUtf8Info) {
|
||||
String name = ((ConstantPoolUtf8Info) poolEntry).getString();
|
||||
@ -388,24 +406,179 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
|
||||
return indexMap;
|
||||
}
|
||||
|
||||
private void labelOperands(Program program, ClassFileJava classFile) {
|
||||
InstructionIterator instructionIt =
|
||||
program.getListing().getInstructions(toAddr(program, 0x10000), true);
|
||||
while (instructionIt.hasNext()) {
|
||||
Instruction instruction = instructionIt.next();
|
||||
private void processInstructions(Program program, Data constantPoolData,
|
||||
ClassFileJava classFile, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
Scalar opValue = instruction.getScalar(0);
|
||||
if (opValue == null) {
|
||||
InstructionIterator instructionIt =
|
||||
program.getListing().getInstructions(toAddr(program, JavaLoader.CODE_OFFSET), true);
|
||||
AbstractConstantPoolInfoJava[] constantPool = classFile.getConstantPool();
|
||||
Map<Integer, Integer> indexMap = getIndexMap(constantPool);
|
||||
BootstrapMethods[] bootstrapMethods =
|
||||
getBootStrapMethodAttribute(classFile, constantPool, indexMap);
|
||||
|
||||
for (Instruction instruction : instructionIt) {
|
||||
monitor.checkCanceled();
|
||||
|
||||
if (!hasConstantPoolReference(instruction.getMnemonicString())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AbstractConstantPoolInfoJava[] constantPool = classFile.getConstantPool();
|
||||
int index = (int) (opValue.getValue() & 0xFFFFFFFF);
|
||||
String opMarkup = getOperandMarkup(program, constantPool, index);
|
||||
instruction.setComment(CodeUnit.EOL_COMMENT, opMarkup);
|
||||
if (instruction.getMnemonicString().equals("invokedynamic")) {
|
||||
addInvokeDynamicComments(program, constantPool, indexMap, bootstrapMethods,
|
||||
instruction);
|
||||
}
|
||||
|
||||
int index = (int) (instruction.getScalar(0).getValue() & 0xFFFFFFFF);
|
||||
|
||||
Data referredData = constantPoolData.getComponent(indexMap.get(index));
|
||||
instruction.addOperandReference(0, referredData.getAddress(), RefType.DATA,
|
||||
SourceType.ANALYSIS);
|
||||
CompoundCmd cmd = new CompoundCmd("Add constant pool reference");
|
||||
String constantPoolLabel = "CPOOL[" + index + "]";
|
||||
cmd.add(
|
||||
new AddLabelCmd(referredData.getAddress(), constantPoolLabel, SourceType.ANALYSIS));
|
||||
|
||||
Reference ref = instruction.getOperandReferences(0)[0];
|
||||
cmd.add(new AssociateSymbolCmd(ref, constantPoolLabel));
|
||||
cmd.applyTo(program);
|
||||
}
|
||||
}
|
||||
|
||||
private void addInvokeDynamicComments(Program program,
|
||||
AbstractConstantPoolInfoJava[] constantPool, Map<Integer, Integer> indexMap,
|
||||
BootstrapMethods[] bootstrapMethods, Instruction instruction) {
|
||||
StringBuffer sb = new StringBuffer("Bootstrap Method: \n");
|
||||
|
||||
Address addr = instruction.getAddress();
|
||||
int index = (int) (instruction.getScalar(0).getValue() & 0xFFFFFFFF);
|
||||
ConstantPoolInvokeDynamicInfo dynamicInfo =
|
||||
(ConstantPoolInvokeDynamicInfo) constantPool[index];
|
||||
int bootstrapIndex = dynamicInfo.getBootstrapMethodAttrIndex();
|
||||
appendMethodHandleInfo(sb, constantPool,
|
||||
bootstrapMethods[bootstrapIndex].getBootstrapMethodsReference());
|
||||
|
||||
sb.append("\n");
|
||||
|
||||
int argNum = 0;
|
||||
for (int i = 0; i < bootstrapMethods[bootstrapIndex].getNumberOfBootstrapArguments(); i++) {
|
||||
sb.append(" static arg " + argNum++ + ": ");
|
||||
appendLoadableInfo(sb, constantPool,
|
||||
bootstrapMethods[bootstrapIndex].getBootstrapArgumentsEntry(i));
|
||||
if (argNum < bootstrapMethods[bootstrapIndex].getNumberOfBootstrapArguments()) {
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
program.getListing().setComment(addr, CodeUnit.PLATE_COMMENT, sb.toString());
|
||||
}
|
||||
|
||||
private void appendMethodHandleInfo(StringBuffer sb,
|
||||
AbstractConstantPoolInfoJava[] constantPool, int argIndex) {
|
||||
ConstantPoolMethodHandleInfo methodHandle =
|
||||
(ConstantPoolMethodHandleInfo) constantPool[argIndex];
|
||||
AbstractConstantPoolInfoJava handleRef = constantPool[methodHandle.getReferenceIndex()];
|
||||
|
||||
if (handleRef instanceof ConstantPoolFieldReferenceInfo) {
|
||||
ConstantPoolFieldReferenceInfo fieldRef = (ConstantPoolFieldReferenceInfo) handleRef;
|
||||
ConstantPoolClassInfo classInfo =
|
||||
(ConstantPoolClassInfo) constantPool[fieldRef.getClassIndex()];
|
||||
ConstantPoolUtf8Info utf8 =
|
||||
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
|
||||
sb.append(utf8.getString());
|
||||
sb.append(".");
|
||||
ConstantPoolNameAndTypeInfo ntInfo =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[fieldRef.getNameAndTypeIndex()];
|
||||
utf8 = (ConstantPoolUtf8Info) constantPool[ntInfo.getNameIndex()];
|
||||
sb.append(utf8.getString());
|
||||
}
|
||||
if (handleRef instanceof ConstantPoolMethodReferenceInfo) {
|
||||
ConstantPoolMethodReferenceInfo methodRef = (ConstantPoolMethodReferenceInfo) handleRef;
|
||||
ConstantPoolClassInfo classRef =
|
||||
(ConstantPoolClassInfo) constantPool[methodRef.getClassIndex()];
|
||||
ConstantPoolUtf8Info utf8 =
|
||||
(ConstantPoolUtf8Info) constantPool[classRef.getNameIndex()];
|
||||
sb.append(utf8.getString() + ".");
|
||||
ConstantPoolNameAndTypeInfo nameAndType =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[methodRef.getNameAndTypeIndex()];
|
||||
utf8 = (ConstantPoolUtf8Info) constantPool[nameAndType.getNameIndex()];
|
||||
sb.append(utf8.getString());
|
||||
}
|
||||
if (handleRef instanceof ConstantPoolInterfaceMethodReferenceInfo) {
|
||||
ConstantPoolInterfaceMethodReferenceInfo mrInfo =
|
||||
(ConstantPoolInterfaceMethodReferenceInfo) handleRef;
|
||||
ConstantPoolClassInfo classRef =
|
||||
(ConstantPoolClassInfo) constantPool[mrInfo.getClassIndex()];
|
||||
ConstantPoolUtf8Info utf8 =
|
||||
(ConstantPoolUtf8Info) constantPool[classRef.getNameIndex()];
|
||||
sb.append(utf8.getString() + ".");
|
||||
ConstantPoolNameAndTypeInfo nameAndType =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[mrInfo.getNameAndTypeIndex()];
|
||||
utf8 = (ConstantPoolUtf8Info) constantPool[nameAndType.getNameIndex()];
|
||||
sb.append(utf8.getString());
|
||||
}
|
||||
}
|
||||
|
||||
private void appendLoadableInfo(StringBuffer sb, AbstractConstantPoolInfoJava[] constantPool,
|
||||
int argIndex) {
|
||||
AbstractConstantPoolInfoJava cpoolInfo = constantPool[argIndex];
|
||||
if (cpoolInfo instanceof ConstantPoolIntegerInfo) {
|
||||
ConstantPoolIntegerInfo intInfo = (ConstantPoolIntegerInfo) cpoolInfo;
|
||||
sb.append(intInfo.getValue());
|
||||
return;
|
||||
}
|
||||
if (cpoolInfo instanceof ConstantPoolFloatInfo) {
|
||||
ConstantPoolFloatInfo floatInfo = (ConstantPoolFloatInfo) cpoolInfo;
|
||||
sb.append(floatInfo.getValue());
|
||||
return;
|
||||
}
|
||||
if (cpoolInfo instanceof ConstantPoolLongInfo) {
|
||||
ConstantPoolLongInfo longInfo = (ConstantPoolLongInfo) cpoolInfo;
|
||||
sb.append(longInfo.getValue());
|
||||
return;
|
||||
}
|
||||
if (cpoolInfo instanceof ConstantPoolDoubleInfo) {
|
||||
ConstantPoolDoubleInfo doubleInfo = (ConstantPoolDoubleInfo) cpoolInfo;
|
||||
sb.append(doubleInfo.getValue());
|
||||
return;
|
||||
}
|
||||
if (cpoolInfo instanceof ConstantPoolClassInfo) {
|
||||
ConstantPoolClassInfo classInfo = (ConstantPoolClassInfo) cpoolInfo;
|
||||
ConstantPoolUtf8Info className =
|
||||
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
|
||||
sb.append(className.getString());
|
||||
return;
|
||||
}
|
||||
if (cpoolInfo instanceof ConstantPoolStringInfo) {
|
||||
ConstantPoolStringInfo stringInfo = (ConstantPoolStringInfo) cpoolInfo;
|
||||
ConstantPoolUtf8Info utf8 =
|
||||
(ConstantPoolUtf8Info) constantPool[stringInfo.getStringIndex()];
|
||||
sb.append("\"");
|
||||
sb.append(utf8.getString());
|
||||
sb.append("\"");
|
||||
return;
|
||||
}
|
||||
if (cpoolInfo instanceof ConstantPoolMethodHandleInfo) {
|
||||
appendMethodHandleInfo(sb, constantPool, argIndex);
|
||||
return;
|
||||
}
|
||||
if (cpoolInfo instanceof ConstantPoolMethodTypeInfo) {
|
||||
ConstantPoolMethodTypeInfo mtInfo = (ConstantPoolMethodTypeInfo) cpoolInfo;
|
||||
ConstantPoolUtf8Info descriptor =
|
||||
(ConstantPoolUtf8Info) constantPool[mtInfo.getDescriptorIndex()];
|
||||
sb.append(descriptor.getString());
|
||||
return;
|
||||
}
|
||||
if (cpoolInfo instanceof ConstantPoolDynamicInfo) {
|
||||
ConstantPoolDynamicInfo dynamicInfo = (ConstantPoolDynamicInfo) cpoolInfo;
|
||||
ConstantPoolNameAndTypeInfo ntInfo =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[dynamicInfo.getNameAndTypeIndex()];
|
||||
ConstantPoolUtf8Info name = (ConstantPoolUtf8Info) constantPool[ntInfo.getNameIndex()];
|
||||
sb.append(name.getString());
|
||||
return;
|
||||
}
|
||||
Msg.showWarn(this, null, "Unsupported Constant Pool Type", cpoolInfo.getClass().getName());
|
||||
return;
|
||||
}
|
||||
|
||||
private void markupFields(Program program, ClassFileJava classFile, TaskMonitor monitor) {
|
||||
AbstractConstantPoolInfoJava[] constantPool = classFile.getConstantPool();
|
||||
|
||||
@ -479,290 +652,6 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
|
||||
}
|
||||
}
|
||||
|
||||
private String getOperandMarkup(Program program, AbstractConstantPoolInfoJava[] constantPool,
|
||||
int index) {
|
||||
if (index >= constantPool.length || index < 0) {
|
||||
// TODO: < 0 can happen with if<cond> branches backwards. Goto's should be handled.
|
||||
return "";
|
||||
}
|
||||
AbstractConstantPoolInfoJava constantPoolInfo = constantPool[index];
|
||||
String opMarkup = "";
|
||||
//
|
||||
// if (monitor.isCancelled()) {
|
||||
// break;
|
||||
// }
|
||||
|
||||
if (constantPoolInfo != null) {
|
||||
switch (constantPoolInfo.getTag()) {
|
||||
case ConstantPoolTagsJava.CONSTANT_Class: {
|
||||
ConstantPoolClassInfo info = (ConstantPoolClassInfo) constantPoolInfo;
|
||||
ConstantPoolUtf8Info utf8 =
|
||||
(ConstantPoolUtf8Info) constantPool[info.getNameIndex()];
|
||||
opMarkup = utf8.getString().replaceAll("/", ".");
|
||||
break;
|
||||
}
|
||||
case ConstantPoolTagsJava.CONSTANT_Double: {
|
||||
ConstantPoolDoubleInfo info = (ConstantPoolDoubleInfo) constantPoolInfo;
|
||||
double value = info.getValue();
|
||||
opMarkup = Double.toString(value);
|
||||
break;
|
||||
}
|
||||
case ConstantPoolTagsJava.CONSTANT_Fieldref: {
|
||||
ConstantPoolFieldReferenceInfo info =
|
||||
(ConstantPoolFieldReferenceInfo) constantPoolInfo;
|
||||
|
||||
ConstantPoolClassInfo classInfo =
|
||||
(ConstantPoolClassInfo) constantPool[info.getClassIndex()];
|
||||
|
||||
ConstantPoolUtf8Info className =
|
||||
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
|
||||
|
||||
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[info.getNameAndTypeIndex()];
|
||||
|
||||
ConstantPoolUtf8Info fieldName =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getNameIndex()];
|
||||
ConstantPoolUtf8Info fieldDescriptor =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
|
||||
|
||||
opMarkup = className.getString().replaceAll("/", ".") + "." +
|
||||
fieldName.getString() + " : " + DescriptorDecoder.getTypeNameFromDescriptor(
|
||||
fieldDescriptor.getString(), true, true);
|
||||
break;
|
||||
}
|
||||
case ConstantPoolTagsJava.CONSTANT_Float: {
|
||||
ConstantPoolFloatInfo info = (ConstantPoolFloatInfo) constantPoolInfo;
|
||||
float value = info.getValue();
|
||||
opMarkup = Float.toString(value);
|
||||
break;
|
||||
}
|
||||
case ConstantPoolTagsJava.CONSTANT_Integer: {
|
||||
ConstantPoolIntegerInfo info = (ConstantPoolIntegerInfo) constantPoolInfo;
|
||||
int value = info.getValue();
|
||||
opMarkup = Integer.toString(value);
|
||||
break;
|
||||
}
|
||||
case ConstantPoolTagsJava.CONSTANT_InterfaceMethodref: {
|
||||
ConstantPoolInterfaceMethodReferenceInfo info =
|
||||
(ConstantPoolInterfaceMethodReferenceInfo) constantPoolInfo;
|
||||
|
||||
ConstantPoolClassInfo classInfo =
|
||||
(ConstantPoolClassInfo) constantPool[info.getClassIndex()];
|
||||
|
||||
ConstantPoolUtf8Info className =
|
||||
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
|
||||
|
||||
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[info.getNameAndTypeIndex()];
|
||||
|
||||
ConstantPoolUtf8Info interfaceName =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getNameIndex()];
|
||||
ConstantPoolUtf8Info interfaceDescriptor =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
|
||||
|
||||
String descriptor = interfaceDescriptor.getString();
|
||||
String params = getParameters(descriptor);
|
||||
String returnType =
|
||||
DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor,
|
||||
program.getDataTypeManager()).getName();
|
||||
|
||||
opMarkup = className.getString().replaceAll("/", ".") + "." +
|
||||
interfaceName.getString() + params + " : " + returnType;
|
||||
break;
|
||||
}
|
||||
case ConstantPoolTagsJava.CONSTANT_InvokeDynamic: {
|
||||
ConstantPoolInvokeDynamicInfo info =
|
||||
(ConstantPoolInvokeDynamicInfo) constantPoolInfo;
|
||||
|
||||
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[info.getNameAndTypeIndex()];
|
||||
|
||||
ConstantPoolUtf8Info name =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getNameIndex()];
|
||||
|
||||
opMarkup = name.getString();
|
||||
break;
|
||||
}
|
||||
case ConstantPoolTagsJava.CONSTANT_Long: {
|
||||
ConstantPoolLongInfo info = (ConstantPoolLongInfo) constantPoolInfo;
|
||||
long value = info.getValue();
|
||||
opMarkup = Long.toString(value);
|
||||
break;
|
||||
}
|
||||
case ConstantPoolTagsJava.CONSTANT_MethodHandle: {
|
||||
ConstantPoolMethodHandleInfo info =
|
||||
(ConstantPoolMethodHandleInfo) constantPoolInfo;
|
||||
|
||||
if (info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_getField ||
|
||||
info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_getStatic ||
|
||||
info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_putField ||
|
||||
info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_putStatic) {
|
||||
|
||||
ConstantPoolFieldReferenceInfo field =
|
||||
(ConstantPoolFieldReferenceInfo) constantPool[info.getReferenceIndex()];
|
||||
ConstantPoolClassInfo classInfo =
|
||||
(ConstantPoolClassInfo) constantPool[field.getClassIndex()];
|
||||
ConstantPoolUtf8Info className =
|
||||
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
|
||||
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[field.getNameAndTypeIndex()];
|
||||
ConstantPoolUtf8Info fieldName =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getNameIndex()];
|
||||
|
||||
ConstantPoolUtf8Info fieldInfo =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
|
||||
|
||||
String descriptor = fieldInfo.getString();
|
||||
String params = getParameters(descriptor);
|
||||
String returnType =
|
||||
DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor,
|
||||
program.getDataTypeManager()).getName();
|
||||
|
||||
opMarkup = className.getString().replaceAll("/", ".") + "." +
|
||||
fieldName.getString() + params + " : " + returnType;
|
||||
}
|
||||
else if (info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_invokeVirtual ||
|
||||
info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_invokeStatic ||
|
||||
info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_invokeSpecial ||
|
||||
info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_newInvokeSpecial) {
|
||||
|
||||
ConstantPoolMethodReferenceInfo method =
|
||||
(ConstantPoolMethodReferenceInfo) constantPool[info.getReferenceIndex()];
|
||||
ConstantPoolClassInfo classInfo =
|
||||
(ConstantPoolClassInfo) constantPool[method.getClassIndex()];
|
||||
ConstantPoolUtf8Info className =
|
||||
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
|
||||
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[method.getNameAndTypeIndex()];
|
||||
ConstantPoolUtf8Info methodName =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getNameIndex()];
|
||||
|
||||
ConstantPoolUtf8Info methodInfo =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
|
||||
|
||||
String descriptor = methodInfo.getString();
|
||||
String params = getParameters(descriptor);
|
||||
String returnType =
|
||||
DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor,
|
||||
program.getDataTypeManager()).getName();
|
||||
|
||||
opMarkup = className.getString().replaceAll("/", ".") + "." +
|
||||
methodName.getString() + params + " : " + returnType;
|
||||
}
|
||||
else if (info.getReferenceKind() == MethodHandleBytecodeBehaviors.REF_invokeInterface) {
|
||||
|
||||
ConstantPoolInterfaceMethodReferenceInfo interfaceMethod =
|
||||
(ConstantPoolInterfaceMethodReferenceInfo) constantPool[info.getReferenceIndex()];
|
||||
ConstantPoolClassInfo classInfo =
|
||||
(ConstantPoolClassInfo) constantPool[interfaceMethod.getClassIndex()];
|
||||
ConstantPoolUtf8Info className =
|
||||
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
|
||||
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[interfaceMethod.getNameAndTypeIndex()];
|
||||
ConstantPoolUtf8Info interfaceMethodName =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getNameIndex()];
|
||||
|
||||
ConstantPoolUtf8Info interfaceMethodInfo =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
|
||||
|
||||
String descriptor = interfaceMethodInfo.getString();
|
||||
String params = getParameters(descriptor);
|
||||
String returnType =
|
||||
DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor,
|
||||
program.getDataTypeManager()).getName();
|
||||
|
||||
opMarkup = className.getString().replaceAll("/", ".") + "." +
|
||||
interfaceMethodName.getString() + params + " : " + returnType;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ConstantPoolTagsJava.CONSTANT_Methodref: {
|
||||
ConstantPoolMethodReferenceInfo info =
|
||||
(ConstantPoolMethodReferenceInfo) constantPoolInfo;
|
||||
|
||||
ConstantPoolClassInfo classInfo =
|
||||
(ConstantPoolClassInfo) constantPool[info.getClassIndex()];
|
||||
|
||||
ConstantPoolUtf8Info className =
|
||||
(ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()];
|
||||
|
||||
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[info.getNameAndTypeIndex()];
|
||||
|
||||
ConstantPoolUtf8Info methodName =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getNameIndex()];
|
||||
ConstantPoolUtf8Info methodDescriptor =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
|
||||
|
||||
ConstantPoolUtf8Info methodInfo =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
|
||||
|
||||
String descriptor = methodInfo.getString();
|
||||
String params = getParameters(descriptor);
|
||||
String returnType =
|
||||
DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor,
|
||||
program.getDataTypeManager()).getName();
|
||||
if (methodName.getString().equals("<init>")) {
|
||||
opMarkup = className.getString() + params;
|
||||
}
|
||||
else {
|
||||
opMarkup = className.getString().replaceAll("/", ".") + "." +
|
||||
methodName.getString() + params + " : " + returnType;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ConstantPoolTagsJava.CONSTANT_MethodType: {
|
||||
ConstantPoolMethodTypeInfo info = (ConstantPoolMethodTypeInfo) constantPoolInfo;
|
||||
ConstantPoolUtf8Info methodType =
|
||||
(ConstantPoolUtf8Info) constantPool[info.getDescriptorIndex()];
|
||||
opMarkup = methodType.getString();
|
||||
break;
|
||||
}
|
||||
case ConstantPoolTagsJava.CONSTANT_NameAndType: {
|
||||
ConstantPoolNameAndTypeInfo info =
|
||||
(ConstantPoolNameAndTypeInfo) constantPoolInfo;
|
||||
|
||||
ConstantPoolUtf8Info fieldName =
|
||||
(ConstantPoolUtf8Info) constantPool[info.getNameIndex()];
|
||||
ConstantPoolUtf8Info fieldDescriptor =
|
||||
(ConstantPoolUtf8Info) constantPool[info.getDescriptorIndex()];
|
||||
|
||||
opMarkup = fieldName.getString();
|
||||
break;
|
||||
}
|
||||
case ConstantPoolTagsJava.CONSTANT_String: {
|
||||
ConstantPoolStringInfo info = (ConstantPoolStringInfo) constantPoolInfo;
|
||||
ConstantPoolUtf8Info utf8 =
|
||||
(ConstantPoolUtf8Info) constantPool[info.getStringIndex()];
|
||||
opMarkup = utf8.toString();
|
||||
break;
|
||||
}
|
||||
case ConstantPoolTagsJava.CONSTANT_Utf8: {
|
||||
ConstantPoolUtf8Info utf8 = (ConstantPoolUtf8Info) constantPoolInfo;
|
||||
opMarkup = utf8.getString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return opMarkup;
|
||||
}
|
||||
|
||||
private String getParameters(String descriptor) {
|
||||
List<String> paramTypeNames = DescriptorDecoder.getTypeNameList(descriptor, true, true);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
//don't append the last element of the list, which is the return type
|
||||
for (int i = 0, max = paramTypeNames.size() - 1; i < max; ++i) {
|
||||
sb.append(paramTypeNames.get(i));
|
||||
if (i < max - 1) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWorkerName() {
|
||||
return getName();
|
||||
@ -780,11 +669,11 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
|
||||
* Sets the name, return type, and parameter types of a method using the information in the constant pool.
|
||||
* Also overrides the signatures on all method invocations made within the method body.
|
||||
* @param function - the function (method)
|
||||
* @param methodDescriptor - the name of the memory block containing the function's code. It is assumed that blockName
|
||||
* is the concatenation of the method name and the descriptor
|
||||
* @param constantPool
|
||||
* @throws DuplicateNameException
|
||||
* @throws InvalidInputException
|
||||
* @param methodInfo information about the method from the constant pool
|
||||
* @param classFile class file containing the method
|
||||
* @param dtManager data type manager for program
|
||||
* @throws DuplicateNameException if there are duplicate name issues with function or parameter names
|
||||
* @throws InvalidInputException if a function or parameter name is invalid
|
||||
*/
|
||||
private void setFunctionInfo(Function function, MethodInfoJava methodInfo,
|
||||
ClassFileJava classFile, DataTypeManager dtManager)
|
||||
@ -833,5 +722,60 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker
|
||||
}
|
||||
function.replaceParameters(params, FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true,
|
||||
SourceType.ANALYSIS);
|
||||
|
||||
createAccessFlagComments(function, methodInfo, classFile);
|
||||
|
||||
}
|
||||
|
||||
private void createAccessFlagComments(Function function, MethodInfoJava methodInfo,
|
||||
ClassFileJava classFile) {
|
||||
|
||||
int flags = methodInfo.getAccessFlags();
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
for (MethodsInfoAccessFlags f : MethodsInfoAccessFlags.values()) {
|
||||
if ((flags & f.getValue()) != 0) {
|
||||
sb.append(" " + f.name() + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(sb)) {
|
||||
sb.insert(0, "Flags:\n");
|
||||
}
|
||||
|
||||
sb.append("\n");
|
||||
sb.append(methodInfo.getMethodSignature(classFile));
|
||||
|
||||
Listing listing = function.getProgram().getListing();
|
||||
Address entryPoint = function.getEntryPoint();
|
||||
|
||||
listing.setComment(entryPoint, CodeUnit.PLATE_COMMENT, sb.toString());
|
||||
}
|
||||
|
||||
private boolean hasConstantPoolReference(String mnemonic) {
|
||||
switch (mnemonic) {
|
||||
case ("anewarray"):
|
||||
case ("checkcast"):
|
||||
case ("getfield"):
|
||||
case ("getstatic"):
|
||||
case ("instanceof"):
|
||||
case ("invokedynamic"):
|
||||
case ("invokeinterface"):
|
||||
case ("invokespecial"):
|
||||
case ("invokestatic"):
|
||||
case ("invokevirtual"):
|
||||
case ("multianewarray"):
|
||||
case ("ldc"):
|
||||
case ("ldc_w"):
|
||||
case ("ldc2_w"):
|
||||
case ("new"):
|
||||
case ("putfield"):
|
||||
case ("putstatic"):
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,23 +15,33 @@
|
||||
*/
|
||||
package ghidra.javaclass.flags;
|
||||
|
||||
public final class ClassFileFlags {
|
||||
public enum ClassFileFlags {
|
||||
|
||||
/** Declared public; may be accessed from outside its package. */
|
||||
public final static short ACC_PUBLIC = 0x0001;
|
||||
ACC_PUBLIC(0x0001),
|
||||
/** Declared final; no subclasses allowed. */
|
||||
public final static short ACC_FINAL = 0x0010;
|
||||
ACC_FINAL(0x0010),
|
||||
/** Treat superclass methods specially when invoked by the invokespecial instruction. */
|
||||
public final static short ACC_SUPER = 0x0020;
|
||||
ACC_SUPER(0x0020),
|
||||
/** Is an interface, not a class. */
|
||||
public final static short ACC_INTERFACE = 0x0200;
|
||||
ACC_INTERFACE(0x0200),
|
||||
/** Declared abstract; must not be instantiated. */
|
||||
public final static short ACC_ABSTRACT = 0x0400;
|
||||
ACC_ABSTRACT(0x0400),
|
||||
/** Declared synthetic; not present in the source code. */
|
||||
public final static short ACC_SYNTHETIC = 0x1000;
|
||||
ACC_SYNTHETIC(0x1000),
|
||||
/** Declared as an annotation type. */
|
||||
public final static short ACC_ANNOTATION = 0x2000;
|
||||
ACC_ANNOTATION(0x2000),
|
||||
/** Declared as an enum type. */
|
||||
public final static short ACC_ENUM = 0x4000;
|
||||
ACC_ENUM(0x4000);
|
||||
|
||||
private int value;
|
||||
|
||||
private ClassFileFlags(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,25 +15,33 @@
|
||||
*/
|
||||
package ghidra.javaclass.flags;
|
||||
|
||||
final class FieldInfoAccessFlags {
|
||||
|
||||
public enum FieldInfoAccessFlags {
|
||||
/** Declared public; may be accessed from outside its package. */
|
||||
public final short ACC_PUBLIC = 0x0001;
|
||||
ACC_PUBLIC(0x0001),
|
||||
/** Declared private; usable only within the defining class. */
|
||||
public final short ACC_PRIVATE = 0x0002;
|
||||
ACC_PRIVATE(0x0002),
|
||||
/** Declared protected; may be accessed within subclasses. */
|
||||
public final short ACC_PROTECTED = 0x0004;
|
||||
ACC_PROTECTED(0x0004),
|
||||
/** Declared static. */
|
||||
public final short ACC_STATIC = 0x0008;
|
||||
ACC_STATIC(0x0008),
|
||||
/** Declared final; never directly assigned to after object construction (JLS ?17.5). */
|
||||
public final short ACC_FINAL = 0x0010;
|
||||
ACC_FINAL(0x0010),
|
||||
/** Declared volatile; cannot be cached. */
|
||||
public final short ACC_VOLATILE = 0x0040;
|
||||
ACC_VOLATILE(0x00400),
|
||||
/** Declared transient; not written or read by a persistent object manager. */
|
||||
public final short ACC_TRANSIENT = 0x0080;
|
||||
ACC_TRANSIENT(0x0080),
|
||||
/** Declared synthetic; not present in the source code. */
|
||||
public final short ACC_SYNTHETIC = 0x1000;
|
||||
ACC_SYNTHETIC(0x1000),
|
||||
/** Declared as an element of an enum. */
|
||||
public final short ACC_ENUM = 0x4000;
|
||||
ACC_ENUM(0x4000);
|
||||
|
||||
private int value;
|
||||
|
||||
private FieldInfoAccessFlags(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
@ -15,31 +15,81 @@
|
||||
*/
|
||||
package ghidra.javaclass.flags;
|
||||
|
||||
public final class MethodsInfoAccessFlags {
|
||||
|
||||
public enum MethodsInfoAccessFlags {
|
||||
/** Declared public; may be accessed from outside its package. */
|
||||
public final static short ACC_PUBLIC = 0x0001;
|
||||
ACC_PUBLIC(0x0001),
|
||||
/** Declared private; accessible only within the defining class. */
|
||||
public final static short ACC_PRIVATE = 0x0002;
|
||||
ACC_PRIVATE(0x0002),
|
||||
/** Declared protected; may be accessed within subclasses. */
|
||||
public final static short ACC_PROTECTED = 0x0004;
|
||||
ACC_PROTECTED(0x0004),
|
||||
/** Declared static. */
|
||||
public final static short ACC_STATIC = 0x0008;
|
||||
ACC_STATIC(0x0008),
|
||||
/** Declared final; must not be overridden (5.4.5). */
|
||||
public final static short ACC_FINAL = 0x0010;
|
||||
ACC_FINAL(0x0010),
|
||||
/** Declared synchronized; invocation is wrapped by a monitor use. */
|
||||
public final static short ACC_SYNCHRONIZED = 0x0020;
|
||||
ACC_SYNCHRONIZED(0x0020),
|
||||
/** A bridge method, generated by the compiler. */
|
||||
public final static short ACC_BRIDGE = 0x0040;
|
||||
ACC_BRIDGE(0x0040),
|
||||
/** Declared with variable number of arguments. */
|
||||
public final static short ACC_VARARGS = 0x0080;
|
||||
ACC_VARARGS(0x0080),
|
||||
/** Declared native; implemented in a language other than Java. */
|
||||
public final static short ACC_NATIVE = 0x0100;
|
||||
ACC_NATIVE(0x0100),
|
||||
/** Declared abstract; no implementation is provided. */
|
||||
public final static short ACC_ABSTRACT = 0x0400;
|
||||
ACC_ABSTRACT(0x0400),
|
||||
/** Declared strictfp; floating-point mode is FP-strict. */
|
||||
public final static short ACC_STRICT = 0x0800;
|
||||
ACC_STRICT(0x0800),
|
||||
/** Declared synthetic; not present in the source code. */
|
||||
public final static short ACC_SYNTHETIC = 0x1000;
|
||||
ACC_SYNTHETIC(0x1000);
|
||||
|
||||
private final int value;
|
||||
|
||||
private MethodsInfoAccessFlags(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a text representation for a given set of access flags.
|
||||
* Here are some examples:
|
||||
* <DL>
|
||||
* <DD><CODE>"public static final"</CODE>,</DD>
|
||||
* <DD><CODE>"package private"</CODE>, or</DD>
|
||||
* <DD><CODE>"protected transient"</CODE>.</DD>
|
||||
* </DL>
|
||||
* Note: only access flags that map to Java modifier keywords are returned.
|
||||
* @param access the mask of flags denoting access permission.
|
||||
* @return a text representation of the access flags.
|
||||
*/
|
||||
public static String toString(int access) {
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
if ((access & ACC_PUBLIC.value) == ACC_PUBLIC.value) {
|
||||
stringBuffer.append("public ");
|
||||
}
|
||||
if ((access & ACC_PRIVATE.value) == ACC_PRIVATE.value) {
|
||||
stringBuffer.append("private ");
|
||||
}
|
||||
if ((access & ACC_PROTECTED.value) == ACC_PROTECTED.value) {
|
||||
stringBuffer.append("protected ");
|
||||
}
|
||||
if ((access & ACC_STATIC.value) == ACC_STATIC.value) {
|
||||
stringBuffer.append("static ");
|
||||
}
|
||||
if ((access & ACC_FINAL.value) == ACC_FINAL.value) {
|
||||
stringBuffer.append("final ");
|
||||
}
|
||||
if ((access & ACC_SYNCHRONIZED.value) == ACC_SYNCHRONIZED.value) {
|
||||
stringBuffer.append("synchronized ");
|
||||
}
|
||||
if ((access & ACC_NATIVE.value) == ACC_NATIVE.value) {
|
||||
stringBuffer.append("native ");
|
||||
}
|
||||
if ((access & ACC_ABSTRACT.value) == ACC_ABSTRACT.value) {
|
||||
stringBuffer.append("abstract ");
|
||||
}
|
||||
return stringBuffer.toString().trim();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
@ -15,22 +15,16 @@
|
||||
*/
|
||||
package ghidra.javaclass.format;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.javaclass.format.attributes.AbstractAttributeInfo;
|
||||
import ghidra.javaclass.format.attributes.AttributeFactory;
|
||||
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolDoubleInfo;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolFactory;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolLongInfo;
|
||||
import ghidra.program.model.data.ArrayDataType;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.javaclass.format.constantpool.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -85,9 +79,9 @@ public class ClassFileJava implements StructConverter {
|
||||
minorVersion = reader.readNextShort();
|
||||
majorVersion = reader.readNextShort();
|
||||
constantPoolCount = reader.readNextShort();
|
||||
constantPool = new AbstractConstantPoolInfoJava[constantPoolCount];
|
||||
constantPool = new AbstractConstantPoolInfoJava[getConstantPoolCount()];
|
||||
//NOTE: start at index 1 per JVM specification!!!
|
||||
for (int i = 1; i < constantPoolCount; i++) {
|
||||
for (int i = 1; i < getConstantPoolCount(); i++) {
|
||||
constantPool[i] = ConstantPoolFactory.get(reader);
|
||||
|
||||
//From section 4.4.5 of JVM specification:
|
||||
@ -97,7 +91,7 @@ public class ClassFileJava implements StructConverter {
|
||||
///located at index n+2. The constant_pool index n+1 must be valid but is considered
|
||||
//unusable.
|
||||
if (constantPool[i] instanceof ConstantPoolLongInfo ||
|
||||
constantPool[i] instanceof ConstantPoolDoubleInfo) {
|
||||
constantPool[i] instanceof ConstantPoolDoubleInfo) {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
@ -105,20 +99,20 @@ public class ClassFileJava implements StructConverter {
|
||||
thisClass = reader.readNextShort();
|
||||
superClass = reader.readNextShort();
|
||||
interfacesCount = reader.readNextShort();
|
||||
interfaces = reader.readNextShortArray(interfacesCount);
|
||||
interfaces = reader.readNextShortArray(getInterfacesCount());
|
||||
fieldsCount = reader.readNextShort();
|
||||
fields = new FieldInfoJava[fieldsCount];
|
||||
for (int i = 0; i < fieldsCount; i++) {
|
||||
fields = new FieldInfoJava[getFieldsCount()];
|
||||
for (int i = 0; i < getFieldsCount(); i++) {
|
||||
fields[i] = new FieldInfoJava(reader, this);
|
||||
}
|
||||
methodsCount = reader.readNextShort();
|
||||
methods = new MethodInfoJava[methodsCount];
|
||||
for (int i = 0; i < methodsCount; i++) {
|
||||
methods = new MethodInfoJava[getMethodsCount()];
|
||||
for (int i = 0; i < getMethodsCount(); i++) {
|
||||
methods[i] = new MethodInfoJava(reader, this);
|
||||
}
|
||||
attributesCount = reader.readNextShort();
|
||||
attributes = new AbstractAttributeInfo[attributesCount];
|
||||
for (int i = 0; i < attributesCount; i++) {
|
||||
attributes = new AbstractAttributeInfo[getAttributesCount()];
|
||||
for (int i = 0; i < getAttributesCount(); i++) {
|
||||
attributes[i] = AttributeFactory.get(reader, getConstantPool());
|
||||
}
|
||||
}
|
||||
@ -173,8 +167,8 @@ public class ClassFileJava implements StructConverter {
|
||||
* exception for constants of type long and double noted in ?4.4.5.
|
||||
* @return the number of entries in the constant_pool table plus one
|
||||
*/
|
||||
public short getConstantPoolCount() {
|
||||
return constantPoolCount;
|
||||
public int getConstantPoolCount() {
|
||||
return constantPoolCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -207,8 +201,8 @@ public class ClassFileJava implements StructConverter {
|
||||
* defined by this class file.
|
||||
* @return a valid index into the constant_pool table to a CONSTANT_Class_info
|
||||
*/
|
||||
public short getThisClass() {
|
||||
return thisClass;
|
||||
public int getThisClass() {
|
||||
return thisClass & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -228,8 +222,8 @@ public class ClassFileJava implements StructConverter {
|
||||
* must be a CONSTANT_Class_info structure representing the class Object.
|
||||
* @return a valid index into the constant_pool table to a CONSTANT_Class_info
|
||||
*/
|
||||
public short getSuperClass() {
|
||||
return superClass;
|
||||
public int getSuperClass() {
|
||||
return superClass & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -237,8 +231,8 @@ public class ClassFileJava implements StructConverter {
|
||||
* superinterfaces of this class or interface type.
|
||||
* @return the number of direct superinterfaces of this class
|
||||
*/
|
||||
public short getInterfacesCount() {
|
||||
return interfacesCount;
|
||||
public int getInterfacesCount() {
|
||||
return interfacesCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -248,10 +242,11 @@ public class ClassFileJava implements StructConverter {
|
||||
* CONSTANT_Class_info (?4.4.1) structure representing an interface that is a
|
||||
* direct superinterface of this class or interface type, in the left-to-right order
|
||||
* given in the source for the type.
|
||||
* @return an array of interfaces
|
||||
* @param i entry
|
||||
* @return interface index
|
||||
*/
|
||||
public short[] getInterfaces() {
|
||||
return interfaces;
|
||||
public int getInterfacesEntry(int i) {
|
||||
return interfaces[i] & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -261,8 +256,8 @@ public class ClassFileJava implements StructConverter {
|
||||
* interface type.
|
||||
* @return the number of field_info structures in the fields table
|
||||
*/
|
||||
public short getFieldsCount() {
|
||||
return fieldsCount;
|
||||
public int getFieldsCount() {
|
||||
return fieldsCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -282,8 +277,8 @@ public class ClassFileJava implements StructConverter {
|
||||
* structures in the methods table.
|
||||
* @return the number of method_info structures in the methods table
|
||||
*/
|
||||
public short getMethodsCount() {
|
||||
return methodsCount;
|
||||
public int getMethodsCount() {
|
||||
return methodsCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -309,8 +304,8 @@ public class ClassFileJava implements StructConverter {
|
||||
* in the attributes table of this class.
|
||||
* @return the number of attributes in the attributes table
|
||||
*/
|
||||
public short getAttributesCount() {
|
||||
return attributesCount;
|
||||
public int getAttributesCount() {
|
||||
return attributesCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -370,14 +365,14 @@ public class ClassFileJava implements StructConverter {
|
||||
structure.add(WORD, "super_class", null);
|
||||
structure.add(WORD, "interfaces_count", null);
|
||||
|
||||
if (interfacesCount > 0) {
|
||||
DataType array = new ArrayDataType(WORD, interfacesCount, WORD.getLength());
|
||||
if (getInterfacesCount() > 0) {
|
||||
DataType array = new ArrayDataType(WORD, getInterfacesCount(), WORD.getLength());
|
||||
structure.add(array, "interfaces", null);
|
||||
}
|
||||
|
||||
structure.add(WORD, "field_count", null);
|
||||
|
||||
if (fieldsCount > 0) {
|
||||
if (getFieldsCount() > 0) {
|
||||
Structure fieldStruct = new StructureDataType("fields", 0);
|
||||
for (int i = 0; i < fields.length; ++i) {
|
||||
fieldStruct.add(fields[i].toDataType(), "field_" + i, null);
|
||||
@ -387,7 +382,7 @@ public class ClassFileJava implements StructConverter {
|
||||
|
||||
structure.add(WORD, "method_count", null);
|
||||
|
||||
if (methodsCount > 0) {
|
||||
if (getMethodsCount() > 0) {
|
||||
Structure methodsStruct = new StructureDataType("methods", 0);
|
||||
for (int i = 0; i < methods.length; ++i) {
|
||||
methodsStruct.add(methods[i].toDataType(), "methods_" + i, null);
|
||||
@ -396,7 +391,7 @@ public class ClassFileJava implements StructConverter {
|
||||
}
|
||||
|
||||
structure.add(WORD, "attributes_count", null);
|
||||
if (attributesCount > 0){
|
||||
if (getAttributesCount() > 0) {
|
||||
Structure attributesStruct = new StructureDataType("attributes", 0);
|
||||
for (int i = 0; i < attributes.length; ++i) {
|
||||
attributesStruct.add(attributes[i].toDataType(), "attributes_" + i, null);
|
||||
|
@ -19,12 +19,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.util.pcodeInject.*;
|
||||
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolInterfaceMethodReferenceInfo;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolInvokeDynamicInfo;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolMethodReferenceInfo;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolNameAndTypeInfo;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
|
||||
import ghidra.javaclass.format.constantpool.*;
|
||||
import ghidra.program.model.data.*;
|
||||
|
||||
/**
|
||||
@ -34,7 +29,6 @@ import ghidra.program.model.data.*;
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
public class DescriptorDecoder {
|
||||
|
||||
public final static byte BASE_TYPE_BYTE = 'B';
|
||||
@ -53,9 +47,8 @@ public class DescriptorDecoder {
|
||||
public final static byte BASE_TYPE_ENUM = 'e';
|
||||
public final static byte BASE_TYPE_ANNOTATION = '@';
|
||||
|
||||
|
||||
//private constructor to enforce noninstantiability
|
||||
private DescriptorDecoder(){
|
||||
private DescriptorDecoder() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@ -65,11 +58,11 @@ public class DescriptorDecoder {
|
||||
* @param methodDescriptor
|
||||
* @return
|
||||
*/
|
||||
public static int getStackPurge(String methodDescriptor){
|
||||
public static int getStackPurge(String methodDescriptor) {
|
||||
int stackPurge = 0;
|
||||
List<JavaComputationalCategory> categories = getParameterCategories(methodDescriptor);
|
||||
for (JavaComputationalCategory cat : categories){
|
||||
switch (cat){
|
||||
for (JavaComputationalCategory cat : categories) {
|
||||
switch (cat) {
|
||||
case CAT_1:
|
||||
stackPurge += PcodeInjectLibraryJava.REFERENCE_SIZE;
|
||||
break;
|
||||
@ -83,31 +76,41 @@ public class DescriptorDecoder {
|
||||
return stackPurge;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the computational category of the return type of a method descriptor.
|
||||
* @param methodDescriptor
|
||||
* @return
|
||||
*/
|
||||
public static JavaComputationalCategory getReturnCategoryOfMethodDescriptor(String methodDescriptor){
|
||||
public static JavaComputationalCategory getReturnCategoryOfMethodDescriptor(
|
||||
String methodDescriptor) {
|
||||
int closeParenIndex = methodDescriptor.indexOf(")");
|
||||
if (closeParenIndex == -1){
|
||||
if (closeParenIndex == -1) {
|
||||
throw new IllegalArgumentException("Invalid method descriptor: " + methodDescriptor);
|
||||
}
|
||||
String returnDescriptor = methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
|
||||
String returnDescriptor =
|
||||
methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
|
||||
return DescriptorDecoder.getComputationalCategoryOfDescriptor(returnDescriptor);
|
||||
}
|
||||
|
||||
public static DataType getReturnTypeOfMethodDescriptor(String methodDescriptor, DataTypeManager dtManager){
|
||||
/**
|
||||
* Given a method descriptor, returns the data type of the return value of the corresponding
|
||||
* method
|
||||
* @param methodDescriptor descriptor of method
|
||||
* @param dtManager data type manger for containing program
|
||||
* @return data type of return value of method
|
||||
*/
|
||||
public static DataType getReturnTypeOfMethodDescriptor(String methodDescriptor,
|
||||
DataTypeManager dtManager) {
|
||||
int closeParenIndex = methodDescriptor.indexOf(")");
|
||||
if (closeParenIndex == -1){
|
||||
if (closeParenIndex == -1) {
|
||||
throw new IllegalArgumentException("Invalid method descriptor: " + methodDescriptor);
|
||||
}
|
||||
String returnDescriptor = methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
|
||||
if (returnDescriptor.startsWith("[")){
|
||||
String returnDescriptor =
|
||||
methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
|
||||
if (returnDescriptor.startsWith("[")) {
|
||||
return getPointerType(returnDescriptor, dtManager);
|
||||
}
|
||||
return DescriptorDecoder.getDataTypeOfDescriptor(returnDescriptor, dtManager);
|
||||
return DescriptorDecoder.getDataTypeOfDescriptor(returnDescriptor, dtManager);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,11 +118,12 @@ public class DescriptorDecoder {
|
||||
* @param descriptor
|
||||
* @return
|
||||
*/
|
||||
public static JavaComputationalCategory getComputationalCategoryOfDescriptor(String descriptor){
|
||||
public static JavaComputationalCategory getComputationalCategoryOfDescriptor(
|
||||
String descriptor) {
|
||||
//all references to objects start with "L"
|
||||
//all references to arrays start with "["
|
||||
//all other descriptors are just one letter.
|
||||
switch (descriptor.charAt(0)){
|
||||
switch (descriptor.charAt(0)) {
|
||||
case BASE_TYPE_BYTE: //signed byte
|
||||
case BASE_TYPE_CHAR: //char
|
||||
case BASE_TYPE_FLOAT: //float
|
||||
@ -144,7 +148,8 @@ public class DescriptorDecoder {
|
||||
* @param methodDescriptor
|
||||
* @return
|
||||
*/
|
||||
public static List<String> getTypeNameList(String methodDescriptor, boolean fullyQualifiedName, boolean replaceSlash) {
|
||||
public static List<String> getTypeNameList(String methodDescriptor, boolean fullyQualifiedName,
|
||||
boolean replaceSlash) {
|
||||
ArrayList<String> typeNames = new ArrayList<>();
|
||||
int closeParenIndex = methodDescriptor.indexOf(")");
|
||||
String argString = methodDescriptor.substring(1, closeParenIndex);
|
||||
@ -152,79 +157,85 @@ public class DescriptorDecoder {
|
||||
|
||||
int currentPosition = 0;
|
||||
int len = argString.length();
|
||||
while (currentPosition < len){
|
||||
while (currentPosition < len) {
|
||||
String currentParam = argString.substring(currentPosition, currentPosition + 1);
|
||||
if (currentParam.equals("[")){
|
||||
if (currentParam.equals("[")) {
|
||||
int initialBracket = currentPosition;
|
||||
while (argString.charAt(currentPosition) == '['){
|
||||
while (argString.charAt(currentPosition) == '[') {
|
||||
currentPosition++;
|
||||
}
|
||||
//advance past the base type of the array
|
||||
if (argString.charAt(currentPosition) == 'L'){
|
||||
if (argString.charAt(currentPosition) == 'L') {
|
||||
int semiColonIndex = argString.indexOf(";", currentPosition);
|
||||
currentPosition = semiColonIndex + 1;
|
||||
}
|
||||
else{
|
||||
else {
|
||||
currentPosition++;
|
||||
}
|
||||
currentParamTypeName = getTypeNameFromDescriptor(argString.substring(initialBracket,currentPosition), fullyQualifiedName, replaceSlash);
|
||||
currentParamTypeName =
|
||||
getTypeNameFromDescriptor(argString.substring(initialBracket, currentPosition),
|
||||
fullyQualifiedName, replaceSlash);
|
||||
typeNames.add(currentParamTypeName);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//advance to next type in argString
|
||||
//if it's a reference, it starts with L and ends with a ;
|
||||
//otherwise you only need to advance one character
|
||||
switch(currentParam){
|
||||
switch (currentParam) {
|
||||
case "L":
|
||||
int semiColonIndex = argString.indexOf(";", currentPosition);
|
||||
currentParamTypeName = getTypeNameFromDescriptor(argString.substring(currentPosition,semiColonIndex+1), fullyQualifiedName, replaceSlash);
|
||||
currentParamTypeName = getTypeNameFromDescriptor(
|
||||
argString.substring(currentPosition, semiColonIndex + 1),
|
||||
fullyQualifiedName, replaceSlash);
|
||||
currentPosition = semiColonIndex + 1; //advance past ;
|
||||
break;
|
||||
default:
|
||||
currentParamTypeName = getTypeNameFromDescriptor(currentParam, fullyQualifiedName, replaceSlash);
|
||||
currentPosition++;
|
||||
currentParamTypeName =
|
||||
getTypeNameFromDescriptor(currentParam, fullyQualifiedName, replaceSlash);
|
||||
currentPosition++;
|
||||
}
|
||||
typeNames.add(currentParamTypeName);
|
||||
|
||||
}
|
||||
|
||||
//now add the the name of the return type
|
||||
String returnType = methodDescriptor.substring(closeParenIndex+1, methodDescriptor.length());
|
||||
String returnType =
|
||||
methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
|
||||
typeNames.add(getTypeNameFromDescriptor(returnType, fullyQualifiedName, replaceSlash));
|
||||
return typeNames;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the type name for a parameter descriptor
|
||||
* @param descriptor
|
||||
* @return
|
||||
*/
|
||||
public static String getTypeNameFromDescriptor(String descriptor, boolean fullyQualifiedName, boolean replaceSlash){
|
||||
if (descriptor.startsWith("L")){
|
||||
public static String getTypeNameFromDescriptor(String descriptor, boolean fullyQualifiedName,
|
||||
boolean replaceSlash) {
|
||||
if (descriptor.startsWith("L")) {
|
||||
//leave off the initial L and the final ;
|
||||
String name = descriptor.substring(1, descriptor.length()-1);
|
||||
if (fullyQualifiedName){
|
||||
if (replaceSlash){
|
||||
return name.replace("/", ".");
|
||||
String name = descriptor.substring(1, descriptor.length() - 1);
|
||||
if (fullyQualifiedName) {
|
||||
if (replaceSlash) {
|
||||
return name.replace("/", ".");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
int lastSlash = name.lastIndexOf("/");
|
||||
//lastSlash+1 so the slash is not included in the name
|
||||
return name.substring(lastSlash+1, name.length());
|
||||
return name.substring(lastSlash + 1, name.length());
|
||||
}
|
||||
if (descriptor.startsWith("[")){
|
||||
if (descriptor.startsWith("[")) {
|
||||
int dimension = descriptor.lastIndexOf("[") + 1;
|
||||
String baseType = getTypeNameFromDescriptor(descriptor.replace("[", ""), fullyQualifiedName, replaceSlash);
|
||||
String baseType = getTypeNameFromDescriptor(descriptor.replace("[", ""),
|
||||
fullyQualifiedName, replaceSlash);
|
||||
StringBuilder sb = new StringBuilder(baseType);
|
||||
for (int i = 0; i < dimension; ++i){
|
||||
for (int i = 0; i < dimension; ++i) {
|
||||
sb.append("[]");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
switch (descriptor.charAt(0)){
|
||||
switch (descriptor.charAt(0)) {
|
||||
case BASE_TYPE_BYTE: //signed byte
|
||||
return "byte";
|
||||
case BASE_TYPE_CHAR: //char
|
||||
@ -248,17 +259,18 @@ public class DescriptorDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
public static DataType getReferenceTypeOfDescriptor(String descriptor, DataTypeManager dtManager, boolean includesLandSemi){
|
||||
if (includesLandSemi){
|
||||
descriptor = descriptor.substring(1, descriptor.length()-1);
|
||||
public static DataType getReferenceTypeOfDescriptor(String descriptor,
|
||||
DataTypeManager dtManager, boolean includesLandSemi) {
|
||||
if (includesLandSemi) {
|
||||
descriptor = descriptor.substring(1, descriptor.length() - 1);
|
||||
}
|
||||
String[] parts = descriptor.split("/");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < parts.length; i++){
|
||||
for (String part : parts) {
|
||||
sb.append(CategoryPath.DELIMITER_CHAR);
|
||||
sb.append(parts[i]);
|
||||
sb.append(part);
|
||||
}
|
||||
DataTypePath dataPath = new DataTypePath(sb.toString(), parts[parts.length-1]);
|
||||
DataTypePath dataPath = new DataTypePath(sb.toString(), parts[parts.length - 1]);
|
||||
DataType referencedType = dtManager.getDataType(dataPath);
|
||||
return new PointerDataType(referencedType);
|
||||
}
|
||||
@ -268,44 +280,50 @@ public class DescriptorDecoder {
|
||||
* @param descriptor
|
||||
* @return
|
||||
*/
|
||||
public static DataType getDataTypeOfDescriptor(String descriptor, DataTypeManager dtManager){
|
||||
public static DataType getDataTypeOfDescriptor(String descriptor, DataTypeManager dtManager) {
|
||||
//all references to objects start with "L"
|
||||
//all references to arrays start with "["
|
||||
//all other descriptors are just one letter.
|
||||
if (descriptor.startsWith("[")){
|
||||
if (descriptor.startsWith("[")) {
|
||||
return getPointerType(descriptor, dtManager);
|
||||
}
|
||||
switch (descriptor.charAt(0)){
|
||||
case BASE_TYPE_BYTE:
|
||||
switch (descriptor.charAt(0)) {
|
||||
case BASE_TYPE_BYTE:
|
||||
return SignedByteDataType.dataType;
|
||||
case BASE_TYPE_CHAR:
|
||||
case BASE_TYPE_CHAR:
|
||||
return CharDataType.dataType;
|
||||
case BASE_TYPE_INT:
|
||||
case BASE_TYPE_INT:
|
||||
return IntegerDataType.dataType;
|
||||
case BASE_TYPE_SHORT:
|
||||
return ShortDataType.dataType;
|
||||
case BASE_TYPE_BOOLEAN:
|
||||
case BASE_TYPE_BOOLEAN:
|
||||
return BooleanDataType.dataType;
|
||||
case BASE_TYPE_FLOAT:
|
||||
case BASE_TYPE_FLOAT:
|
||||
return FloatDataType.dataType;
|
||||
case BASE_TYPE_REFERENCE: //object reference
|
||||
return getReferenceTypeOfDescriptor(descriptor, dtManager, true);
|
||||
case BASE_TYPE_DOUBLE:
|
||||
case BASE_TYPE_DOUBLE:
|
||||
return DoubleDataType.dataType;
|
||||
case BASE_TYPE_LONG:
|
||||
case BASE_TYPE_LONG:
|
||||
return LongDataType.dataType;
|
||||
case BASE_TYPE_VOID: //void (only for return types)
|
||||
return DataType.VOID;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid computational category: " + descriptor);
|
||||
throw new IllegalArgumentException("Invalid type descriptor: " + descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
public static DataType getPointerType(String descriptor, DataTypeManager dtManager){
|
||||
/**
|
||||
* Returns the data type of a pointer to the type represented by descriptor
|
||||
* @param descriptor description of base type
|
||||
* @param dtManager data type manager of program
|
||||
* @return pointer data type
|
||||
*/
|
||||
public static DataType getPointerType(String descriptor, DataTypeManager dtManager) {
|
||||
int lastBracket = descriptor.lastIndexOf("[");
|
||||
String baseTypeOfArray = descriptor.substring(lastBracket+1, lastBracket+2);
|
||||
String baseTypeOfArray = descriptor.substring(lastBracket + 1, lastBracket + 2);
|
||||
DataType baseType = null;
|
||||
switch (baseTypeOfArray.charAt(0)){
|
||||
switch (baseTypeOfArray.charAt(0)) {
|
||||
case BASE_TYPE_BYTE:
|
||||
baseType = ArrayMethods.getArrayBaseType(JavaClassConstants.T_BYTE, dtManager);
|
||||
break;
|
||||
@ -334,7 +352,8 @@ public class DescriptorDecoder {
|
||||
return dtManager.getPointer(DWordDataType.dataType);
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid array base type category: " + baseTypeOfArray);
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid array base type category: " + baseTypeOfArray);
|
||||
}
|
||||
return dtManager.getPointer(baseType);
|
||||
}
|
||||
@ -345,17 +364,18 @@ public class DescriptorDecoder {
|
||||
* @param methodDescriptor
|
||||
* @return
|
||||
*/
|
||||
public static List<JavaComputationalCategory> getParameterCategories(String methodDescriptor){
|
||||
public static List<JavaComputationalCategory> getParameterCategories(String methodDescriptor) {
|
||||
ArrayList<JavaComputationalCategory> categories = new ArrayList<>();
|
||||
int closeParenIndex = methodDescriptor.indexOf(")");
|
||||
String argString = methodDescriptor.substring(1, closeParenIndex);
|
||||
int currentPosition = 0;
|
||||
int len = argString.length();
|
||||
while (currentPosition < len){
|
||||
while (currentPosition < len) {
|
||||
String currentParam = argString.substring(currentPosition, currentPosition + 1);
|
||||
JavaComputationalCategory category = DescriptorDecoder.getComputationalCategoryOfDescriptor(currentParam);
|
||||
JavaComputationalCategory category =
|
||||
DescriptorDecoder.getComputationalCategoryOfDescriptor(currentParam);
|
||||
|
||||
switch (category){
|
||||
switch (category) {
|
||||
case CAT_1:
|
||||
categories.add(JavaComputationalCategory.CAT_1);
|
||||
break;
|
||||
@ -370,22 +390,22 @@ public class DescriptorDecoder {
|
||||
//if it's a reference, it starts with L and ends with a ;
|
||||
//if it's an array, it has one "[" for each dimension, then the type (which might be a reference)
|
||||
//otherwise you only need to advance one character
|
||||
switch(currentParam){
|
||||
switch (currentParam) {
|
||||
case "L":
|
||||
int semiColonIndex = argString.indexOf(";", currentPosition);
|
||||
currentPosition = semiColonIndex + 1; //advance past ;
|
||||
break;
|
||||
case "[":
|
||||
//advance past all the ['s
|
||||
while (argString.charAt(currentPosition) == '['){
|
||||
while (argString.charAt(currentPosition) == '[') {
|
||||
currentPosition++;
|
||||
}
|
||||
//advance past the base type of the array
|
||||
if (argString.charAt(currentPosition) == 'L'){
|
||||
if (argString.charAt(currentPosition) == 'L') {
|
||||
semiColonIndex = argString.indexOf(";", currentPosition);
|
||||
currentPosition = semiColonIndex + 1;
|
||||
}
|
||||
else{
|
||||
else {
|
||||
currentPosition++;
|
||||
}
|
||||
break;
|
||||
@ -402,7 +422,8 @@ public class DescriptorDecoder {
|
||||
* @param methodDescriptor
|
||||
* @return
|
||||
*/
|
||||
public static List<DataType> getDataTypeList(String methodDescriptor, DataTypeManager dtManager) {
|
||||
public static List<DataType> getDataTypeList(String methodDescriptor,
|
||||
DataTypeManager dtManager) {
|
||||
ArrayList<DataType> paramDataTypes = new ArrayList<>();
|
||||
int closeParenIndex = methodDescriptor.indexOf(")");
|
||||
String argString = methodDescriptor.substring(1, closeParenIndex);
|
||||
@ -411,14 +432,14 @@ public class DescriptorDecoder {
|
||||
int currentPosition = 0;
|
||||
int len = argString.length();
|
||||
String currentParam = null;
|
||||
while (currentPosition < len){
|
||||
while (currentPosition < len) {
|
||||
int arrayDimensions = 0;
|
||||
//if it's an array, decode the number of dimensions
|
||||
while (argString.charAt(currentPosition) == '['){
|
||||
while (argString.charAt(currentPosition) == '[') {
|
||||
arrayDimensions++;
|
||||
currentPosition++;
|
||||
}
|
||||
switch (argString.charAt(currentPosition)){
|
||||
switch (argString.charAt(currentPosition)) {
|
||||
case BASE_TYPE_BYTE:
|
||||
case BASE_TYPE_CHAR:
|
||||
case BASE_TYPE_SHORT:
|
||||
@ -427,17 +448,17 @@ public class DescriptorDecoder {
|
||||
case BASE_TYPE_FLOAT:
|
||||
case BASE_TYPE_DOUBLE:
|
||||
case BASE_TYPE_BOOLEAN:
|
||||
currentParam = argString.substring(currentPosition, currentPosition+1);
|
||||
currentParam = argString.substring(currentPosition, currentPosition + 1);
|
||||
currentPosition++;
|
||||
break;
|
||||
case BASE_TYPE_REFERENCE:
|
||||
int semiColonIndex = argString.indexOf(";", currentPosition);
|
||||
currentParam = argString.substring(currentPosition, semiColonIndex+1);
|
||||
currentParam = argString.substring(currentPosition, semiColonIndex + 1);
|
||||
currentPosition = semiColonIndex + 1;
|
||||
break;
|
||||
}
|
||||
currentParamType = getDataTypeOfDescriptor(currentParam, dtManager);
|
||||
if (arrayDimensions > 0){
|
||||
if (arrayDimensions > 0) {
|
||||
paramDataTypes.add(dtManager.getPointer(currentParamType));
|
||||
}
|
||||
else {
|
||||
@ -455,47 +476,91 @@ public class DescriptorDecoder {
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public static String getDescriptorForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type){
|
||||
public static String getDescriptorForInvoke(int offset,
|
||||
AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) {
|
||||
String descriptor = null;
|
||||
int name_and_type_index = 0;
|
||||
switch (type){
|
||||
switch (type) {
|
||||
case INVOKE_DYNAMIC:
|
||||
ConstantPoolInvokeDynamicInfo dynamicInfo = (ConstantPoolInvokeDynamicInfo) constantPool[offset];
|
||||
ConstantPoolInvokeDynamicInfo dynamicInfo =
|
||||
(ConstantPoolInvokeDynamicInfo) constantPool[offset];
|
||||
name_and_type_index = dynamicInfo.getNameAndTypeIndex();
|
||||
break;
|
||||
case INVOKE_INTERFACE:
|
||||
ConstantPoolInterfaceMethodReferenceInfo interfaceInfo = (ConstantPoolInterfaceMethodReferenceInfo) constantPool[offset];
|
||||
ConstantPoolInterfaceMethodReferenceInfo interfaceInfo =
|
||||
(ConstantPoolInterfaceMethodReferenceInfo) constantPool[offset];
|
||||
name_and_type_index = interfaceInfo.getNameAndTypeIndex();
|
||||
break;
|
||||
case INVOKE_SPECIAL:
|
||||
case INVOKE_STATIC:
|
||||
AbstractConstantPoolInfoJava poolElem = constantPool[offset];
|
||||
if (poolElem instanceof ConstantPoolInterfaceMethodReferenceInfo) {
|
||||
interfaceInfo = (ConstantPoolInterfaceMethodReferenceInfo) constantPool[offset];
|
||||
name_and_type_index = interfaceInfo.getNameAndTypeIndex();
|
||||
break;
|
||||
}
|
||||
if (poolElem instanceof ConstantPoolMethodReferenceInfo) {
|
||||
ConstantPoolMethodReferenceInfo methodReferenceInfo =
|
||||
(ConstantPoolMethodReferenceInfo) constantPool[offset];
|
||||
name_and_type_index = methodReferenceInfo.getNameAndTypeIndex();
|
||||
break;
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported type for invokestatic at constant pool element " + offset);
|
||||
case INVOKE_SPECIAL:
|
||||
case INVOKE_VIRTUAL:
|
||||
ConstantPoolMethodReferenceInfo methodReferenceInfo = (ConstantPoolMethodReferenceInfo) constantPool[offset];
|
||||
ConstantPoolMethodReferenceInfo methodReferenceInfo =
|
||||
(ConstantPoolMethodReferenceInfo) constantPool[offset];
|
||||
name_and_type_index = methodReferenceInfo.getNameAndTypeIndex();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("unimplemented method type: " + type.name());
|
||||
}
|
||||
ConstantPoolNameAndTypeInfo methodNameAndType = (ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index];
|
||||
ConstantPoolNameAndTypeInfo methodNameAndType =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index];
|
||||
int descriptor_index = methodNameAndType.getDescriptorIndex();
|
||||
ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
|
||||
descriptor = descriptorInfo.getString();
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
public final static String decodeType(ConstantPoolUtf8Info utf,
|
||||
boolean useFullyQualifiedClassName) {
|
||||
return DescriptorDecoder.getTypeNameFromDescriptor(utf.getString(), useFullyQualifiedClassName, true);
|
||||
}
|
||||
|
||||
//no L, no ;
|
||||
public static DataType resolveClassForString(String fullyQualifiedName, DataTypeManager dtm, DataType baseType){
|
||||
/**
|
||||
* Resolves the datatype represented by {@code fullyQualifiedName} with a base type of
|
||||
* {@code baseType} into dtm
|
||||
* @param fullyQualifiedName String representation of type
|
||||
* @param dtm data type manager
|
||||
* @param baseType base type
|
||||
* @return data type represented by input string
|
||||
*/
|
||||
public static DataType resolveClassForString(String fullyQualifiedName, DataTypeManager dtm,
|
||||
DataType baseType) {
|
||||
fullyQualifiedName = CategoryPath.DELIMITER_CHAR + fullyQualifiedName;
|
||||
CategoryPath catPath = new CategoryPath(fullyQualifiedName);
|
||||
String[] parts = catPath.getPathElements();
|
||||
DataType dataType = new TypedefDataType(catPath,parts[parts.length-1],baseType);
|
||||
DataType dataType = new TypedefDataType(catPath, parts[parts.length - 1], baseType);
|
||||
dtm.resolve(dataType, DataTypeConflictHandler.KEEP_HANDLER);
|
||||
return dataType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String representing the types of the parameters of a method, e.g.
|
||||
* (java.lang.String, java.lang.Integer) for a method with signature
|
||||
* public static void test(String x, Integer y);
|
||||
* @param descriptor method descriptor
|
||||
* @return string representation of types of method parameters
|
||||
*/
|
||||
public static String getParameterString(String descriptor) {
|
||||
List<String> paramTypeNames = getTypeNameList(descriptor, true, true);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
//don't append the last element of the list, which is the return type
|
||||
for (int i = 0, max = paramTypeNames.size() - 1; i < max; ++i) {
|
||||
sb.append(paramTypeNames.get(i));
|
||||
if (i < max - 1) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,14 +15,14 @@
|
||||
*/
|
||||
package ghidra.javaclass.format;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.javaclass.format.attributes.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -48,18 +48,18 @@ public class FieldInfoJava implements StructConverter {
|
||||
private short nameIndex;
|
||||
private short descriptorIndex;
|
||||
private short attributesCount;
|
||||
private AbstractAttributeInfo [] attributes;
|
||||
private AbstractAttributeInfo[] attributes;
|
||||
|
||||
public FieldInfoJava( BinaryReader reader, ClassFileJava classFile ) throws IOException {
|
||||
public FieldInfoJava(BinaryReader reader, ClassFileJava classFile) throws IOException {
|
||||
_offset = reader.getPointerIndex();
|
||||
|
||||
accessFlags = reader.readNextShort();
|
||||
nameIndex = reader.readNextShort();
|
||||
descriptorIndex = reader.readNextShort();
|
||||
attributesCount = reader.readNextShort();
|
||||
attributes = new AbstractAttributeInfo[ attributesCount ];
|
||||
for ( int i = 0 ; i < attributesCount ; i++ ) {
|
||||
attributes[ i ] = AttributeFactory.get( reader, classFile.getConstantPool() );
|
||||
accessFlags = reader.readNextShort();
|
||||
nameIndex = reader.readNextShort();
|
||||
descriptorIndex = reader.readNextShort();
|
||||
attributesCount = reader.readNextShort();
|
||||
attributes = new AbstractAttributeInfo[getAttributesCount()];
|
||||
for (int i = 0; i < getAttributesCount(); i++) {
|
||||
attributes[i] = AttributeFactory.get(reader, classFile.getConstantPool());
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,8 +84,8 @@ public class FieldInfoJava implements StructConverter {
|
||||
* unqualified name denoting a field.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getNameIndex() {
|
||||
return nameIndex;
|
||||
public int getNameIndex() {
|
||||
return nameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,8 +95,8 @@ public class FieldInfoJava implements StructConverter {
|
||||
* descriptor.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getDescriptorIndex() {
|
||||
return descriptorIndex;
|
||||
public int getDescriptorIndex() {
|
||||
return descriptorIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,8 +104,8 @@ public class FieldInfoJava implements StructConverter {
|
||||
* attributes of this field.
|
||||
* @return the number of additional attributes
|
||||
*/
|
||||
public short getAttributesCount() {
|
||||
return attributesCount;
|
||||
public int getAttributesCount() {
|
||||
return attributesCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,13 +137,13 @@ public class FieldInfoJava implements StructConverter {
|
||||
* information.
|
||||
* @return
|
||||
*/
|
||||
public AbstractAttributeInfo [] getAttributes() {
|
||||
public AbstractAttributeInfo[] getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public ConstantValueAttribute getConstantValueAttribute() {
|
||||
for ( AbstractAttributeInfo attributeInfo : attributes ) {
|
||||
if ( attributeInfo instanceof ConstantValueAttribute ) {
|
||||
for (AbstractAttributeInfo attributeInfo : attributes) {
|
||||
if (attributeInfo instanceof ConstantValueAttribute) {
|
||||
return (ConstantValueAttribute) attributeInfo;
|
||||
}
|
||||
}
|
||||
@ -152,17 +152,17 @@ public class FieldInfoJava implements StructConverter {
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "field_info" + "|" + attributesCount + "|";
|
||||
String name = "field_info" + "|" + attributesCount + "|";
|
||||
|
||||
Structure structure = new StructureDataType( name, 0 );
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
|
||||
structure.add( WORD, "access_flags", null );
|
||||
structure.add( WORD, "name_index", null );
|
||||
structure.add( WORD, "descriptor_index", null );
|
||||
structure.add( WORD, "attributes_count", null );
|
||||
structure.add(WORD, "access_flags", null);
|
||||
structure.add(WORD, "name_index", null);
|
||||
structure.add(WORD, "descriptor_index", null);
|
||||
structure.add(WORD, "attributes_count", null);
|
||||
|
||||
for ( int i = 0 ; i < attributes.length ; ++i ) {
|
||||
structure.add( attributes[ i ].toDataType(), "attributes_" + i, null );
|
||||
for (int i = 0; i < attributes.length; ++i) {
|
||||
structure.add(attributes[i].toDataType(), "attributes_" + i, null);
|
||||
}
|
||||
|
||||
return structure;
|
||||
|
@ -15,42 +15,38 @@
|
||||
*/
|
||||
package ghidra.javaclass.format;
|
||||
|
||||
import ghidra.framework.options.Options;
|
||||
import java.util.Arrays;
|
||||
|
||||
import ghidra.app.util.opinion.JavaLoader;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class JavaClassUtil {
|
||||
|
||||
|
||||
public final static long LOOKUP_ADDRESS = 0xE0000000L;
|
||||
//65536 is the maximum size of the methods_count item in a class file
|
||||
public static final long METHOD_INDEX_SIZE = 65536 * 4;
|
||||
|
||||
public final static boolean isClassFile(Program program) {
|
||||
Options options = program.getOptions(Program.PROGRAM_INFO);
|
||||
String firmwarePath = options.getString("Firmware Path", "");
|
||||
|
||||
if (program.getExecutablePath().toLowerCase().endsWith(".class") ||
|
||||
firmwarePath.toLowerCase().endsWith(".class")) {
|
||||
byte[] bytes = new byte[4];
|
||||
try {
|
||||
Address address = program.getAddressFactory().getAddressSpace("constantPool").getMinAddress();
|
||||
program.getMemory().getBytes(address, bytes);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.info(JavaClassUtil.class, e.getLocalizedMessage());
|
||||
}
|
||||
return Arrays.equals(bytes, JavaClassConstants.MAGIC_BYTES);
|
||||
byte[] bytes = new byte[4];
|
||||
try {
|
||||
Address address = program.getAddressFactory().getAddressSpace(
|
||||
JavaLoader.CONSTANT_POOL).getMinAddress();
|
||||
program.getMemory().getBytes(address, bytes);
|
||||
}
|
||||
return false;
|
||||
catch (Exception e) {
|
||||
Msg.info(JavaClassUtil.class, e.getLocalizedMessage());
|
||||
return false;
|
||||
}
|
||||
return Arrays.equals(bytes, JavaClassConstants.MAGIC_BYTES);
|
||||
}
|
||||
|
||||
public static Address toLookupAddress( Program program, int methodIndex ) {
|
||||
AddressFactory addressFactory = program.getAddressFactory( );
|
||||
AddressSpace defaultAddressSpace = addressFactory.getDefaultAddressSpace( );
|
||||
return defaultAddressSpace.getAddress( JavaClassUtil.LOOKUP_ADDRESS + ( methodIndex * 4 ) );
|
||||
|
||||
public static Address toLookupAddress(Program program, int methodIndex) {
|
||||
AddressFactory addressFactory = program.getAddressFactory();
|
||||
AddressSpace defaultAddressSpace = addressFactory.getDefaultAddressSpace();
|
||||
return defaultAddressSpace.getAddress(JavaClassUtil.LOOKUP_ADDRESS + (methodIndex * 4));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,15 +15,16 @@
|
||||
*/
|
||||
package ghidra.javaclass.format;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.javaclass.flags.MethodsInfoAccessFlags;
|
||||
import ghidra.javaclass.format.attributes.*;
|
||||
import ghidra.javaclass.format.constantpool.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Each method, including each instance initialization method (2.9) and the class or
|
||||
* interface initialization method (2.9), is described by a method_info structure. No
|
||||
@ -58,8 +59,8 @@ public class MethodInfoJava implements StructConverter {
|
||||
nameIndex = reader.readNextShort();
|
||||
descriptorIndex = reader.readNextShort();
|
||||
attributesCount = reader.readNextShort();
|
||||
attributes = new AbstractAttributeInfo[attributesCount];
|
||||
for (int i = 0; i < attributesCount; i++) {
|
||||
attributes = new AbstractAttributeInfo[getAttributesCount()];
|
||||
for (int i = 0; i < getAttributesCount(); i++) {
|
||||
attributes[i] = AttributeFactory.get(reader, classFile.getConstantPool());
|
||||
}
|
||||
}
|
||||
@ -81,13 +82,14 @@ public class MethodInfoJava implements StructConverter {
|
||||
public short getAccessFlags() {
|
||||
return accessFlags;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return boolean encoding whether the method is static
|
||||
*/
|
||||
public boolean isStatic(){
|
||||
return AccessFlagsJava.isStatic(accessFlags);
|
||||
public boolean isStatic() {
|
||||
return (MethodsInfoAccessFlags.ACC_STATIC.getValue() &
|
||||
accessFlags) == MethodsInfoAccessFlags.ACC_STATIC.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,8 +100,8 @@ public class MethodInfoJava implements StructConverter {
|
||||
* denoting a method.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getNameIndex() {
|
||||
return nameIndex;
|
||||
public int getNameIndex() {
|
||||
return nameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,8 +110,8 @@ public class MethodInfoJava implements StructConverter {
|
||||
* CONSTANT_Utf8_info structure representing a valid method descriptor.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getDescriptorIndex() {
|
||||
return descriptorIndex;
|
||||
public int getDescriptorIndex() {
|
||||
return descriptorIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -117,8 +119,8 @@ public class MethodInfoJava implements StructConverter {
|
||||
* attributes of this method.
|
||||
* @return the number of additional attributes of this method
|
||||
*/
|
||||
public short getAttributesCount() {
|
||||
return attributesCount;
|
||||
public int getAttributesCount() {
|
||||
return attributesCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -178,11 +180,13 @@ public class MethodInfoJava implements StructConverter {
|
||||
ConstantPoolUtf8Info methodDescriptor =
|
||||
(ConstantPoolUtf8Info) constantPool[descriptorIndex];
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
stringBuffer.append(AccessFlagsJava.toString(accessFlags, false).trim());
|
||||
stringBuffer.append(MethodsInfoAccessFlags.toString(accessFlags));
|
||||
|
||||
if (!methodName.getString().equals("<clinit>")) {
|
||||
if (methodName.getString().equals("<clinit>")) {
|
||||
stringBuffer.append(" (class initializer)");
|
||||
}
|
||||
else {
|
||||
stringBuffer.append(' ');
|
||||
|
||||
if (methodName.getString().equals("<init>")) {//replace constructors with name of this class
|
||||
ConstantPoolClassInfo thisClass =
|
||||
(ConstantPoolClassInfo) constantPool[classFile.getThisClass()];
|
||||
@ -205,13 +209,12 @@ public class MethodInfoJava implements StructConverter {
|
||||
stringBuffer.append(methodName.getString());
|
||||
}
|
||||
|
||||
stringBuffer.append('(');
|
||||
|
||||
CodeAttribute codeAttribute = getCodeAttribute();
|
||||
if (codeAttribute != null) {
|
||||
LocalVariableTableAttribute localVariableTable =
|
||||
codeAttribute.getLocalVariableTableAttribute();
|
||||
if (localVariableTable != null) {
|
||||
stringBuffer.append('(');
|
||||
LocalVariableJava[] localVariables = localVariableTable.getLocalVariables();
|
||||
int startIndex = getParametersStartIndex();
|
||||
for (int i = startIndex; i < localVariables.length; ++i) {
|
||||
@ -224,22 +227,28 @@ public class MethodInfoJava implements StructConverter {
|
||||
ConstantPoolUtf8Info parameterDescriptor =
|
||||
(ConstantPoolUtf8Info) constantPool[localVariables[i].getDescriptorIndex()];
|
||||
|
||||
stringBuffer.append(DescriptorDecoder.decodeType(parameterDescriptor,
|
||||
false));
|
||||
stringBuffer.append(DescriptorDecoder.getTypeNameFromDescriptor(
|
||||
parameterDescriptor.getString(), false, true));
|
||||
stringBuffer.append(" ");
|
||||
stringBuffer.append(parameterName);
|
||||
|
||||
}
|
||||
}
|
||||
stringBuffer.append(')');
|
||||
}
|
||||
else {
|
||||
stringBuffer.append(
|
||||
DescriptorDecoder.getParameterString(methodDescriptor.getString()));
|
||||
}
|
||||
}
|
||||
|
||||
stringBuffer.append(')');
|
||||
ExceptionsAttribute exceptionsAttribute = getExceptionsAttribute();
|
||||
if (exceptionsAttribute != null) {
|
||||
int i = 0;
|
||||
for (short s : exceptionsAttribute.getExceptionIndexTable()) {
|
||||
ConstantPoolClassInfo exceptionClass = (ConstantPoolClassInfo) constantPool[s];
|
||||
for (int k = 0; k < exceptionsAttribute.getNumberOfExceptions(); k++) {
|
||||
ConstantPoolClassInfo exceptionClass =
|
||||
(ConstantPoolClassInfo) constantPool[exceptionsAttribute.getExceptionIndexTableEntry(
|
||||
k)];
|
||||
ConstantPoolUtf8Info exceptionClassName =
|
||||
(ConstantPoolUtf8Info) constantPool[exceptionClass.getNameIndex()];
|
||||
String className = exceptionClassName.getString();
|
||||
@ -265,7 +274,7 @@ public class MethodInfoJava implements StructConverter {
|
||||
* otherwise skip index 0 because it contains the 'this' parameter.
|
||||
*/
|
||||
private int getParametersStartIndex() {
|
||||
return AccessFlagsJava.isStatic(accessFlags) ? 0 : 1;
|
||||
return isStatic() ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -299,7 +308,8 @@ public class MethodInfoJava implements StructConverter {
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "method_info" + "|" + nameIndex + "|" + descriptorIndex + "|" + attributesCount + "|";
|
||||
String name =
|
||||
"method_info" + "|" + nameIndex + "|" + descriptorIndex + "|" + attributesCount + "|";
|
||||
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,12 +15,12 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -94,11 +93,11 @@ public abstract class AbstractAttributeInfo implements StructConverter {
|
||||
private short attributeNameIndex;
|
||||
private int attributeLength;
|
||||
|
||||
protected AbstractAttributeInfo( BinaryReader reader ) throws IOException {
|
||||
protected AbstractAttributeInfo(BinaryReader reader) throws IOException {
|
||||
_offset = reader.getPointerIndex();
|
||||
|
||||
attributeNameIndex = reader.readNextShort();
|
||||
attributeLength = reader.readNextInt();
|
||||
attributeLength = reader.readNextInt();
|
||||
}
|
||||
|
||||
public long getOffset() {
|
||||
@ -112,8 +111,8 @@ public abstract class AbstractAttributeInfo implements StructConverter {
|
||||
* @see AttributesConstants
|
||||
* @return the attribute_name_index
|
||||
*/
|
||||
public short getAttributeNameIndex() {
|
||||
return attributeNameIndex;
|
||||
public int getAttributeNameIndex() {
|
||||
return attributeNameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -127,10 +126,10 @@ public abstract class AbstractAttributeInfo implements StructConverter {
|
||||
return attributeLength;
|
||||
}
|
||||
|
||||
protected StructureDataType getBaseStructure( String name ) {
|
||||
StructureDataType structure = new StructureDataType( name + "|" + attributeLength + "|", 0 );
|
||||
structure.add( WORD, "attribute_name_index", null );
|
||||
structure.add( DWORD, "attribute_length" , null );
|
||||
protected StructureDataType getBaseStructure(String name) {
|
||||
StructureDataType structure = new StructureDataType(name + "|" + attributeLength + "|", 0);
|
||||
structure.add(WORD, "attribute_name_index", null);
|
||||
structure.add(DWORD, "attribute_length", null);
|
||||
return structure;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.javaclass.format.DescriptorDecoder;
|
||||
@ -22,8 +24,6 @@ import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -69,38 +69,35 @@ public class AnnotationElementValue implements StructConverter {
|
||||
private AnnotationJava annotation;
|
||||
|
||||
private short numberOfValues;
|
||||
private AnnotationElementValue [] values;
|
||||
private AnnotationElementValue[] values;
|
||||
|
||||
public AnnotationElementValue( BinaryReader reader ) throws IOException {
|
||||
public AnnotationElementValue(BinaryReader reader) throws IOException {
|
||||
tag = reader.readNextByte();
|
||||
|
||||
if ( tag == DescriptorDecoder.BASE_TYPE_BYTE ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_CHAR ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_INT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_SHORT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_LONG ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_FLOAT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_DOUBLE ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_BOOLEAN ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_STRING ) {
|
||||
if (tag == DescriptorDecoder.BASE_TYPE_BYTE || tag == DescriptorDecoder.BASE_TYPE_CHAR ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_INT || tag == DescriptorDecoder.BASE_TYPE_SHORT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_LONG || tag == DescriptorDecoder.BASE_TYPE_FLOAT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_DOUBLE ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_BOOLEAN ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_STRING) {
|
||||
|
||||
constantValueIndex = reader.readNextShort();
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_ENUM ) {
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_ENUM) {
|
||||
typeNameIndex = reader.readNextShort();
|
||||
constantNameIndex = reader.readNextShort();
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_CLASS ) {
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_CLASS) {
|
||||
classInfoIndex = reader.readNextShort();
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_ANNOTATION ) {
|
||||
annotation = new AnnotationJava( reader );
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_ANNOTATION) {
|
||||
annotation = new AnnotationJava(reader);
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_ARRAY ) {
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_ARRAY) {
|
||||
numberOfValues = reader.readNextShort();
|
||||
values = new AnnotationElementValue[ numberOfValues ];
|
||||
for ( int i = 0 ; i < numberOfValues ; ++i ) {
|
||||
values[ i ] = new AnnotationElementValue( reader );
|
||||
values = new AnnotationElementValue[numberOfValues & 0xffff];
|
||||
for (int i = 0; i < (numberOfValues & 0xffff); ++i) {
|
||||
values[i] = new AnnotationElementValue(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -138,8 +135,8 @@ public class AnnotationElementValue implements StructConverter {
|
||||
* for the field type designated by the tag item, as specified in Table 4.24.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getConstantValueIndex() {
|
||||
return constantValueIndex;
|
||||
public int getConstantValueIndex() {
|
||||
return constantValueIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -151,11 +148,11 @@ public class AnnotationElementValue implements StructConverter {
|
||||
* element_value structure.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getTypeNameIndex() {
|
||||
if ( tag != DescriptorDecoder.BASE_TYPE_ENUM ) {
|
||||
public int getTypeNameIndex() {
|
||||
if (tag != DescriptorDecoder.BASE_TYPE_ENUM) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return typeNameIndex;
|
||||
return typeNameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -166,11 +163,11 @@ public class AnnotationElementValue implements StructConverter {
|
||||
* structure.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getConstantNameIndex() {
|
||||
if ( tag != DescriptorDecoder.BASE_TYPE_ENUM ) {
|
||||
public int getConstantNameIndex() {
|
||||
if (tag != DescriptorDecoder.BASE_TYPE_ENUM) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return constantNameIndex;
|
||||
return constantNameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -183,8 +180,8 @@ public class AnnotationElementValue implements StructConverter {
|
||||
* For example, 'V' for Void.class, 'Ljava/lang/Object;' for Object, etc.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getClassInfoIndex() {
|
||||
return classInfoIndex;
|
||||
public int getClassInfoIndex() {
|
||||
return classInfoIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -206,32 +203,29 @@ public class AnnotationElementValue implements StructConverter {
|
||||
* array-typed value represented by this element_value structure.
|
||||
* @return nested element value table
|
||||
*/
|
||||
public AnnotationElementValue [] getValues() {
|
||||
public AnnotationElementValue[] getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "element_value" +"|" + tag + "|";
|
||||
StructureDataType structure = new StructureDataType( name, 0 );
|
||||
String name = "element_value" + "|" + tag + "|";
|
||||
StructureDataType structure = new StructureDataType(name, 0);
|
||||
|
||||
if ( tag == DescriptorDecoder.BASE_TYPE_BYTE ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_CHAR ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_INT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_SHORT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_LONG ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_FLOAT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_DOUBLE ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_BOOLEAN ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_STRING ) {
|
||||
if (tag == DescriptorDecoder.BASE_TYPE_BYTE || tag == DescriptorDecoder.BASE_TYPE_CHAR ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_INT || tag == DescriptorDecoder.BASE_TYPE_SHORT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_LONG || tag == DescriptorDecoder.BASE_TYPE_FLOAT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_DOUBLE ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_BOOLEAN ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_STRING) {
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_ENUM ) {
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_ENUM) {
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_CLASS ) {
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_CLASS) {
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_ANNOTATION ) {
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_ANNOTATION) {
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_ARRAY ) {
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_ARRAY) {
|
||||
}
|
||||
|
||||
return structure;
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,14 +15,14 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -43,9 +42,9 @@ public class AnnotationElementValuePair implements StructConverter {
|
||||
private short elementNameIndex;
|
||||
private AnnotationElementValue value;
|
||||
|
||||
public AnnotationElementValuePair( BinaryReader reader ) throws IOException {
|
||||
public AnnotationElementValuePair(BinaryReader reader) throws IOException {
|
||||
elementNameIndex = reader.readNextShort();
|
||||
value = new AnnotationElementValue( reader );
|
||||
value = new AnnotationElementValue(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,8 +55,8 @@ public class AnnotationElementValuePair implements StructConverter {
|
||||
* element represented by this element_value_pairs entry.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getElementNameIndex() {
|
||||
return elementNameIndex;
|
||||
public int getElementNameIndex() {
|
||||
return elementNameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,9 +70,9 @@ public class AnnotationElementValuePair implements StructConverter {
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = new StructureDataType( "element_value_pair", 0 );
|
||||
structure.add( WORD, "element_name_index", null );
|
||||
structure.add( value.toDataType(), "element_value_pair", null );
|
||||
StructureDataType structure = new StructureDataType("element_value_pair", 0);
|
||||
structure.add(WORD, "element_name_index", null);
|
||||
structure.add(value.toDataType(), "element_value_pair", null);
|
||||
return structure;
|
||||
}
|
||||
}
|
||||
|
@ -15,14 +15,14 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -45,14 +45,14 @@ public class AnnotationJava implements StructConverter {
|
||||
|
||||
private short typeIndex;
|
||||
private short numberOfElementValuePairs;
|
||||
private AnnotationElementValuePair [] elementValuePairs;
|
||||
private AnnotationElementValuePair[] elementValuePairs;
|
||||
|
||||
public AnnotationJava( BinaryReader reader ) throws IOException {
|
||||
public AnnotationJava(BinaryReader reader) throws IOException {
|
||||
typeIndex = reader.readNextShort();
|
||||
numberOfElementValuePairs = reader.readNextShort();
|
||||
elementValuePairs = new AnnotationElementValuePair[ numberOfElementValuePairs ];
|
||||
for ( int i = 0 ; i < numberOfElementValuePairs ; ++i ) {
|
||||
elementValuePairs[ i ] = new AnnotationElementValuePair( reader );
|
||||
elementValuePairs = new AnnotationElementValuePair[getNumberOfElementValuePairs()];
|
||||
for (int i = 0; i < getNumberOfElementValuePairs(); ++i) {
|
||||
elementValuePairs[i] = new AnnotationElementValuePair(reader);
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,8 +64,8 @@ public class AnnotationJava implements StructConverter {
|
||||
* represented by this annotation structure.
|
||||
* @return valid index into the constant_pool table
|
||||
*/
|
||||
public short getTypeIndex() {
|
||||
return typeIndex;
|
||||
public int getTypeIndex() {
|
||||
return typeIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,26 +77,26 @@ public class AnnotationJava implements StructConverter {
|
||||
* annotation.
|
||||
* @return the number of element-value pairs of the annotation
|
||||
*/
|
||||
public short getNumberOfElementValuePairs() {
|
||||
return numberOfElementValuePairs;
|
||||
public int getNumberOfElementValuePairs() {
|
||||
return numberOfElementValuePairs & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element value pair table for this annotation.
|
||||
* @return the element value pair table
|
||||
*/
|
||||
public AnnotationElementValuePair [] getElementValuePairs() {
|
||||
public AnnotationElementValuePair[] getElementValuePairs() {
|
||||
return elementValuePairs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "annotation" +"|" + numberOfElementValuePairs + "|";
|
||||
StructureDataType structure = new StructureDataType( name, 0 );
|
||||
structure.add( WORD, "type_index", null );
|
||||
structure.add( WORD, "num_element_value_pairs", null );
|
||||
for ( int i = 0 ; i < elementValuePairs.length ; ++i ) {
|
||||
structure.add( elementValuePairs[ i ].toDataType(), "element_value_pair_" + i, null );
|
||||
String name = "annotation" + "|" + numberOfElementValuePairs + "|";
|
||||
StructureDataType structure = new StructureDataType(name, 0);
|
||||
structure.add(WORD, "type_index", null);
|
||||
structure.add(WORD, "num_element_value_pairs", null);
|
||||
for (int i = 0; i < elementValuePairs.length; ++i) {
|
||||
structure.add(elementValuePairs[i].toDataType(), "element_value_pair_" + i, null);
|
||||
}
|
||||
return structure;
|
||||
}
|
||||
|
@ -15,90 +15,82 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class AttributeFactory {
|
||||
|
||||
public static AbstractAttributeInfo get( BinaryReader reader, AbstractConstantPoolInfoJava [] constantPool ) throws IOException {
|
||||
|
||||
int attributeNameIndex = reader.readShort( reader.getPointerIndex() );
|
||||
public static AbstractAttributeInfo get(BinaryReader reader,
|
||||
AbstractConstantPoolInfoJava[] constantPool) throws IOException {
|
||||
|
||||
if ( attributeNameIndex < 1 || attributeNameIndex >= constantPool.length ) {
|
||||
throw new RuntimeException( "invalid index");
|
||||
int attributeNameIndex = reader.readShort(reader.getPointerIndex());
|
||||
|
||||
if (attributeNameIndex < 1 || attributeNameIndex >= constantPool.length) {
|
||||
throw new RuntimeException("invalid index");
|
||||
}
|
||||
|
||||
if ( !( constantPool[ attributeNameIndex ] instanceof ConstantPoolUtf8Info ) ) {
|
||||
if (!(constantPool[attributeNameIndex] instanceof ConstantPoolUtf8Info)) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
ConstantPoolUtf8Info utf8 = (ConstantPoolUtf8Info) constantPool[ attributeNameIndex ];
|
||||
ConstantPoolUtf8Info utf8 = (ConstantPoolUtf8Info) constantPool[attributeNameIndex];
|
||||
|
||||
if ( utf8.getString().equals( AttributesConstants.ConstantValue ) ) {
|
||||
return new ConstantValueAttribute( reader );
|
||||
switch (utf8.getString()) {
|
||||
case AttributesConstants.AnnotationDefault:
|
||||
return new AnnotationDefaultAttribute(reader);
|
||||
case AttributesConstants.BootstrapMethods:
|
||||
return new BootstrapMethodsAttribute(reader);
|
||||
case AttributesConstants.Code:
|
||||
return new CodeAttribute(reader, constantPool);
|
||||
case AttributesConstants.ConstantValue:
|
||||
return new ConstantValueAttribute(reader);
|
||||
case AttributesConstants.Deprecated:
|
||||
return new DeprecatedAttribute(reader);
|
||||
case AttributesConstants.EnclosingMethod:
|
||||
return new EnclosingMethodAttribute(reader);
|
||||
case AttributesConstants.Exceptions:
|
||||
return new ExceptionsAttribute(reader);
|
||||
case AttributesConstants.InnerClasses:
|
||||
return new InnerClassesAttribute(reader);
|
||||
case AttributesConstants.LineNumberTable:
|
||||
return new LineNumberTableAttribute(reader);
|
||||
case AttributesConstants.LocalVariableTable:
|
||||
return new LocalVariableTableAttribute(reader, constantPool);
|
||||
case AttributesConstants.LocalVariableTypeTable:
|
||||
return new LocalVariableTypeTableAttribute(reader);
|
||||
case AttributesConstants.ModuleMainClass:
|
||||
return new ModuleMainClassAttribute(reader);
|
||||
case AttributesConstants.ModulePackages:
|
||||
return new ModulePackagesAttribute(reader);
|
||||
case AttributesConstants.NestHost:
|
||||
return new NestHostAttribute(reader);
|
||||
case AttributesConstants.NestMembers:
|
||||
return new NestMembersAttribute(reader);
|
||||
case AttributesConstants.RuntimeInvisibleAnnotations:
|
||||
return new RuntimeInvisibleAnnotationsAttribute(reader);
|
||||
case AttributesConstants.RuntimeInvisibleParameterAnnotations:
|
||||
return new RuntimeParameterAnnotationsAttribute(reader, false /*invisible*/ );
|
||||
case AttributesConstants.RuntimeVisibleAnnotations:
|
||||
return new RuntimeVisibleAnnotationsAttribute(reader);
|
||||
case AttributesConstants.RuntimeVisibleParameterAnnotations:
|
||||
return new RuntimeParameterAnnotationsAttribute(reader, true /*visible*/ );
|
||||
case AttributesConstants.Signature:
|
||||
return new SignatureAttribute(reader);
|
||||
case AttributesConstants.SourceDebugExtension:
|
||||
return new SourceDebugExtensionAttribute(reader);
|
||||
case AttributesConstants.SourceFile:
|
||||
return new SourceFileAttribute(reader);
|
||||
case AttributesConstants.StackMapTable:
|
||||
return new StackMapTableAttribute(reader);
|
||||
case AttributesConstants.Synthetic:
|
||||
return new SyntheticAttribute(reader);
|
||||
case AttributesConstants.Module:
|
||||
return new ModuleAttribute(reader);
|
||||
default:
|
||||
throw new RuntimeException("Unknown attribute type: " + utf8.getString());
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.Code ) ) {
|
||||
return new CodeAttribute( reader, constantPool );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.StackMapTable ) ) {
|
||||
return new StackMapTableAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.Exceptions ) ) {
|
||||
return new ExceptionsAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.InnerClasses ) ) {
|
||||
return new InnerClassesAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.EnclosingMethod ) ) {
|
||||
return new EnclosingMethodAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.Synthetic ) ) {
|
||||
return new SyntheticAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.Signature ) ) {
|
||||
return new SignatureAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.SourceFile ) ) {
|
||||
return new SourceFileAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.SourceDebugExtension ) ) {
|
||||
return new SourceDebugExtensionAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.LineNumberTable ) ) {
|
||||
return new LineNumberTableAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.LocalVariableTable ) ) {
|
||||
return new LocalVariableTableAttribute( reader, constantPool );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.LocalVariableTypeTable ) ) {
|
||||
return new LocalVariableTypeTableAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.Deprecated ) ) {
|
||||
return new DeprecatedAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.RuntimeVisibleAnnotations ) ) {
|
||||
return new RuntimeVisibleAnnotationsAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.RuntimeInvisibleAnnotations ) ) {
|
||||
return new RuntimeInvisibleAnnotationsAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.RuntimeVisibleParameterAnnotations ) ) {
|
||||
return new RuntimeParameterAnnotationsAttribute( reader, true /*visible*/ );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.RuntimeInvisibleParameterAnnotations ) ) {
|
||||
return new RuntimeParameterAnnotationsAttribute( reader, false /*invisible*/ );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.AnnotationDefault ) ) {
|
||||
return new AnnotationDefaultAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.BootstrapMethods ) ) {
|
||||
return new BootstrapMethodsAttribute( reader );
|
||||
}
|
||||
|
||||
throw new RuntimeException( "Unknown attribute type: " + utf8.getString() );
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -34,9 +33,16 @@ public final class AttributesConstants {
|
||||
public final static String Deprecated = "Deprecated";
|
||||
public final static String RuntimeVisibleAnnotations = "RuntimeVisibleAnnotations";
|
||||
public final static String RuntimeInvisibleAnnotations = "RuntimeInvisibleAnnotations";
|
||||
public final static String RuntimeVisibleParameterAnnotations = "RuntimeVisibleParameterAnnotations";
|
||||
public final static String RuntimeInvisibleParameterAnnotations = "RuntimeInvisibleParameterAnnotations";
|
||||
public final static String RuntimeVisibleParameterAnnotations =
|
||||
"RuntimeVisibleParameterAnnotations";
|
||||
public final static String RuntimeInvisibleParameterAnnotations =
|
||||
"RuntimeInvisibleParameterAnnotations";
|
||||
public final static String AnnotationDefault = "AnnotationDefault";
|
||||
public final static String BootstrapMethods = "BootstrapMethods";
|
||||
public final static String Module = "Module";
|
||||
public final static String ModulePackages = "ModulePackages";
|
||||
public final static String ModuleMainClass = "ModuleMainClass";
|
||||
public final static String NestHost = "NestHost";
|
||||
public final static String NestMembers = "NestMembers";
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -20,9 +19,7 @@ import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.ArrayDataType;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
@ -34,12 +31,12 @@ public class BootstrapMethods implements StructConverter {
|
||||
|
||||
private short bootstrapMethodsReference;
|
||||
private short numberOfBootstrapArguments;
|
||||
private short [] bootstrapArguments;
|
||||
private short[] bootstrapArguments;
|
||||
|
||||
public BootstrapMethods( BinaryReader reader ) throws IOException {
|
||||
public BootstrapMethods(BinaryReader reader) throws IOException {
|
||||
bootstrapMethodsReference = reader.readNextShort();
|
||||
numberOfBootstrapArguments = reader.readNextShort();
|
||||
bootstrapArguments = reader.readNextShortArray( numberOfBootstrapArguments & 0xffff );
|
||||
bootstrapArguments = reader.readNextShortArray(getNumberOfBootstrapArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,8 +52,8 @@ public class BootstrapMethods implements StructConverter {
|
||||
*
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getBootstrapMethodsReference() {
|
||||
return bootstrapMethodsReference;
|
||||
public int getBootstrapMethodsReference() {
|
||||
return bootstrapMethodsReference & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -64,8 +61,8 @@ public class BootstrapMethods implements StructConverter {
|
||||
* items in the bootstrap_arguments array.
|
||||
* @return the number of items in the bootstrap_arguments array
|
||||
*/
|
||||
public short getNumberOfBootstrapArguments() {
|
||||
return numberOfBootstrapArguments;
|
||||
public int getNumberOfBootstrapArguments() {
|
||||
return numberOfBootstrapArguments & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,20 +77,21 @@ public class BootstrapMethods implements StructConverter {
|
||||
* CONSTANT_Double_info,
|
||||
* CONSTANT_MethodHandle_info, or
|
||||
* CONSTANT_MethodType_info structure.
|
||||
* @return
|
||||
* @param i entry
|
||||
* @return index
|
||||
*/
|
||||
public short [] getBootstrapArguments() {
|
||||
return bootstrapArguments;
|
||||
public int getBootstrapArgumentsEntry(int i) {
|
||||
return bootstrapArguments[i] & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = new StructureDataType( "bootstrap_methods", 0 );
|
||||
structure.add( WORD, "bootstrap_method_ref", null );
|
||||
structure.add( WORD, "num_bootstrap_arguments", null );
|
||||
if ( numberOfBootstrapArguments > 0 ) {
|
||||
DataType array = new ArrayDataType( WORD, numberOfBootstrapArguments, WORD.getLength() );
|
||||
structure.add( array, "bootstrapArguments", null );
|
||||
StructureDataType structure = new StructureDataType("bootstrap_methods", 0);
|
||||
structure.add(WORD, "bootstrap_method_ref", null);
|
||||
structure.add(WORD, "num_bootstrap_arguments", null);
|
||||
if (numberOfBootstrapArguments > 0) {
|
||||
DataType array = new ArrayDataType(WORD, numberOfBootstrapArguments, WORD.getLength());
|
||||
structure.add(array, "bootstrapArguments", null);
|
||||
}
|
||||
return structure;
|
||||
}
|
||||
|
@ -15,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -55,33 +55,33 @@ import java.io.IOException;
|
||||
public class BootstrapMethodsAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short numberOfBootstrapMethods;
|
||||
private BootstrapMethods [] bootstrapMethods;
|
||||
private BootstrapMethods[] bootstrapMethods;
|
||||
|
||||
public BootstrapMethodsAttribute( BinaryReader reader ) throws IOException {
|
||||
public BootstrapMethodsAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
|
||||
numberOfBootstrapMethods = reader.readNextShort();
|
||||
|
||||
bootstrapMethods = new BootstrapMethods[ numberOfBootstrapMethods ];
|
||||
for ( int i = 0 ; i < numberOfBootstrapMethods ; ++i ) {
|
||||
bootstrapMethods[ i ] = new BootstrapMethods( reader );
|
||||
bootstrapMethods = new BootstrapMethods[getNumberOfBootstrapMethods()];
|
||||
for (int i = 0; i < getNumberOfBootstrapMethods(); ++i) {
|
||||
bootstrapMethods[i] = new BootstrapMethods(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public short getNumberOfBootstrapMethods() {
|
||||
return numberOfBootstrapMethods;
|
||||
public int getNumberOfBootstrapMethods() {
|
||||
return numberOfBootstrapMethods & 0xffff;
|
||||
}
|
||||
|
||||
public BootstrapMethods[] getBootstrapMethods(){
|
||||
|
||||
public BootstrapMethods[] getBootstrapMethods() {
|
||||
return bootstrapMethods;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = getBaseStructure( "BootstrapMethods_attribute" );
|
||||
structure.add( WORD, "num_bootstrap_methods", null );
|
||||
for ( int i = 0 ; i < bootstrapMethods.length ; ++i ) {
|
||||
structure.add( bootstrapMethods[ i ].toDataType(), "bootstrap_methods" + i, null );
|
||||
StructureDataType structure = getBaseStructure("BootstrapMethods_attribute");
|
||||
structure.add(WORD, "num_bootstrap_methods", null);
|
||||
for (int i = 0; i < bootstrapMethods.length; ++i) {
|
||||
structure.add(bootstrapMethods[i].toDataType(), "bootstrap_methods" + i, null);
|
||||
}
|
||||
return structure;
|
||||
}
|
||||
|
@ -15,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -80,13 +80,13 @@ public class CodeAttribute extends AbstractAttributeInfo {
|
||||
_codeOffset = reader.getPointerIndex();
|
||||
code = reader.readNextByteArray(codeLength);
|
||||
exceptionTableLength = reader.readNextShort();
|
||||
exceptionTable = new ExceptionHandlerJava[exceptionTableLength];
|
||||
for (int i = 0; i < exceptionTableLength; i++) {
|
||||
exceptionTable = new ExceptionHandlerJava[getExceptionTableLength()];
|
||||
for (int i = 0; i < getExceptionTableLength(); i++) {
|
||||
exceptionTable[i] = new ExceptionHandlerJava(reader);
|
||||
}
|
||||
attributesCount = reader.readNextShort();
|
||||
attributes = new AbstractAttributeInfo[attributesCount];
|
||||
for (int i = 0; i < attributesCount; i++) {
|
||||
attributes = new AbstractAttributeInfo[getAttributesCount()];
|
||||
for (int i = 0; i < getAttributesCount(); i++) {
|
||||
attributes[i] = AttributeFactory.get(reader, constantPool);
|
||||
}
|
||||
}
|
||||
@ -96,8 +96,8 @@ public class CodeAttribute extends AbstractAttributeInfo {
|
||||
* operand stack of this method at any point during execution of the method.
|
||||
* @return the maximum depth of the operand stack
|
||||
*/
|
||||
public short getMaxStack() {
|
||||
return maxStack;
|
||||
public int getMaxStack() {
|
||||
return maxStack & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -111,8 +111,8 @@ public class CodeAttribute extends AbstractAttributeInfo {
|
||||
* @return the number of local variables in the
|
||||
* local variable array allocated upon invocation of this method
|
||||
*/
|
||||
public short getMaxLocals() {
|
||||
return maxLocals;
|
||||
public int getMaxLocals() {
|
||||
return maxLocals & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -148,8 +148,8 @@ public class CodeAttribute extends AbstractAttributeInfo {
|
||||
* in the exception_table table.
|
||||
* @return the number of entries in the exception_table table
|
||||
*/
|
||||
public short getExceptionTableLength() {
|
||||
return exceptionTableLength;
|
||||
public int getExceptionTableLength() {
|
||||
return exceptionTableLength & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -168,8 +168,8 @@ public class CodeAttribute extends AbstractAttributeInfo {
|
||||
* the Code attribute.
|
||||
* @return the number of attributes of the Code attribute
|
||||
*/
|
||||
public short getAttributesCount() {
|
||||
return attributesCount;
|
||||
public int getAttributesCount() {
|
||||
return attributesCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -56,8 +55,8 @@ public class ConstantValueAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short constantValueIndex;
|
||||
|
||||
public ConstantValueAttribute( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public ConstantValueAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
constantValueIndex = reader.readNextShort();
|
||||
}
|
||||
|
||||
@ -80,15 +79,15 @@ public class ConstantValueAttribute extends AbstractAttributeInfo {
|
||||
* </pre>
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getConstantValueIndex() {
|
||||
return constantValueIndex;
|
||||
public int getConstantValueIndex() {
|
||||
return constantValueIndex & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = getBaseStructure( "ConstantValue_attribute" );
|
||||
structure.add( WORD, "constantvalue_index", null );
|
||||
StructureDataType structure = getBaseStructure("ConstantValue_attribute");
|
||||
structure.add(WORD, "constantvalue_index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -46,8 +45,8 @@ public class EnclosingMethodAttribute extends AbstractAttributeInfo {
|
||||
private short classIndex;
|
||||
private short methodIndex;
|
||||
|
||||
public EnclosingMethodAttribute( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public EnclosingMethodAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
|
||||
classIndex = reader.readNextShort();
|
||||
methodIndex = reader.readNextShort();
|
||||
@ -60,8 +59,8 @@ public class EnclosingMethodAttribute extends AbstractAttributeInfo {
|
||||
* encloses the declaration of the current class.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getClassIndex() {
|
||||
return classIndex;
|
||||
public int getClassIndex() {
|
||||
return classIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,15 +73,15 @@ public class EnclosingMethodAttribute extends AbstractAttributeInfo {
|
||||
* type of a method in the class referenced by the class_index attribute above.
|
||||
* @return a valid index into the constant_pool table, or zero
|
||||
*/
|
||||
public short getMethodIndex() {
|
||||
return methodIndex;
|
||||
public int getMethodIndex() {
|
||||
return methodIndex & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = getBaseStructure( "EnclosingMethod_attribute" );
|
||||
structure.add( WORD, "class_index", null );
|
||||
structure.add( WORD, "method_index", null );
|
||||
StructureDataType structure = getBaseStructure("EnclosingMethod_attribute");
|
||||
structure.add(WORD, "class_index", null);
|
||||
structure.add(WORD, "method_index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
@ -15,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -32,10 +32,10 @@ public class ExceptionHandlerJava implements StructConverter {
|
||||
private short endPC;
|
||||
private short handlerPC;
|
||||
private short catchType;
|
||||
|
||||
public ExceptionHandlerJava( BinaryReader reader ) throws IOException {
|
||||
startPC = reader.readNextShort();
|
||||
endPC = reader.readNextShort();
|
||||
|
||||
public ExceptionHandlerJava(BinaryReader reader) throws IOException {
|
||||
startPC = reader.readNextShort();
|
||||
endPC = reader.readNextShort();
|
||||
handlerPC = reader.readNextShort();
|
||||
catchType = reader.readNextShort();
|
||||
}
|
||||
@ -54,9 +54,10 @@ public class ExceptionHandlerJava implements StructConverter {
|
||||
* [start_pc, end_pc].
|
||||
* @return a valid index into the code array
|
||||
*/
|
||||
public short getStartPC() {
|
||||
return startPC;
|
||||
public int getStartPC() {
|
||||
return startPC & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* The values of the two items start_pc and end_pc indicate the ranges in the
|
||||
* code array at which the exception handler is active.
|
||||
@ -72,18 +73,20 @@ public class ExceptionHandlerJava implements StructConverter {
|
||||
* [start_pc, end_pc].
|
||||
* @return a valid index into the code array
|
||||
*/
|
||||
public short getEndPC() {
|
||||
return endPC;
|
||||
public int getEndPC() {
|
||||
return endPC & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of the handler_pc item indicates the start of the exception
|
||||
* handler. The value of the item must be a valid index into the code array
|
||||
* and must be the index of the opcode of an instruction.
|
||||
* @return the start of the exception handler
|
||||
*/
|
||||
public short getHandlerPC() {
|
||||
return handlerPC;
|
||||
public int getHandlerPC() {
|
||||
return handlerPC & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the value of the catch_type item is nonzero, it must be a valid index
|
||||
* into the constant_pool table. The constant_pool entry at that index
|
||||
@ -96,17 +99,17 @@ public class ExceptionHandlerJava implements StructConverter {
|
||||
* for all exceptions. This is used to implement finally (?3.13).
|
||||
* @return the value of the catch_type item
|
||||
*/
|
||||
public short getCatchType() {
|
||||
return catchType;
|
||||
public int getCatchType() {
|
||||
return catchType & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
Structure structure = new StructureDataType( "exception_handler", 0 );
|
||||
structure.add( WORD, "start_pc", null );
|
||||
structure.add( WORD, "end_pc", null );
|
||||
structure.add( WORD, "handler_pc", null );
|
||||
structure.add( WORD, "catch_type", null );
|
||||
Structure structure = new StructureDataType("exception_handler", 0);
|
||||
structure.add(WORD, "start_pc", null);
|
||||
structure.add(WORD, "end_pc", null);
|
||||
structure.add(WORD, "handler_pc", null);
|
||||
structure.add(WORD, "catch_type", null);
|
||||
return structure;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,12 +15,12 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -49,7 +48,7 @@ public class ExceptionsAttribute extends AbstractAttributeInfo {
|
||||
super(reader);
|
||||
|
||||
numberOfExceptions = reader.readNextShort();
|
||||
exceptionIndexTable = reader.readNextShortArray(numberOfExceptions);
|
||||
exceptionIndexTable = reader.readNextShortArray(getNumberOfExceptions());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,8 +56,8 @@ public class ExceptionsAttribute extends AbstractAttributeInfo {
|
||||
* in the exception_index_table.
|
||||
* @return the number of entries in the exception_index_table
|
||||
*/
|
||||
public short getNumberOfExceptions() {
|
||||
return numberOfExceptions;
|
||||
public int getNumberOfExceptions() {
|
||||
return numberOfExceptions & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,10 +65,11 @@ public class ExceptionsAttribute extends AbstractAttributeInfo {
|
||||
* the constant_pool table. The constant_pool entry referenced by each table
|
||||
* item must be a CONSTANT_Class_info structure representing a class
|
||||
* type that this method is declared to throw.
|
||||
* @return the exception_index_table array
|
||||
* @param i entry
|
||||
* @return index
|
||||
*/
|
||||
public short[] getExceptionIndexTable() {
|
||||
return exceptionIndexTable;
|
||||
public int getExceptionIndexTableEntry(int i) {
|
||||
return exceptionIndexTable[i] & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,14 +15,14 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -44,7 +43,7 @@ public class InnerClass implements StructConverter {
|
||||
private short innerNameIndex;
|
||||
private short innerClassAccessFlags;
|
||||
|
||||
public InnerClass( BinaryReader reader ) throws IOException {
|
||||
public InnerClass(BinaryReader reader) throws IOException {
|
||||
innerClassInfoIndex = reader.readNextShort();
|
||||
outerClassInfoIndex = reader.readNextShort();
|
||||
innerNameIndex = reader.readNextShort();
|
||||
@ -58,8 +57,8 @@ public class InnerClass implements StructConverter {
|
||||
* items in the classes array entry give information about C.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getInnerClassInfoIndex() {
|
||||
return innerClassInfoIndex;
|
||||
public int getInnerClassInfoIndex() {
|
||||
return innerClassInfoIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,8 +73,8 @@ public class InnerClass implements StructConverter {
|
||||
* interface of which C is a member.
|
||||
* @return a valid index into the constant_pool table, or zero
|
||||
*/
|
||||
public short getOuterClassInfoIndex() {
|
||||
return outerClassInfoIndex;
|
||||
public int getOuterClassInfoIndex() {
|
||||
return outerClassInfoIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,8 +87,8 @@ public class InnerClass implements StructConverter {
|
||||
* compiled.
|
||||
* @return a valid index into the constant_pool table, or zero
|
||||
*/
|
||||
public short getInnerNameIndex() {
|
||||
return innerNameIndex;
|
||||
public int getInnerNameIndex() {
|
||||
return innerNameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -107,11 +106,11 @@ public class InnerClass implements StructConverter {
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = new StructureDataType( "inner_class", 0 );
|
||||
structure.add( WORD, "inner_class_info_index", null );
|
||||
structure.add( WORD, "outer_class_info_index", null );
|
||||
structure.add( WORD, "inner_name_index", null );
|
||||
structure.add( WORD, "inner_class_access_flags", null );
|
||||
StructureDataType structure = new StructureDataType("inner_class", 0);
|
||||
structure.add(WORD, "inner_class_info_index", null);
|
||||
structure.add(WORD, "outer_class_info_index", null);
|
||||
structure.add(WORD, "inner_name_index", null);
|
||||
structure.add(WORD, "inner_class_access_flags", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -50,15 +49,15 @@ import java.io.IOException;
|
||||
public class InnerClassesAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short numberOfInnerClasses;
|
||||
private InnerClass [] innerClasses;
|
||||
private InnerClass[] innerClasses;
|
||||
|
||||
public InnerClassesAttribute( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public InnerClassesAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
|
||||
numberOfInnerClasses = reader.readNextShort();
|
||||
innerClasses = new InnerClass[ numberOfInnerClasses ];
|
||||
for ( int i = 0 ; i < numberOfInnerClasses ; i++ ) {
|
||||
innerClasses[ i ] = new InnerClass( reader );
|
||||
innerClasses = new InnerClass[getNumberOfInnerClasses()];
|
||||
for (int i = 0; i < getNumberOfInnerClasses(); i++) {
|
||||
innerClasses[i] = new InnerClass(reader);
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,25 +65,26 @@ public class InnerClassesAttribute extends AbstractAttributeInfo {
|
||||
* The value of the number_of_classes item indicates the number of entries in
|
||||
* the classes array.
|
||||
* @return the number of entries in the classes array
|
||||
*/
|
||||
public short getNumberOfInnerClasses() {
|
||||
return numberOfInnerClasses;
|
||||
*/
|
||||
public int getNumberOfInnerClasses() {
|
||||
return numberOfInnerClasses & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of inner classes.
|
||||
* @return array of inner classes.
|
||||
*/
|
||||
public InnerClass [] getInnerClasses() {
|
||||
public InnerClass[] getInnerClasses() {
|
||||
return innerClasses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = getBaseStructure( "InnerClasses_attribute" + "|" + numberOfInnerClasses + "|" );
|
||||
structure.add( WORD, "number_of_classes", null );
|
||||
for ( int i = 0 ; i < innerClasses.length ; ++i ) {
|
||||
structure.add( innerClasses[ i ].toDataType(), "inner_class_" + i, null );
|
||||
StructureDataType structure =
|
||||
getBaseStructure("InnerClasses_attribute" + "|" + numberOfInnerClasses + "|");
|
||||
structure.add(WORD, "number_of_classes", null);
|
||||
for (int i = 0; i < innerClasses.length; ++i) {
|
||||
structure.add(innerClasses[i].toDataType(), "inner_class_" + i, null);
|
||||
}
|
||||
|
||||
return structure;
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,14 +15,14 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -40,7 +39,7 @@ public class LineNumber implements StructConverter {
|
||||
private short startPC;
|
||||
private short lineNumber;
|
||||
|
||||
public LineNumber( BinaryReader reader ) throws IOException {
|
||||
public LineNumber(BinaryReader reader) throws IOException {
|
||||
startPC = reader.readNextShort();
|
||||
lineNumber = reader.readNextShort();
|
||||
}
|
||||
@ -53,23 +52,23 @@ public class LineNumber implements StructConverter {
|
||||
* item of the Code attribute of which this LineNumberTable is an attribute.
|
||||
* @return index into the code array at which the code for a new line in the original source file begins
|
||||
*/
|
||||
public short getStartPC() {
|
||||
return startPC;
|
||||
public int getStartPC() {
|
||||
return startPC & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of the line_number item must give the corresponding line number in the original source file.
|
||||
* @return the corresponding line number in the original source file
|
||||
*/
|
||||
public short getLineNumber() {
|
||||
return lineNumber;
|
||||
public int getLineNumber() {
|
||||
return lineNumber & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = new StructureDataType( "line_number", 0 );
|
||||
structure.add( WORD, "start_pc", null );
|
||||
structure.add( WORD, "line_number", null );
|
||||
StructureDataType structure = new StructureDataType("line_number", 0);
|
||||
structure.add(WORD, "start_pc", null);
|
||||
structure.add(WORD, "line_number", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -52,25 +51,25 @@ import java.io.IOException;
|
||||
public class LineNumberTableAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short lineNumberTableLength;
|
||||
private LineNumber [] lineNumberTable;
|
||||
private LineNumber[] lineNumberTable;
|
||||
|
||||
public LineNumberTableAttribute( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public LineNumberTableAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
|
||||
lineNumberTableLength = reader.readNextShort();
|
||||
lineNumberTable = new LineNumber[ lineNumberTableLength ];
|
||||
for ( int i = 0 ; i < lineNumberTableLength ; i++ ) {
|
||||
lineNumberTable[ i ] = new LineNumber( reader );
|
||||
lineNumberTable = new LineNumber[lineNumberTableLength & 0xffff];
|
||||
for (int i = 0; i < (lineNumberTableLength & 0xffff); i++) {
|
||||
lineNumberTable[i] = new LineNumber(reader);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "LineNumberTable_attribute" + "|" + lineNumberTableLength + "|";
|
||||
StructureDataType structure = getBaseStructure( name );
|
||||
structure.add( WORD, "line_number_table_length", null );
|
||||
for ( int i = 0 ; i < lineNumberTable.length ; ++i ) {
|
||||
structure.add( lineNumberTable[ i ].toDataType(), "line_number_" + i, null );
|
||||
StructureDataType structure = getBaseStructure(name);
|
||||
structure.add(WORD, "line_number_table_length", null);
|
||||
for (int i = 0; i < lineNumberTable.length; ++i) {
|
||||
structure.add(lineNumberTable[i].toDataType(), "line_number_" + i, null);
|
||||
}
|
||||
return structure;
|
||||
}
|
||||
|
@ -15,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -90,12 +90,12 @@ public class LocalVariableJava implements StructConverter {
|
||||
private short descriptorIndex;
|
||||
private short index;
|
||||
|
||||
public LocalVariableJava( BinaryReader reader ) throws IOException {
|
||||
startPC = reader.readNextShort();
|
||||
length = reader.readNextShort();
|
||||
nameIndex = reader.readNextShort();
|
||||
public LocalVariableJava(BinaryReader reader) throws IOException {
|
||||
startPC = reader.readNextShort();
|
||||
length = reader.readNextShort();
|
||||
nameIndex = reader.readNextShort();
|
||||
descriptorIndex = reader.readNextShort();
|
||||
index = reader.readNextShort();
|
||||
index = reader.readNextShort();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -111,16 +111,16 @@ public class LocalVariableJava implements StructConverter {
|
||||
* or it must be the first index beyond the end of that code array.
|
||||
* @return the start PC
|
||||
*/
|
||||
public short getStartPC() {
|
||||
return startPC;
|
||||
public int getStartPC() {
|
||||
return startPC & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of this local variable in bytes.
|
||||
* @return the length of this local variable in bytes
|
||||
*/
|
||||
public short getLength() {
|
||||
return length;
|
||||
public int getLength() {
|
||||
return length & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,8 +130,8 @@ public class LocalVariableJava implements StructConverter {
|
||||
* name denoting a local variable.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getNameIndex() {
|
||||
return nameIndex;
|
||||
public int getNameIndex() {
|
||||
return nameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -141,8 +141,8 @@ public class LocalVariableJava implements StructConverter {
|
||||
* encoding the type of a local variable in the source program.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getDescriptorIndex() {
|
||||
return descriptorIndex;
|
||||
public int getDescriptorIndex() {
|
||||
return descriptorIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,18 +153,18 @@ public class LocalVariableJava implements StructConverter {
|
||||
* index and index + 1.
|
||||
* @return index in the local variable array
|
||||
*/
|
||||
public short getIndex() {
|
||||
return index;
|
||||
public int getIndex() {
|
||||
return index & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
Structure structure = new StructureDataType( "local_variable", 0 );
|
||||
structure.add( WORD, "start_pc", null );
|
||||
structure.add( WORD, "length", null );
|
||||
structure.add( WORD, "name_index", null );
|
||||
structure.add( WORD, "descriptor_index", null );
|
||||
structure.add( WORD, "index", null );
|
||||
Structure structure = new StructureDataType("local_variable", 0);
|
||||
structure.add(WORD, "start_pc", null);
|
||||
structure.add(WORD, "length", null);
|
||||
structure.add(WORD, "name_index", null);
|
||||
structure.add(WORD, "descriptor_index", null);
|
||||
structure.add(WORD, "index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
@ -15,14 +15,14 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -53,28 +53,29 @@ import java.io.IOException;
|
||||
public class LocalVariableTableAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short localVariableTableLength;
|
||||
private LocalVariableJava [] localVariableTable;
|
||||
private LocalVariableJava[] localVariableTable;
|
||||
|
||||
public LocalVariableTableAttribute( BinaryReader reader, AbstractConstantPoolInfoJava [] constantPool ) throws IOException {
|
||||
super( reader );
|
||||
public LocalVariableTableAttribute(BinaryReader reader,
|
||||
AbstractConstantPoolInfoJava[] constantPool) throws IOException {
|
||||
super(reader);
|
||||
|
||||
localVariableTableLength = reader.readNextShort();
|
||||
localVariableTable = new LocalVariableJava[ localVariableTableLength ];
|
||||
for ( int i = 0 ; i < localVariableTableLength ; i++ ) {
|
||||
localVariableTable[ i ] = new LocalVariableJava( reader );
|
||||
localVariableTable = new LocalVariableJava[localVariableTableLength & 0xffff];
|
||||
for (int i = 0; i < (localVariableTableLength & 0xffff); i++) {
|
||||
localVariableTable[i] = new LocalVariableJava(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public LocalVariableJava [] getLocalVariables() {
|
||||
public LocalVariableJava[] getLocalVariables() {
|
||||
return localVariableTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = getBaseStructure( "LocalVariableTable_attribute" );
|
||||
structure.add( WORD, "local_variable_table_length", null );
|
||||
for ( int i = 0 ; i < localVariableTable.length ; ++i ) {
|
||||
structure.add( localVariableTable[ i ].toDataType(), "local_variable_" + i, null );
|
||||
StructureDataType structure = getBaseStructure("LocalVariableTable_attribute");
|
||||
structure.add(WORD, "local_variable_table_length", null);
|
||||
for (int i = 0; i < localVariableTable.length; ++i) {
|
||||
structure.add(localVariableTable[i].toDataType(), "local_variable_" + i, null);
|
||||
}
|
||||
return structure;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -15,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -52,17 +52,17 @@ import java.io.IOException;
|
||||
public class RuntimeInvisibleAnnotationsAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short numberOfAnnotations;
|
||||
private AnnotationJava [] annotations;
|
||||
private AnnotationJava[] annotations;
|
||||
|
||||
public RuntimeInvisibleAnnotationsAttribute( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public RuntimeInvisibleAnnotationsAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
|
||||
numberOfAnnotations = reader.readNextShort();
|
||||
|
||||
annotations = new AnnotationJava[ numberOfAnnotations ];
|
||||
annotations = new AnnotationJava[getNumberOfAnnotations()];
|
||||
|
||||
for ( int i = 0 ; i < numberOfAnnotations ; ++i ) {
|
||||
annotations[ i ] = new AnnotationJava( reader );
|
||||
for (int i = 0; i < getNumberOfAnnotations(); ++i) {
|
||||
annotations[i] = new AnnotationJava(reader);
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,8 +74,8 @@ public class RuntimeInvisibleAnnotationsAttribute extends AbstractAttributeInfo
|
||||
* may be directly attached to a program element.
|
||||
* @return the number of runtime-visible annotations
|
||||
*/
|
||||
public short getNumberOfAnnotations() {
|
||||
return numberOfAnnotations;
|
||||
public int getNumberOfAnnotations() {
|
||||
return numberOfAnnotations & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,17 +83,17 @@ public class RuntimeInvisibleAnnotationsAttribute extends AbstractAttributeInfo
|
||||
* annotation on a program element.
|
||||
* @return the annotations table
|
||||
*/
|
||||
public AnnotationJava [] getAnnotations() {
|
||||
public AnnotationJava[] getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "RuntimeInvisibleAnnotations_attribute" +"|" + numberOfAnnotations + "|";
|
||||
StructureDataType structure = getBaseStructure( name );
|
||||
structure.add( WORD, "num_annotations", null );
|
||||
for ( int i = 0 ; i < annotations.length ; ++i ) {
|
||||
structure.add( annotations[ i ].toDataType(), "annotation_" + i, null );
|
||||
String name = "RuntimeInvisibleAnnotations_attribute" + "|" + numberOfAnnotations + "|";
|
||||
StructureDataType structure = getBaseStructure(name);
|
||||
structure.add(WORD, "num_annotations", null);
|
||||
for (int i = 0; i < annotations.length; ++i) {
|
||||
structure.add(annotations[i].toDataType(), "annotation_" + i, null);
|
||||
}
|
||||
return structure;
|
||||
}
|
||||
|
@ -15,15 +15,15 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -65,22 +65,24 @@ public class RuntimeParameterAnnotationsAttribute extends AbstractAttributeInfo
|
||||
private boolean _isVisible;
|
||||
|
||||
private byte numberOfParameters;
|
||||
private Map<Integer, AnnotationJava []> parameterAnnotations = new HashMap<Integer, AnnotationJava []>();
|
||||
private Map<Integer, AnnotationJava[]> parameterAnnotations =
|
||||
new HashMap<Integer, AnnotationJava[]>();
|
||||
|
||||
public RuntimeParameterAnnotationsAttribute( BinaryReader reader, boolean isVisible ) throws IOException {
|
||||
super( reader );
|
||||
public RuntimeParameterAnnotationsAttribute(BinaryReader reader, boolean isVisible)
|
||||
throws IOException {
|
||||
super(reader);
|
||||
|
||||
_isVisible = isVisible;
|
||||
|
||||
numberOfParameters = reader.readNextByte();
|
||||
|
||||
for ( int i = 0 ; i < numberOfParameters ; ++i ) {
|
||||
for (int i = 0; i < getNumberOfParameters(); ++i) {
|
||||
short numberOfAnnotations = reader.readNextShort();
|
||||
AnnotationJava [] annotations = new AnnotationJava[ numberOfAnnotations ];
|
||||
for ( int a = 0 ; a < numberOfAnnotations ; ++a ) {
|
||||
annotations[ a ] = new AnnotationJava( reader );
|
||||
AnnotationJava[] annotations = new AnnotationJava[(numberOfAnnotations & 0xffff)];
|
||||
for (int a = 0; a < (numberOfAnnotations & 0xffff); ++a) {
|
||||
annotations[a] = new AnnotationJava(reader);
|
||||
}
|
||||
parameterAnnotations.put( i, annotations );
|
||||
parameterAnnotations.put(i, annotations);
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,8 +102,8 @@ public class RuntimeParameterAnnotationsAttribute extends AbstractAttributeInfo
|
||||
* (This duplicates information that could be extracted from the method descriptor.)
|
||||
* @return the number of parameters for this method
|
||||
*/
|
||||
public byte getNumberOfParameters() {
|
||||
return numberOfParameters;
|
||||
public int getNumberOfParameters() {
|
||||
return numberOfParameters & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,23 +122,23 @@ public class RuntimeParameterAnnotationsAttribute extends AbstractAttributeInfo
|
||||
* @param parameter the parameter index
|
||||
* @return the annotations for the given parameter
|
||||
*/
|
||||
public AnnotationJava [] getParameterAnnotations( int parameter ) {
|
||||
return parameterAnnotations.get( parameter );
|
||||
public AnnotationJava[] getParameterAnnotations(int parameter) {
|
||||
return parameterAnnotations.get(parameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = _isVisible ?
|
||||
"RuntimeVisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|" :
|
||||
"RuntimeInvisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|";
|
||||
String name = _isVisible
|
||||
? "RuntimeVisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|"
|
||||
: "RuntimeInvisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|";
|
||||
|
||||
StructureDataType structure = getBaseStructure( name );
|
||||
structure.add( BYTE, "num_parameters", null );
|
||||
for ( int i = 0 ; i < numberOfParameters ; ++i ) {
|
||||
structure.add( WORD, "num_annotations_" + i, null );
|
||||
AnnotationJava [] annotations = parameterAnnotations.get( i );
|
||||
for ( int a = 0 ; a < annotations.length ; ++a ) {
|
||||
structure.add( annotations[ a ].toDataType(), "annotations_" + i + "_" + a, null );
|
||||
StructureDataType structure = getBaseStructure(name);
|
||||
structure.add(BYTE, "num_parameters", null);
|
||||
for (int i = 0; i < numberOfParameters; ++i) {
|
||||
structure.add(WORD, "num_annotations_" + i, null);
|
||||
AnnotationJava[] annotations = parameterAnnotations.get(i);
|
||||
for (int a = 0; a < annotations.length; ++a) {
|
||||
structure.add(annotations[a].toDataType(), "annotations_" + i + "_" + a, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -45,8 +44,8 @@ public class SignatureAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short signatureIndex;
|
||||
|
||||
public SignatureAttribute( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public SignatureAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
|
||||
signatureIndex = reader.readNextShort();
|
||||
}
|
||||
@ -60,14 +59,14 @@ public class SignatureAttribute extends AbstractAttributeInfo {
|
||||
* type signature otherwise.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getSignatureIndex() {
|
||||
return signatureIndex;
|
||||
public int getSignatureIndex() {
|
||||
return signatureIndex & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = getBaseStructure( "Signature_attribute" );
|
||||
structure.add( WORD, "signature_index", null );
|
||||
StructureDataType structure = getBaseStructure("Signature_attribute");
|
||||
structure.add(WORD, "signature_index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -43,8 +42,8 @@ public class SourceFileAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short sourceFileIndex;
|
||||
|
||||
public SourceFileAttribute( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public SourceFileAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
|
||||
sourceFileIndex = reader.readNextShort();
|
||||
}
|
||||
@ -62,14 +61,14 @@ public class SourceFileAttribute extends AbstractAttributeInfo {
|
||||
* at the time the file name is actually used.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getSourceFileIndex() {
|
||||
return sourceFileIndex;
|
||||
public int getSourceFileIndex() {
|
||||
return sourceFileIndex & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = getBaseStructure( "SourceFile_attribute" );
|
||||
structure.add( WORD, "sourcefile_index", null );
|
||||
StructureDataType structure = getBaseStructure("SourceFile_attribute");
|
||||
structure.add(WORD, "sourcefile_index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
@ -15,11 +15,11 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.constantpool;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -46,7 +46,7 @@ public abstract class AbstractConstantPoolInfoJava implements StructConverter {
|
||||
private long _offset;
|
||||
private byte tag;
|
||||
|
||||
protected AbstractConstantPoolInfoJava( BinaryReader reader ) throws IOException {
|
||||
protected AbstractConstantPoolInfoJava(BinaryReader reader) throws IOException {
|
||||
_offset = reader.getPointerIndex();
|
||||
|
||||
tag = reader.readNextByte();
|
||||
|
@ -15,14 +15,12 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.constantpool;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -56,8 +54,8 @@ public abstract class AbstractConstantPoolReferenceInfo extends AbstractConstant
|
||||
* <p>
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getClassIndex() {
|
||||
return classIndex;
|
||||
public int getClassIndex() {
|
||||
return classIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,17 +75,17 @@ public abstract class AbstractConstantPoolReferenceInfo extends AbstractConstant
|
||||
* <p>
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getNameAndTypeIndex() {
|
||||
return nameAndTypeIndex;
|
||||
public int getNameAndTypeIndex() {
|
||||
return nameAndTypeIndex & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "unnamed";
|
||||
Structure structure = new StructureDataType( name, 0 );
|
||||
structure.add( BYTE, "tag", null );
|
||||
structure.add( WORD, "class_index", null );
|
||||
structure.add( WORD, "name_and_type_index", null );
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
structure.add(BYTE, "tag", null);
|
||||
structure.add(WORD, "class_index", null);
|
||||
structure.add(WORD, "name_and_type_index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
@ -18,9 +18,7 @@ package ghidra.javaclass.format.constantpool;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
@ -47,8 +45,8 @@ public class ConstantPoolClassInfo extends AbstractConstantPoolInfoJava {
|
||||
|
||||
private short nameIndex;
|
||||
|
||||
public ConstantPoolClassInfo( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public ConstantPoolClassInfo(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
|
||||
nameIndex = reader.readNextShort();
|
||||
}
|
||||
@ -60,16 +58,16 @@ public class ConstantPoolClassInfo extends AbstractConstantPoolInfoJava {
|
||||
* interface name encoded in internal form (?4.2.1).
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getNameIndex() {
|
||||
return nameIndex;
|
||||
public int getNameIndex() {
|
||||
return nameIndex & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "CONSTANT_Class_info";
|
||||
Structure structure = new StructureDataType( name, 0 );
|
||||
structure.add( BYTE, "tag", null );
|
||||
structure.add( WORD, "name_index", null );
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
structure.add(BYTE, "tag", null);
|
||||
structure.add(WORD, "name_index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -15,62 +15,74 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.constantpool;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
|
||||
public class ConstantPoolFactory {
|
||||
|
||||
public static AbstractConstantPoolInfoJava get( BinaryReader reader ) throws IOException {
|
||||
public static AbstractConstantPoolInfoJava get(BinaryReader reader) throws IOException {
|
||||
|
||||
switch ( reader.peekNextByte() ) {
|
||||
switch (reader.peekNextByte()) {
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_Class:
|
||||
return new ConstantPoolClassInfo( reader );
|
||||
return new ConstantPoolClassInfo(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_Double:
|
||||
return new ConstantPoolDoubleInfo( reader );
|
||||
return new ConstantPoolDoubleInfo(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_Fieldref:
|
||||
return new ConstantPoolFieldReferenceInfo( reader );
|
||||
return new ConstantPoolFieldReferenceInfo(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_Float:
|
||||
return new ConstantPoolFloatInfo( reader );
|
||||
return new ConstantPoolFloatInfo(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_Integer:
|
||||
return new ConstantPoolIntegerInfo( reader );
|
||||
return new ConstantPoolIntegerInfo(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_InterfaceMethodref:
|
||||
return new ConstantPoolInterfaceMethodReferenceInfo( reader );
|
||||
return new ConstantPoolInterfaceMethodReferenceInfo(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_InvokeDynamic:
|
||||
return new ConstantPoolInvokeDynamicInfo( reader );
|
||||
return new ConstantPoolInvokeDynamicInfo(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_Long:
|
||||
return new ConstantPoolLongInfo( reader );
|
||||
return new ConstantPoolLongInfo(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_MethodHandle:
|
||||
return new ConstantPoolMethodHandleInfo( reader );
|
||||
return new ConstantPoolMethodHandleInfo(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_Methodref:
|
||||
return new ConstantPoolMethodReferenceInfo( reader );
|
||||
return new ConstantPoolMethodReferenceInfo(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_MethodType:
|
||||
return new ConstantPoolMethodTypeInfo( reader );
|
||||
return new ConstantPoolMethodTypeInfo(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_NameAndType:
|
||||
return new ConstantPoolNameAndTypeInfo( reader );
|
||||
return new ConstantPoolNameAndTypeInfo(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_String:
|
||||
return new ConstantPoolStringInfo( reader );
|
||||
return new ConstantPoolStringInfo(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_Utf8:
|
||||
return new ConstantPoolUtf8Info( reader );
|
||||
return new ConstantPoolUtf8Info(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_Dynamic:
|
||||
return new ConstantPoolDynamicInfo(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_Module:
|
||||
return new ConstantPoolModuleInfo(reader);
|
||||
|
||||
case ConstantPoolTagsJava.CONSTANT_Package:
|
||||
return new ConstantPoolPackageInfo(reader);
|
||||
|
||||
case 0:
|
||||
return null;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupport Constant Pool Entry Type: " + reader.peekNextByte());
|
||||
}
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,19 +15,17 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.constantpool;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
* The CONSTANT_InvokeDynamic_info structure is used by an invokedynamic
|
||||
* instruction (?invokedynamic) to specify a bootstrap method, the dynamic
|
||||
* instruction to specify a bootstrap method, the dynamic
|
||||
* invocation name, the argument and return types of the call, and optionally, a
|
||||
* sequence of additional constants called static arguments to the bootstrap method.
|
||||
* <pre>
|
||||
@ -43,8 +41,8 @@ public class ConstantPoolInvokeDynamicInfo extends AbstractConstantPoolInfoJava
|
||||
private short bootstrapMethodAttrIndex;
|
||||
private short nameAndTypeIndex;
|
||||
|
||||
public ConstantPoolInvokeDynamicInfo( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public ConstantPoolInvokeDynamicInfo(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
bootstrapMethodAttrIndex = reader.readNextShort();
|
||||
nameAndTypeIndex = reader.readNextShort();
|
||||
}
|
||||
@ -55,8 +53,8 @@ public class ConstantPoolInvokeDynamicInfo extends AbstractConstantPoolInfoJava
|
||||
* this class file.
|
||||
* @return a valid index into the bootstrap_methods array
|
||||
*/
|
||||
public short getBootstrapMethodAttrIndex() {
|
||||
return bootstrapMethodAttrIndex;
|
||||
public int getBootstrapMethodAttrIndex() {
|
||||
return bootstrapMethodAttrIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,17 +64,17 @@ public class ConstantPoolInvokeDynamicInfo extends AbstractConstantPoolInfoJava
|
||||
* and method descriptor.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getNameAndTypeIndex() {
|
||||
return nameAndTypeIndex;
|
||||
public int getNameAndTypeIndex() {
|
||||
return nameAndTypeIndex & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "CONSTANT_InvokeDynamic_info";
|
||||
Structure structure = new StructureDataType( name, 0 );
|
||||
structure.add( BYTE, "tag", null );
|
||||
structure.add( WORD, "bootstrap_method_attr_index", null );
|
||||
structure.add( WORD, "name_and_type_index", null );
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
structure.add(BYTE, "tag", null);
|
||||
structure.add(WORD, "bootstrap_method_attr_index", null);
|
||||
structure.add(WORD, "name_and_type_index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
@ -15,14 +15,11 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.constantpool;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
@ -37,12 +34,12 @@ import java.io.IOException;
|
||||
* </pre>
|
||||
*/
|
||||
public class ConstantPoolMethodHandleInfo extends AbstractConstantPoolInfoJava {
|
||||
|
||||
private byte referenceKind;
|
||||
private int referenceIndex;
|
||||
|
||||
public ConstantPoolMethodHandleInfo( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
private byte referenceKind;
|
||||
private short referenceIndex;
|
||||
|
||||
public ConstantPoolMethodHandleInfo(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
referenceKind = reader.readNextByte();
|
||||
referenceIndex = reader.readNextShort();
|
||||
}
|
||||
@ -101,16 +98,16 @@ public class ConstantPoolMethodHandleInfo extends AbstractConstantPoolInfoJava {
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public int getReferenceIndex() {
|
||||
return referenceIndex;
|
||||
return referenceIndex & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "CONSTANT_MethodHandle_info";
|
||||
Structure structure = new StructureDataType( name, 0 );
|
||||
structure.add( BYTE, "tag", null );
|
||||
structure.add( BYTE, "reference_kind", null );
|
||||
structure.add( WORD, "reference_index", null );
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
structure.add(BYTE, "tag", null);
|
||||
structure.add(BYTE, "reference_kind", null);
|
||||
structure.add(WORD, "reference_index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
@ -18,9 +18,7 @@ package ghidra.javaclass.format.constantpool;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
@ -38,8 +36,8 @@ public class ConstantPoolMethodTypeInfo extends AbstractConstantPoolInfoJava {
|
||||
|
||||
private short descriptorIndex;
|
||||
|
||||
public ConstantPoolMethodTypeInfo( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public ConstantPoolMethodTypeInfo(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
descriptorIndex = reader.readNextShort();
|
||||
}
|
||||
|
||||
@ -49,16 +47,16 @@ public class ConstantPoolMethodTypeInfo extends AbstractConstantPoolInfoJava {
|
||||
* CONSTANT_Utf8_info structure representing a method descriptor.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getDescriptorIndex() {
|
||||
return descriptorIndex;
|
||||
public int getDescriptorIndex() {
|
||||
return descriptorIndex & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "CONSTANT_MethodType_info";
|
||||
Structure structure = new StructureDataType( name, 0 );
|
||||
structure.add( BYTE, "tag", null );
|
||||
structure.add( WORD, "descriptor_index", null );
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
structure.add(BYTE, "tag", null);
|
||||
structure.add(WORD, "descriptor_index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -15,14 +15,12 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.constantpool;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@ -41,8 +39,8 @@ public class ConstantPoolNameAndTypeInfo extends AbstractConstantPoolInfoJava {
|
||||
private short nameIndex;
|
||||
private short descriptorIndex;
|
||||
|
||||
public ConstantPoolNameAndTypeInfo( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public ConstantPoolNameAndTypeInfo(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
nameIndex = reader.readNextShort();
|
||||
descriptorIndex = reader.readNextShort();
|
||||
}
|
||||
@ -55,8 +53,8 @@ public class ConstantPoolNameAndTypeInfo extends AbstractConstantPoolInfoJava {
|
||||
* method.
|
||||
* @return a valid index into the constant_pool table to the name
|
||||
*/
|
||||
public short getNameIndex() {
|
||||
return nameIndex;
|
||||
public int getNameIndex() {
|
||||
return nameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,17 +64,17 @@ public class ConstantPoolNameAndTypeInfo extends AbstractConstantPoolInfoJava {
|
||||
* or method descriptor.
|
||||
* @return a valid index into the constant_pool table to the descriptor
|
||||
*/
|
||||
public short getDescriptorIndex() {
|
||||
return descriptorIndex;
|
||||
public int getDescriptorIndex() {
|
||||
return descriptorIndex & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "CONSTANT_NameAndType_info";
|
||||
Structure structure = new StructureDataType( name, 0 );
|
||||
structure.add( BYTE, "tag", null );
|
||||
structure.add( WORD, "name_index", null );
|
||||
structure.add( WORD, "descriptor_index", null );
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
structure.add(BYTE, "tag", null);
|
||||
structure.add(WORD, "name_index", null);
|
||||
structure.add(WORD, "descriptor_index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -18,9 +18,7 @@ package ghidra.javaclass.format.constantpool;
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
@ -39,7 +37,7 @@ public class ConstantPoolStringInfo extends AbstractConstantPoolInfoJava {
|
||||
|
||||
private short stringIndex;
|
||||
|
||||
public ConstantPoolStringInfo( BinaryReader reader ) throws IOException {
|
||||
public ConstantPoolStringInfo(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
stringIndex = reader.readNextShort();
|
||||
}
|
||||
@ -51,16 +49,16 @@ public class ConstantPoolStringInfo extends AbstractConstantPoolInfoJava {
|
||||
* code points to which the String object is to be initialized.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getStringIndex() {
|
||||
return stringIndex;
|
||||
public int getStringIndex() {
|
||||
return stringIndex & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "CONSTANT_String_info";
|
||||
Structure structure = new StructureDataType( name, 0 );
|
||||
structure.add( BYTE, "tag", null );
|
||||
structure.add( WORD, "string_index", null );
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
structure.add(BYTE, "tag", null);
|
||||
structure.add(WORD, "string_index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
@ -17,19 +17,22 @@ package ghidra.javaclass.format.constantpool;
|
||||
|
||||
public final class ConstantPoolTagsJava {
|
||||
|
||||
public final static byte CONSTANT_Class = 7;
|
||||
public final static byte CONSTANT_Fieldref = 9;
|
||||
public final static byte CONSTANT_Methodref = 10;
|
||||
public final static byte CONSTANT_InterfaceMethodref = 11;
|
||||
public final static byte CONSTANT_String = 8;
|
||||
public final static byte CONSTANT_Integer = 3;
|
||||
public final static byte CONSTANT_Float = 4;
|
||||
public final static byte CONSTANT_Long = 5;
|
||||
public final static byte CONSTANT_Double = 6;
|
||||
public final static byte CONSTANT_NameAndType = 12;
|
||||
public final static byte CONSTANT_Utf8 = 1;
|
||||
public final static byte CONSTANT_MethodHandle = 15;
|
||||
public final static byte CONSTANT_MethodType = 16;
|
||||
public final static byte CONSTANT_InvokeDynamic = 18;
|
||||
public final static byte CONSTANT_Class = 7;
|
||||
public final static byte CONSTANT_Fieldref = 9;
|
||||
public final static byte CONSTANT_Methodref = 10;
|
||||
public final static byte CONSTANT_InterfaceMethodref = 11;
|
||||
public final static byte CONSTANT_String = 8;
|
||||
public final static byte CONSTANT_Integer = 3;
|
||||
public final static byte CONSTANT_Float = 4;
|
||||
public final static byte CONSTANT_Long = 5;
|
||||
public final static byte CONSTANT_Double = 6;
|
||||
public final static byte CONSTANT_NameAndType = 12;
|
||||
public final static byte CONSTANT_Utf8 = 1;
|
||||
public final static byte CONSTANT_MethodHandle = 15;
|
||||
public final static byte CONSTANT_MethodType = 16;
|
||||
public final static byte CONSTANT_Dynamic = 17;
|
||||
public final static byte CONSTANT_InvokeDynamic = 18;
|
||||
public final static byte CONSTANT_Module = 19;
|
||||
public final static byte CONSTANT_Package = 20;
|
||||
|
||||
}
|
||||
|
@ -41,12 +41,12 @@ import ghidra.util.exception.DuplicateNameException;
|
||||
public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
|
||||
|
||||
private short length;
|
||||
private byte [] bytes;
|
||||
private byte[] bytes;
|
||||
|
||||
public ConstantPoolUtf8Info( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public ConstantPoolUtf8Info(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
length = reader.readNextShort();
|
||||
bytes = reader.readNextByteArray( length );
|
||||
bytes = reader.readNextByteArray(getLength());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,8 +55,8 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
|
||||
* structure are not null-terminated.
|
||||
* @return the number of bytes in the bytes array
|
||||
*/
|
||||
public short getLength() {
|
||||
return length;
|
||||
public int getLength() {
|
||||
return length & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -65,7 +65,7 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
|
||||
* range (byte)0xf0 - (byte)0xff.
|
||||
* @return the bytes of the string
|
||||
*/
|
||||
public byte [] getBytes() {
|
||||
public byte[] getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
|
||||
* @return the byte array translated into a string
|
||||
*/
|
||||
public String getString() {
|
||||
return new String( bytes );
|
||||
return new String(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -86,10 +86,10 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "CONSTANT_Utf8_info" + "|" + length + "|";
|
||||
Structure structure = new StructureDataType( name, 0 );
|
||||
structure.add( BYTE, "tag", null );
|
||||
structure.add( WORD, "length", null );
|
||||
if ( length > 0 ) {
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
structure.add(BYTE, "tag", null);
|
||||
structure.add(WORD, "length", null);
|
||||
if (length > 0) {
|
||||
structure.add(UTF8, length, "data", null);
|
||||
}
|
||||
return structure;
|
||||
|
@ -28,9 +28,8 @@ import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
|
||||
|
||||
public class InvokeMethodsTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void testEmitPcodeToResolveMethodReferenceInvokeDynamic() throws IOException{
|
||||
public void testEmitPcodeToResolveMethodReferenceInvokeDynamic() throws IOException {
|
||||
short bootstrap = 0;
|
||||
ArrayList<Byte> classFile = new ArrayList<>();
|
||||
TestClassFileCreator.appendMagic(classFile);
|
||||
@ -39,151 +38,173 @@ public class InvokeMethodsTest {
|
||||
TestClassFileCreator.appendInvokeDynamicInfo(classFile, bootstrap, (short) 2); //1
|
||||
TestClassFileCreator.appendNameAndType(classFile, (short) 3, (short) 4); //2
|
||||
TestClassFileCreator.appendUtf8(classFile, "dynamicMethodName"); //3
|
||||
TestClassFileCreator.appendUtf8(classFile,"(I)I"); //4 (descriptor)
|
||||
TestClassFileCreator.appendUtf8(classFile, "(I)I"); //4 (descriptor)
|
||||
|
||||
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
|
||||
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
AbstractConstantPoolInfoJava[] constantPool =
|
||||
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
|
||||
|
||||
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
|
||||
JavaInvocationType.INVOKE_DYNAMIC);
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
|
||||
assertEquals("incorrect pcode for dynamic invocation", expected.toString(), pCode.toString());
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
|
||||
ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
|
||||
assertEquals("incorrect pcode for dynamic invocation", expected.toString(),
|
||||
pCode.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEmitPcodeToResolveMethodReferenceInvokeInterface() throws IOException{
|
||||
public void testEmitPcodeToResolveMethodReferenceInvokeInterface() throws IOException {
|
||||
ArrayList<Byte> classFile = new ArrayList<>();
|
||||
TestClassFileCreator.appendMagic(classFile);
|
||||
TestClassFileCreator.appendVersions(classFile);
|
||||
TestClassFileCreator.appendCount(classFile, (short) 7);
|
||||
TestClassFileCreator.appendInterfaceMethodRef(classFile, (short) 2, (short)3); //1
|
||||
TestClassFileCreator.appendInterfaceMethodRef(classFile, (short) 2, (short) 3); //1
|
||||
TestClassFileCreator.appendClass(classFile, (short) 4); //2
|
||||
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
|
||||
TestClassFileCreator.appendUtf8(classFile, "className"); //4
|
||||
TestClassFileCreator.appendUtf8(classFile, "interfaceMethodName"); //5
|
||||
TestClassFileCreator.appendUtf8(classFile,"(I)I"); //6 (descriptor)
|
||||
TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor)
|
||||
|
||||
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
|
||||
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
AbstractConstantPoolInfoJava[] constantPool =
|
||||
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_INTERFACE);
|
||||
|
||||
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
|
||||
JavaInvocationType.INVOKE_INTERFACE);
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1", ConstantPoolJava.CPOOL_INVOKEINTERFACE);
|
||||
assertEquals("incorrect pcode for interface method invocation", expected.toString(), pCode.toString());
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
|
||||
ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1",
|
||||
ConstantPoolJava.CPOOL_INVOKEINTERFACE);
|
||||
assertEquals("incorrect pcode for interface method invocation", expected.toString(),
|
||||
pCode.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEmitPcodeToResolveMethodReferenceInvokeSpecial() throws IOException{
|
||||
public void testEmitPcodeToResolveMethodReferenceInvokeSpecial() throws IOException {
|
||||
ArrayList<Byte> classFile = new ArrayList<>();
|
||||
TestClassFileCreator.appendMagic(classFile);
|
||||
TestClassFileCreator.appendVersions(classFile);
|
||||
TestClassFileCreator.appendCount(classFile, (short) 7);
|
||||
TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short)3); //1
|
||||
TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short) 3); //1
|
||||
TestClassFileCreator.appendClass(classFile, (short) 4); //2
|
||||
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
|
||||
TestClassFileCreator.appendUtf8(classFile, "className"); //4
|
||||
TestClassFileCreator.appendUtf8(classFile, "methodName"); //5
|
||||
TestClassFileCreator.appendUtf8(classFile,"(I)I"); //6 (descriptor)
|
||||
TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor)
|
||||
|
||||
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
|
||||
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
AbstractConstantPoolInfoJava[] constantPool =
|
||||
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_SPECIAL);
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1", ConstantPoolJava.CPOOL_INVOKESPECIAL);
|
||||
assertEquals("incorrect pcode for special method invocation", expected.toString(), pCode.toString());
|
||||
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
|
||||
JavaInvocationType.INVOKE_SPECIAL);
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
|
||||
ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1",
|
||||
ConstantPoolJava.CPOOL_INVOKESPECIAL);
|
||||
assertEquals("incorrect pcode for special method invocation", expected.toString(),
|
||||
pCode.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEmitPcodeToResolveMethodReferenceInvokeStatic() throws IOException{
|
||||
public void testEmitPcodeToResolveMethodReferenceInvokeStatic() throws IOException {
|
||||
ArrayList<Byte> classFile = new ArrayList<>();
|
||||
TestClassFileCreator.appendMagic(classFile);
|
||||
TestClassFileCreator.appendVersions(classFile);
|
||||
TestClassFileCreator.appendCount(classFile, (short) 7);
|
||||
TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short)3); //1
|
||||
TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short) 3); //1
|
||||
TestClassFileCreator.appendClass(classFile, (short) 4); //2
|
||||
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
|
||||
TestClassFileCreator.appendUtf8(classFile, "className"); //4
|
||||
TestClassFileCreator.appendUtf8(classFile, "methodName"); //5
|
||||
TestClassFileCreator.appendUtf8(classFile,"(I)I"); //6 (descriptor)
|
||||
TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor)
|
||||
|
||||
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
|
||||
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
AbstractConstantPoolInfoJava[] constantPool =
|
||||
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_STATIC);
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKESTATIC);
|
||||
assertEquals("incorrect pcode for static method invocation", expected.toString(), pCode.toString());
|
||||
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
|
||||
JavaInvocationType.INVOKE_STATIC);
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
|
||||
ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKESTATIC);
|
||||
assertEquals("incorrect pcode for static method invocation", expected.toString(),
|
||||
pCode.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEmitPcodeToResolveMethodReferenceInvokeVirtual() throws IOException{
|
||||
public void testEmitPcodeToResolveMethodReferenceInvokeVirtual() throws IOException {
|
||||
ArrayList<Byte> classFile = new ArrayList<>();
|
||||
TestClassFileCreator.appendMagic(classFile);
|
||||
TestClassFileCreator.appendVersions(classFile);
|
||||
TestClassFileCreator.appendCount(classFile, (short) 7);
|
||||
TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short)3); //1
|
||||
TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short) 3); //1
|
||||
TestClassFileCreator.appendClass(classFile, (short) 4); //2
|
||||
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
|
||||
TestClassFileCreator.appendUtf8(classFile, "className"); //4
|
||||
TestClassFileCreator.appendUtf8(classFile, "methodName"); //5
|
||||
TestClassFileCreator.appendUtf8(classFile,"(I)I"); //6 (descriptor)
|
||||
TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor)
|
||||
|
||||
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
|
||||
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
AbstractConstantPoolInfoJava[] constantPool =
|
||||
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_VIRTUAL);
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1", ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
|
||||
assertEquals("incorrect pcode for static method invocation", expected.toString(), pCode.toString());
|
||||
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
|
||||
JavaInvocationType.INVOKE_VIRTUAL);
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
|
||||
ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1",
|
||||
ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
|
||||
assertEquals("incorrect pcode for static method invocation", expected.toString(),
|
||||
pCode.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEmitPcodeToReverseStackNoParamsNoThis(){
|
||||
public void testEmitPcodeToReverseStackNoParamsNoThis() {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
//InvokeMethods.emitPcodeToReverseStack(pCode, new ArrayList<JavaComputationalCategory>(), false);
|
||||
StringBuilder expected = new StringBuilder();
|
||||
assertEquals("incorrect pcode reversing stack: no params no this", expected.toString(), pCode.toString());
|
||||
assertEquals("incorrect pcode reversing stack: no params no this", expected.toString(),
|
||||
pCode.toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//test bad category
|
||||
|
||||
|
||||
@Test
|
||||
public void testGetPcodeForInvoke() throws IOException{
|
||||
public void testGetPcodeForInvoke() throws IOException {
|
||||
ArrayList<Byte> classFile = new ArrayList<>();
|
||||
TestClassFileCreator.appendMagic(classFile);
|
||||
TestClassFileCreator.appendVersions(classFile);
|
||||
TestClassFileCreator.appendCount(classFile, (short) 5);
|
||||
TestClassFileCreator.appendInvokeDynamicInfo(classFile, (short) 0, (short)2); //1
|
||||
TestClassFileCreator.appendInvokeDynamicInfo(classFile, (short) 0, (short) 2); //1
|
||||
TestClassFileCreator.appendNameAndType(classFile, (short) 3, (short) 4); //2
|
||||
TestClassFileCreator.appendUtf8(classFile, "dynamicMethodName"); //3
|
||||
TestClassFileCreator.appendUtf8(classFile,"(JJII)I"); //4 (descriptor)
|
||||
TestClassFileCreator.appendUtf8(classFile, "(JJII)I"); //4 (descriptor)
|
||||
|
||||
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
|
||||
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
String pCode = InvokeMethods.getPcodeForInvoke(1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
|
||||
|
||||
AbstractConstantPoolInfoJava[] constantPool =
|
||||
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
String pCode =
|
||||
InvokeMethods.getPcodeForInvoke(1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
String descriptor = DescriptorDecoder.getDescriptorForInvoke(1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
|
||||
List<JavaComputationalCategory> categories = DescriptorDecoder.getParameterCategories(descriptor);
|
||||
String descriptor = DescriptorDecoder.getDescriptorForInvoke(1, constantPool,
|
||||
JavaInvocationType.INVOKE_DYNAMIC);
|
||||
List<JavaComputationalCategory> categories =
|
||||
DescriptorDecoder.getParameterCategories(descriptor);
|
||||
|
||||
InvokeMethods.emitPcodeToMoveParams(expected, categories, false, 24);
|
||||
InvokeMethods.emitPcodeToResolveMethodReference(expected, 1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
|
||||
PcodeTextEmitter.emitIndirectCall(expected, InvokeMethods.CALL_TARGET);
|
||||
PcodeTextEmitter.emitPushCat1Value(expected, InvokeMethods.CAT_1_RETURN);
|
||||
System.out.println(pCode);
|
||||
System.out.println(expected);
|
||||
|
||||
|
||||
InvokeMethods.emitPcodeToResolveMethodReference(expected, 1, constantPool,
|
||||
JavaInvocationType.INVOKE_DYNAMIC);
|
||||
PcodeTextEmitter.emitIndirectCall(expected, InvokeMethods.CALL_TARGET);
|
||||
PcodeTextEmitter.emitPushCat1Value(expected, InvokeMethods.CAT_1_RETURN);
|
||||
|
||||
assertEquals("incorrect pcode for invoke dynamic: (JJII)I", expected.toString(), pCode);
|
||||
|
||||
}
|
||||
|
@ -22,35 +22,35 @@ import org.junit.Test;
|
||||
public class PcodeTextEmitterTest {
|
||||
|
||||
@Test
|
||||
public void testEmitPushType1Value(){
|
||||
public void testEmitPushType1Value() {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, "x");
|
||||
assertTrue(pCode.toString().equals("SP = SP - 4;\n*:4 SP = x;\n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmitPushType2Value(){
|
||||
public void testEmitPushType2Value() {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitPushCat2Value(pCode, "x");
|
||||
assertTrue(pCode.toString().equals("SP = SP - 8;\n*:8 SP = x;\n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmitPopType1Value(){
|
||||
public void testEmitPopType1Value() {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, "x");
|
||||
assertTrue(pCode.toString().equals("x:4 = *:4 SP;\nSP = SP + 4;\n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmitPopType2Value(){
|
||||
public void testEmitPopType2Value() {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitPopCat2Value(pCode, "x");
|
||||
assertTrue(pCode.toString().equals("x:8 = *:8 SP;\nSP = SP + 8;\n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmitVarnodeBytesFromPcodeOpCall(){
|
||||
@Test
|
||||
public void testEmitVarnodeBytesFromPcodeOpCall() {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
|
||||
//test no args
|
||||
@ -64,9 +64,9 @@ public class PcodeTextEmitterTest {
|
||||
|
||||
//two args
|
||||
pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 4, "PCODEOP", "ARG1", "ARG2");
|
||||
assertTrue(pCode.toString().equals("LHS:4 = PCODEOP(ARG1,ARG2);\n"));
|
||||
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 4, "PCODEOP", "ARG1",
|
||||
"ARG2");
|
||||
assertTrue(pCode.toString().equals("LHS:4 = PCODEOP(ARG1,ARG2);\n"));
|
||||
|
||||
//test no args
|
||||
pCode = new StringBuilder();
|
||||
@ -80,12 +80,13 @@ public class PcodeTextEmitterTest {
|
||||
|
||||
//two args
|
||||
pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 8, "PCODEOP", "ARG1", "ARG2");
|
||||
assertTrue(pCode.toString().equals("LHS:8 = PCODEOP(ARG1,ARG2);\n"));
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 8, "PCODEOP", "ARG1",
|
||||
"ARG2");
|
||||
assertTrue(pCode.toString().equals("LHS:8 = PCODEOP(ARG1,ARG2);\n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmitVoidPcodeOpCall(){
|
||||
@Test
|
||||
public void testEmitVoidPcodeOpCall() {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
|
||||
//test no args
|
||||
@ -94,17 +95,17 @@ public class PcodeTextEmitterTest {
|
||||
|
||||
//one arg
|
||||
pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitVoidPcodeOpCall(pCode,"PCODEOP", "ARG1");
|
||||
PcodeTextEmitter.emitVoidPcodeOpCall(pCode, "PCODEOP", "ARG1");
|
||||
assertTrue(pCode.toString().equals("PCODEOP(ARG1);\n"));
|
||||
|
||||
//two args
|
||||
pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitVoidPcodeOpCall(pCode,"PCODEOP", "ARG1", "ARG2");
|
||||
assertTrue(pCode.toString().equals("PCODEOP(ARG1,ARG2);\n"));
|
||||
PcodeTextEmitter.emitVoidPcodeOpCall(pCode, "PCODEOP", "ARG1", "ARG2");
|
||||
assertTrue(pCode.toString().equals("PCODEOP(ARG1,ARG2);\n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmitAssignRegisterFromPcodeOpCall(){
|
||||
public void testEmitAssignRegisterFromPcodeOpCall() {
|
||||
//void call
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, "REG", "TEST");
|
||||
@ -122,38 +123,59 @@ public class PcodeTextEmitterTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmitAssignConstantToRegister(){
|
||||
public void testEmitAssignConstantToRegister() {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitAssignConstantToRegister(pCode, "REGISTER", 0);
|
||||
assertTrue(pCode.toString().equals("REGISTER = 0x0;\n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmitLabelDef(){
|
||||
public void testEmitLabelDef() {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitLabelDefinition(pCode, "LABEL");
|
||||
assertEquals("bad label definition emitted", "<LABEL>\n", pCode.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmitAddToStackPointer(){
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitAddToStackPointer(pCode, 4);
|
||||
assertEquals("SP = SP + 4;\n", pCode.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmitIndirectCall(){
|
||||
public void testEmitIndirectCall() {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitIndirectCall(pCode, "call_target");
|
||||
assertEquals("call [call_target];\n", pCode.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmitWriteToMemory(){
|
||||
public void testEmitWriteToMemory() {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, "ram", 4, "offset", "test");
|
||||
assertEquals("*[ram]:4 offset = test;\n", pCode.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmitSignExtension() {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitSignExtension(pCode, "dest", 4, "src");
|
||||
assertEquals("dest:4 = sext(src);\n", pCode.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmitZeroExtension() {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, "dest", 4, "src");
|
||||
assertEquals("dest:4 = zext(src);\n", pCode.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmitTruncate() {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitTruncate(pCode, "dest", 4, "src");
|
||||
assertEquals("dest = src:4;\n", pCode.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssignVarnodeFromDereference() {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, "dest", 4, "src");
|
||||
assertEquals("dest:4 = *:4 src;\n", pCode.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,8 +15,7 @@
|
||||
*/
|
||||
package ghidra.app.util.pcodeInject;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@ -26,36 +25,37 @@ import org.junit.Test;
|
||||
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
|
||||
|
||||
public class ReferenceMethodsTest {
|
||||
|
||||
|
||||
|
||||
public ReferenceMethodsTest(){
|
||||
|
||||
public ReferenceMethodsTest() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGetStatic1() throws IOException {
|
||||
ArrayList<Byte> classFile = new ArrayList<>();
|
||||
TestClassFileCreator.appendMagic(classFile);
|
||||
TestClassFileCreator.appendVersions(classFile);
|
||||
TestClassFileCreator.appendCount(classFile, (short) 7);
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
|
||||
TestClassFileCreator.appendClass(classFile, (short) 4); //2
|
||||
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
|
||||
TestClassFileCreator.appendUtf8(classFile, "className"); //4
|
||||
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
|
||||
TestClassFileCreator.appendUtf8(classFile,"I"); //6 (descriptor)
|
||||
|
||||
TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
|
||||
|
||||
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
|
||||
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
AbstractConstantPoolInfoJava[] constantPool =
|
||||
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
String pCode = ReferenceMethods.getPcodeForGetStatic(1, constantPool);
|
||||
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.VALUE, 4, ConstantPoolJava.CPOOL_OP , "0", "1", ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.TEMP_1, 4,
|
||||
ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(expected, ReferenceMethods.VALUE, 4,
|
||||
ReferenceMethods.TEMP_1);
|
||||
PcodeTextEmitter.emitPushCat1Value(expected, ReferenceMethods.VALUE);
|
||||
assertTrue(pCode.equals(expected.toString()));
|
||||
|
||||
|
||||
assertTrue(pCode.equals(expected.toString()));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -64,180 +64,204 @@ public class ReferenceMethodsTest {
|
||||
TestClassFileCreator.appendMagic(classFile);
|
||||
TestClassFileCreator.appendVersions(classFile);
|
||||
TestClassFileCreator.appendCount(classFile, (short) 7);
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
|
||||
TestClassFileCreator.appendClass(classFile, (short) 4); //2
|
||||
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
|
||||
TestClassFileCreator.appendUtf8(classFile, "className"); //4
|
||||
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
|
||||
TestClassFileCreator.appendUtf8(classFile,"J"); //6 (descriptor)
|
||||
|
||||
TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
|
||||
|
||||
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
|
||||
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
AbstractConstantPoolInfoJava[] constantPool =
|
||||
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
String pCode = ReferenceMethods.getPcodeForGetStatic(1, constantPool);
|
||||
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.VALUE, 8, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.TEMP_1, 8,
|
||||
ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(expected, ReferenceMethods.VALUE, 8,
|
||||
ReferenceMethods.TEMP_1);
|
||||
PcodeTextEmitter.emitPushCat2Value(expected, ReferenceMethods.VALUE);
|
||||
|
||||
assertEquals(pCode,expected.toString());
|
||||
|
||||
assertEquals(pCode, expected.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPutStatic1() throws IOException {
|
||||
ArrayList<Byte> classFile = new ArrayList<>();
|
||||
TestClassFileCreator.appendMagic(classFile);
|
||||
TestClassFileCreator.appendVersions(classFile);
|
||||
TestClassFileCreator.appendCount(classFile, (short) 7);
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
|
||||
TestClassFileCreator.appendClass(classFile, (short) 4); //2
|
||||
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
|
||||
TestClassFileCreator.appendUtf8(classFile, "className"); //4
|
||||
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
|
||||
TestClassFileCreator.appendUtf8(classFile,"I"); //6 (descriptor)
|
||||
|
||||
TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
|
||||
|
||||
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
|
||||
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
AbstractConstantPoolInfoJava[] constantPool =
|
||||
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
String pCode = ReferenceMethods.getPcodeForPutStatic(1, constantPool);
|
||||
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 4, ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE);
|
||||
assertEquals(pCode,expected.toString());
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET,
|
||||
4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 4,
|
||||
ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE);
|
||||
assertEquals(pCode, expected.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPutStatic2() throws IOException {
|
||||
ArrayList<Byte> classFile = new ArrayList<>();
|
||||
TestClassFileCreator.appendMagic(classFile);
|
||||
TestClassFileCreator.appendVersions(classFile);
|
||||
TestClassFileCreator.appendCount(classFile, (short) 7);
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
|
||||
TestClassFileCreator.appendClass(classFile, (short) 4); //2
|
||||
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
|
||||
TestClassFileCreator.appendUtf8(classFile, "className"); //4
|
||||
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
|
||||
TestClassFileCreator.appendUtf8(classFile,"J"); //6 (descriptor)
|
||||
|
||||
TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
|
||||
|
||||
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
|
||||
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
AbstractConstantPoolInfoJava[] constantPool =
|
||||
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
String pCode = ReferenceMethods.getPcodeForPutStatic(1, constantPool);
|
||||
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
PcodeTextEmitter.emitPopCat2Value(expected, ReferenceMethods.NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 8, ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE);
|
||||
assertEquals(pCode,expected.toString());
|
||||
|
||||
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET,
|
||||
4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 8,
|
||||
ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE);
|
||||
assertEquals(pCode, expected.toString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGetField1() throws IOException {
|
||||
ArrayList<Byte> classFile = new ArrayList<>();
|
||||
TestClassFileCreator.appendMagic(classFile);
|
||||
TestClassFileCreator.appendVersions(classFile);
|
||||
TestClassFileCreator.appendCount(classFile, (short) 7);
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
|
||||
TestClassFileCreator.appendClass(classFile, (short) 4); //2
|
||||
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
|
||||
TestClassFileCreator.appendUtf8(classFile, "className"); //4
|
||||
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
|
||||
TestClassFileCreator.appendUtf8(classFile,"I"); //6 (descriptor)
|
||||
|
||||
TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
|
||||
|
||||
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
|
||||
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
AbstractConstantPoolInfoJava[] constantPool =
|
||||
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
String pCode = ReferenceMethods.getPcodeForGetField(1, constantPool);
|
||||
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.VALUE, 4, ConstantPoolJava.CPOOL_OP , ReferenceMethods.OBJECT_REF, "1", ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.TEMP_1, 4,
|
||||
ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1",
|
||||
ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(expected, ReferenceMethods.VALUE, 4,
|
||||
ReferenceMethods.TEMP_1);
|
||||
PcodeTextEmitter.emitPushCat1Value(expected, ReferenceMethods.VALUE);
|
||||
assertEquals(pCode,expected.toString());
|
||||
|
||||
assertEquals(pCode, expected.toString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGetField2() throws IOException {
|
||||
ArrayList<Byte> classFile = new ArrayList<>();
|
||||
TestClassFileCreator.appendMagic(classFile);
|
||||
TestClassFileCreator.appendVersions(classFile);
|
||||
TestClassFileCreator.appendCount(classFile, (short) 7);
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
|
||||
TestClassFileCreator.appendClass(classFile, (short) 4); //2
|
||||
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
|
||||
TestClassFileCreator.appendUtf8(classFile, "className"); //4
|
||||
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
|
||||
TestClassFileCreator.appendUtf8(classFile,"J"); //6 (descriptor)
|
||||
|
||||
TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
|
||||
|
||||
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
|
||||
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
AbstractConstantPoolInfoJava[] constantPool =
|
||||
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
String pCode = ReferenceMethods.getPcodeForGetField(1, constantPool);
|
||||
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.VALUE, 8, ConstantPoolJava.CPOOL_OP , ReferenceMethods.OBJECT_REF, "1", ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.TEMP_1, 8,
|
||||
ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1",
|
||||
ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(expected, ReferenceMethods.VALUE, 8,
|
||||
ReferenceMethods.TEMP_1);
|
||||
PcodeTextEmitter.emitPushCat2Value(expected, ReferenceMethods.VALUE);
|
||||
assertEquals(pCode,expected.toString());
|
||||
|
||||
assertEquals(pCode, expected.toString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPutField1() throws IOException {
|
||||
ArrayList<Byte> classFile = new ArrayList<>();
|
||||
TestClassFileCreator.appendMagic(classFile);
|
||||
TestClassFileCreator.appendVersions(classFile);
|
||||
TestClassFileCreator.appendCount(classFile, (short) 7);
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
|
||||
TestClassFileCreator.appendClass(classFile, (short) 4); //2
|
||||
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
|
||||
TestClassFileCreator.appendUtf8(classFile, "className"); //4
|
||||
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
|
||||
TestClassFileCreator.appendUtf8(classFile,"I"); //6 (descriptor)
|
||||
|
||||
TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
|
||||
|
||||
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
|
||||
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
AbstractConstantPoolInfoJava[] constantPool =
|
||||
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
String pCode = ReferenceMethods.getPcodeForPutField(1, constantPool);
|
||||
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.NEW_VALUE);
|
||||
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1", ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 4, ReferenceMethods.FIELD_OFFSET, ReferenceMethods.NEW_VALUE);
|
||||
|
||||
assertEquals(pCode,expected.toString());
|
||||
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET,
|
||||
4, ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1",
|
||||
ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 4,
|
||||
ReferenceMethods.FIELD_OFFSET, ReferenceMethods.NEW_VALUE);
|
||||
|
||||
assertEquals(pCode, expected.toString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPutField2() throws IOException {
|
||||
ArrayList<Byte> classFile = new ArrayList<>();
|
||||
TestClassFileCreator.appendMagic(classFile);
|
||||
TestClassFileCreator.appendVersions(classFile);
|
||||
TestClassFileCreator.appendCount(classFile, (short) 7);
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short)3); //1
|
||||
TestClassFileCreator.appendFieldRef(classFile, (short) 2, (short) 3); //1
|
||||
TestClassFileCreator.appendClass(classFile, (short) 4); //2
|
||||
TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3
|
||||
TestClassFileCreator.appendUtf8(classFile, "className"); //4
|
||||
TestClassFileCreator.appendUtf8(classFile, "fieldName"); //5
|
||||
TestClassFileCreator.appendUtf8(classFile,"J"); //6 (descriptor)
|
||||
|
||||
TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
|
||||
|
||||
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
|
||||
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
AbstractConstantPoolInfoJava[] constantPool =
|
||||
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
|
||||
String pCode = ReferenceMethods.getPcodeForPutField(1, constantPool);
|
||||
|
||||
|
||||
StringBuilder expected = new StringBuilder();
|
||||
PcodeTextEmitter.emitPopCat2Value(expected, ReferenceMethods.NEW_VALUE);
|
||||
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1", ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 8, ReferenceMethods.FIELD_OFFSET, ReferenceMethods.NEW_VALUE);
|
||||
|
||||
assertEquals(pCode,expected.toString());
|
||||
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET,
|
||||
4, ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1",
|
||||
ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 8,
|
||||
ReferenceMethods.FIELD_OFFSET, ReferenceMethods.NEW_VALUE);
|
||||
|
||||
assertEquals(pCode, expected.toString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -15,8 +15,7 @@
|
||||
*/
|
||||
package ghidra.javaclass.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@ -437,4 +436,78 @@ public class DescriptorDecoderTest extends AbstractGenericTest {
|
||||
assertEquals("Integer[][][]", typeNames.get(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetReturnTypeOfMethodDescriptor() {
|
||||
String ItoInt = "(I)Ljava/lang/Integer;";
|
||||
|
||||
DataType type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(ItoInt, dtm);
|
||||
assertEquals(new PointerDataType(dtInteger), type);
|
||||
|
||||
String IntIntInttoInt =
|
||||
"(Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;";
|
||||
type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(IntIntInttoInt, dtm);
|
||||
assertEquals(new PointerDataType(dtInteger), type);
|
||||
|
||||
String voidTovoid = "()V";
|
||||
type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(voidTovoid, dtm);
|
||||
assertEquals(DataType.VOID, type);
|
||||
|
||||
String ItoI = "(I)I";
|
||||
type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(ItoI, dtm);
|
||||
assertEquals(IntegerDataType.dataType, type);
|
||||
|
||||
String OneDIntTwoDInttoInt =
|
||||
"([Ljava/lang/Integer;[[Ljava/lang/Integer;)Ljava/lang/Integer;";
|
||||
|
||||
type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(OneDIntTwoDInttoInt, dtm);
|
||||
assertEquals(new PointerDataType(dtInteger), type);
|
||||
|
||||
String DDtoD = "(DD)D";
|
||||
type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(DDtoD, dtm);
|
||||
assertEquals(DoubleDataType.dataType, type);
|
||||
|
||||
String crazy = "(DJLjava/lang/Integer;[[Ljava/lang/Integer;)[[Ljava/lang/Integer;";
|
||||
type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(crazy, dtm);
|
||||
assertEquals(dtm.getPointer(DWordDataType.dataType), type);
|
||||
|
||||
String getClass = "()Ljava/lang/Class";
|
||||
type = DescriptorDecoder.getReturnTypeOfMethodDescriptor(getClass, dtm);
|
||||
assertEquals(PointerDataType.dataType, type);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetParameterString() {
|
||||
String ItoInt = "(I)Ljava/lang/Integer;";
|
||||
|
||||
String paramString = DescriptorDecoder.getParameterString(ItoInt);
|
||||
assertEquals("(int)", paramString);
|
||||
|
||||
String IntIntInttoInt =
|
||||
"(Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Integer;";
|
||||
paramString = DescriptorDecoder.getParameterString(IntIntInttoInt);
|
||||
assertEquals("(java.lang.Integer, java.lang.Integer, java.lang.Integer)", paramString);
|
||||
|
||||
String voidToVoid = "()V";
|
||||
paramString = DescriptorDecoder.getParameterString(voidToVoid);
|
||||
assertEquals("()", paramString);
|
||||
|
||||
String ItoI = "(I)I";
|
||||
paramString = DescriptorDecoder.getParameterString(ItoI);
|
||||
assertEquals("(int)", paramString);
|
||||
|
||||
String OneDIntTwoDInttoInt =
|
||||
"([Ljava/lang/Integer;[[Ljava/lang/Integer;)Ljava/lang/Integer;";
|
||||
|
||||
paramString = DescriptorDecoder.getParameterString(OneDIntTwoDInttoInt);
|
||||
assertEquals("(java.lang.Integer[], java.lang.Integer[][])", paramString);
|
||||
|
||||
String DDtoD = "(DD)D";
|
||||
paramString = DescriptorDecoder.getParameterString(DDtoD);
|
||||
assertEquals("(double, double)", paramString);
|
||||
|
||||
String crazy = "(DJLjava/lang/Integer;[[Ljava/lang/Integer;)[[Ljava/lang/Integer;";
|
||||
paramString = DescriptorDecoder.getParameterString(crazy);
|
||||
assertEquals("(double, long, java.lang.Integer, java.lang.Integer[][])", paramString);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user