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