mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-24 03:09:36 +08:00
GT_2757 fixed java stream decompile bug
This commit is contained in:
+31
-21
@@ -26,15 +26,15 @@ import ghidra.util.xml.SpecXmlUtils;
|
||||
*
|
||||
*/
|
||||
public abstract class ConstantPool {
|
||||
public static final int PRIMITIVE = 0; // Constant -value- of datatype -type-
|
||||
public static final int STRING_LITERAL = 1; // Constant reference to string in -token-
|
||||
public static final int CLASS_REFERENCE = 2; // Reference to (system level) class object
|
||||
public static final int POINTER_METHOD = 3; // Pointer to a method, name in -token-, signature in -type-
|
||||
public static final int POINTER_FIELD = 4; // Pointer to a field, name in -token-, datatype in -type-
|
||||
public static final int ARRAY_LENGTH = 5; // Integer length, -token- is language specific indicator, -type- is integral type
|
||||
public static final int INSTANCE_OF = 6; // boolean value, -token- is language specific indicator, -type- is boolean type
|
||||
public static final int CHECK_CAST = 7; // Pointer to object, new name in -token-, new datatype in -type-
|
||||
|
||||
public static final int PRIMITIVE = 0; // Constant -value- of datatype -type-
|
||||
public static final int STRING_LITERAL = 1; // Constant reference to string in -token-
|
||||
public static final int CLASS_REFERENCE = 2; // Reference to (system level) class object
|
||||
public static final int POINTER_METHOD = 3; // Pointer to a method, name in -token-, signature in -type-
|
||||
public static final int POINTER_FIELD = 4; // Pointer to a field, name in -token-, datatype in -type-
|
||||
public static final int ARRAY_LENGTH = 5; // Integer length, -token- is language specific indicator, -type- is integral type
|
||||
public static final int INSTANCE_OF = 6; // boolean value, -token- is language specific indicator, -type- is boolean type
|
||||
public static final int CHECK_CAST = 7; // Pointer to object, new name in -token-, new datatype in -type-
|
||||
|
||||
public static class Record {
|
||||
public int tag; // The type of the record
|
||||
public String token; // Name or token associated with object
|
||||
@@ -43,31 +43,41 @@ public abstract class ConstantPool {
|
||||
public DataType type;
|
||||
public boolean hasThisPtr = false;
|
||||
public boolean isConstructor = false;
|
||||
|
||||
public StringBuilder build(long ref,PcodeDataTypeManager dtmanage) {
|
||||
|
||||
public StringBuilder build(long ref, PcodeDataTypeManager dtmanage) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("<cpoolrec");
|
||||
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "ref", ref);
|
||||
if (tag == STRING_LITERAL)
|
||||
if (tag == STRING_LITERAL) {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "string");
|
||||
else if (tag == CLASS_REFERENCE)
|
||||
}
|
||||
else if (tag == CLASS_REFERENCE) {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "classref");
|
||||
else if (tag == POINTER_METHOD)
|
||||
}
|
||||
else if (tag == POINTER_METHOD) {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "method");
|
||||
else if (tag == POINTER_FIELD)
|
||||
}
|
||||
else if (tag == POINTER_FIELD) {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "field");
|
||||
else if (tag == ARRAY_LENGTH)
|
||||
}
|
||||
else if (tag == ARRAY_LENGTH) {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "arraylength");
|
||||
else if (tag == INSTANCE_OF)
|
||||
}
|
||||
else if (tag == INSTANCE_OF) {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "instanceof");
|
||||
else if (tag == CHECK_CAST)
|
||||
}
|
||||
else if (tag == CHECK_CAST) {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "checkcast");
|
||||
else
|
||||
}
|
||||
else {
|
||||
SpecXmlUtils.encodeStringAttribute(buf, "tag", "primitive");
|
||||
if (hasThisPtr)
|
||||
}
|
||||
if (hasThisPtr) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(buf, "hasthis", true);
|
||||
if (isConstructor)
|
||||
}
|
||||
if (isConstructor) {
|
||||
SpecXmlUtils.encodeBooleanAttribute(buf, "constructor", true);
|
||||
}
|
||||
buf.append(">\n");
|
||||
if (tag == PRIMITIVE) {
|
||||
buf.append("<value>");
|
||||
|
||||
@@ -99,15 +99,7 @@
|
||||
<input name="cpool_index_ldc2_w"/>
|
||||
</pcode>
|
||||
</callotherfixup>
|
||||
|
||||
<callotherfixup targetop="lookupswitchCallOther">
|
||||
<pcode dynamic="true">
|
||||
<input name="default"/>
|
||||
<input name="numPairs"/>
|
||||
<input name ="padding"/>
|
||||
</pcode>
|
||||
</callotherfixup>
|
||||
|
||||
|
||||
<callotherfixup targetop="multianewarrayCallOther">
|
||||
<pcode dynamic="true">
|
||||
<input name="cpool_index_multianewarray"/>
|
||||
|
||||
@@ -66,7 +66,6 @@ define pcodeop invokeinterfaceCallOther;
|
||||
define pcodeop invokespecialCallOther;
|
||||
define pcodeop invokestaticCallOther;
|
||||
define pcodeop invokevirtualCallOther;
|
||||
define pcodeop lookupswitchCallOther;
|
||||
define pcodeop multianewarrayCallOther;
|
||||
define pcodeop putStaticCallOther;
|
||||
define pcodeop putFieldCallOther;
|
||||
@@ -418,8 +417,8 @@ Default:"default" addr is defaultbyte1; defaultbyte2; defaultbyte3; defaultbyte4
|
||||
|
||||
:checkcast index is (in_table_switch=0 & in_lookup_switch=0 & op=0xc0); indexbyte1; indexbyte2 [ index = indexbyte1<<8 | indexbyte2; ]
|
||||
{
|
||||
_object: $(SIZE) = *:$(SIZE) SP;
|
||||
throwExceptionOp(_object);
|
||||
#_object: $(SIZE) = *:$(SIZE) SP;
|
||||
#throwExceptionOp(_object);
|
||||
|
||||
#_res:1 = cpool(_object,index,$(CPOOL_CHECKCAST));
|
||||
#throwExceptionOp(_res);
|
||||
@@ -428,9 +427,12 @@ Default:"default" addr is defaultbyte1; defaultbyte2; defaultbyte3; defaultbyte4
|
||||
#_ref: $(SIZE) = cpool(0:4,index,$(CPOOL_CHECKCAST));
|
||||
#checkcastOp(_object,_ref);
|
||||
|
||||
#_object:$(SIZE) = 0;
|
||||
#pop(_object);
|
||||
#_res:1 = cpool(_object,index,$(CPOOL_INSTANCEOF));
|
||||
_object:$(SIZE) = 0;
|
||||
pop(_object);
|
||||
_object = cpool(_object,index,$(CPOOL_CHECKCAST));
|
||||
push(_object);
|
||||
|
||||
#_res:1 = cpool(_object,index,$(CPOOL_CHECKCAST));
|
||||
#_result:$(SIZE) = zext(_res);
|
||||
#push(_result);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import ghidra.javaclass.format.attributes.CodeAttribute;
|
||||
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.PointerDataType;
|
||||
import ghidra.program.model.lang.LanguageCompilerSpecPair;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.listing.Program;
|
||||
@@ -43,6 +44,8 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
|
||||
private static final String JAVA_NAME = "Java Class File";
|
||||
private Register alignmentReg;
|
||||
public static final long CODE_OFFSET = 0x10000L;
|
||||
public static final String CONSTANT_POOL = "constantPool";
|
||||
|
||||
@Override
|
||||
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
|
||||
@@ -61,22 +64,24 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
return loadSpecs;
|
||||
}
|
||||
|
||||
private boolean checkClass(ByteProvider provider) {
|
||||
private boolean checkClass(ByteProvider provider) throws IOException {
|
||||
BinaryReader reader = new BinaryReader(provider, false);
|
||||
ClassFileJava classFile;
|
||||
int magic = reader.peekNextInt();
|
||||
//if it doesn't begin with the 0xCAFEBABE it's not a class file
|
||||
if (magic != JavaClassConstants.MAGIC) {
|
||||
return false;
|
||||
}
|
||||
//attempt to parse the header, if successful count it as a class file.
|
||||
try {
|
||||
classFile = new ClassFileJava(reader);
|
||||
new ClassFileJava(reader);
|
||||
}
|
||||
catch (IOException e) {
|
||||
return false;
|
||||
} catch (RuntimeException re) {
|
||||
}
|
||||
catch (RuntimeException re) {
|
||||
return false;
|
||||
}
|
||||
int magic = classFile.getMagic();
|
||||
if (magic == 0xCAFEBABE) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -117,7 +122,7 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
throws LockException, MemoryConflictException, AddressOverflowException,
|
||||
CancelledException, DuplicateNameException, IOException {
|
||||
AddressFactory af = program.getAddressFactory();
|
||||
AddressSpace space = af.getAddressSpace("constantPool");
|
||||
AddressSpace space = af.getAddressSpace(CONSTANT_POOL);
|
||||
Memory memory = program.getMemory();
|
||||
alignmentReg = program.getRegister("alignmentPad");
|
||||
|
||||
@@ -130,28 +135,27 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
memory.createInitializedBlock("_" + provider.getName() + "_", address,
|
||||
provider.getInputStream(0), provider.length(), monitor, false);
|
||||
|
||||
createMethodLookupMemoryBlock( program, monitor );
|
||||
createMethodLookupMemoryBlock(program, monitor);
|
||||
createMethodMemoryBlocks(program, provider, classFile, monitor);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void createMethodLookupMemoryBlock(Program program, TaskMonitor monitor) {
|
||||
Address address = toAddr( program, JavaClassUtil.LOOKUP_ADDRESS );
|
||||
Address address = toAddr(program, JavaClassUtil.LOOKUP_ADDRESS);
|
||||
MemoryBlock block = null;
|
||||
Memory memory = program.getMemory();
|
||||
try {
|
||||
block = memory.createInitializedBlock( "method_lookup", address, JavaClassUtil.METHOD_INDEX_SIZE, (byte) 0xff, monitor, false );
|
||||
block = memory.createInitializedBlock("method_lookup", address,
|
||||
JavaClassUtil.METHOD_INDEX_SIZE, (byte) 0xff, monitor, false);
|
||||
}
|
||||
catch (LockException | DuplicateNameException | MemoryConflictException
|
||||
| AddressOverflowException | CancelledException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
block.setRead( true );
|
||||
block.setWrite( false );
|
||||
block.setExecute( false );
|
||||
block.setRead(true);
|
||||
block.setWrite(false);
|
||||
block.setExecute(false);
|
||||
|
||||
}
|
||||
|
||||
@@ -164,12 +168,11 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
monitor.setProgress(0);
|
||||
monitor.setMaximum(methods.length);
|
||||
|
||||
long codeOffset = 0x10000;
|
||||
Address start = toAddr(program, codeOffset);
|
||||
Address start = toAddr(program, CODE_OFFSET);
|
||||
try {
|
||||
//program.setImageBase(start, true);
|
||||
//for (MethodInfoJava method : methods) {
|
||||
for (int i = 0, max = methods.length; i < max; ++i){
|
||||
for (int i = 0, max = methods.length; i < max; ++i) {
|
||||
MethodInfoJava method = methods[i];
|
||||
monitor.incrementProgress(1);
|
||||
CodeAttribute code = method.getCodeAttribute();
|
||||
@@ -180,18 +183,19 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
long offset = code.getCodeOffset();
|
||||
|
||||
Memory memory = program.getMemory();
|
||||
short nameIndex = method.getNameIndex();
|
||||
short descriptorIndex = method.getDescriptorIndex();
|
||||
ConstantPoolUtf8Info methodNameInfo = (ConstantPoolUtf8Info) constantPool[nameIndex];
|
||||
int nameIndex = method.getNameIndex();
|
||||
int descriptorIndex = method.getDescriptorIndex();
|
||||
ConstantPoolUtf8Info methodNameInfo =
|
||||
(ConstantPoolUtf8Info) constantPool[nameIndex];
|
||||
ConstantPoolUtf8Info methodDescriptorInfo =
|
||||
(ConstantPoolUtf8Info) constantPool[descriptorIndex];
|
||||
(ConstantPoolUtf8Info) constantPool[descriptorIndex];
|
||||
String methodName = methodNameInfo.getString() + methodDescriptorInfo.getString();
|
||||
|
||||
MemoryBlock memoryBlock =
|
||||
memory.createInitializedBlock(methodName, start,
|
||||
provider.getInputStream(offset), length, monitor, false);
|
||||
Address methodIndexAddress = JavaClassUtil.toLookupAddress( program, i );
|
||||
program.getMemory( ).setInt( methodIndexAddress, (int) start.getOffset() );
|
||||
MemoryBlock memoryBlock = memory.createInitializedBlock(methodName, start,
|
||||
provider.getInputStream(offset), length, monitor, false);
|
||||
Address methodIndexAddress = JavaClassUtil.toLookupAddress(program, i);
|
||||
program.getMemory().setInt(methodIndexAddress, (int) start.getOffset());
|
||||
program.getListing().createData(methodIndexAddress, PointerDataType.dataType);
|
||||
|
||||
setAlignmentInfo(program,
|
||||
new AddressSet(memoryBlock.getStart(), memoryBlock.getEnd()));
|
||||
@@ -200,10 +204,9 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
start = start.add(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
} catch (Exception e1) {
|
||||
}
|
||||
catch (Exception e1) {
|
||||
// TODO Auto-generated catch block
|
||||
e1.printStackTrace();
|
||||
}
|
||||
@@ -214,9 +217,8 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
|
||||
int alignmentValue = 3;
|
||||
while (addressIterator.hasNext()) {
|
||||
Address address = addressIterator.next();
|
||||
SetRegisterCmd cmd =
|
||||
new SetRegisterCmd(alignmentReg, address, address,
|
||||
BigInteger.valueOf(alignmentValue));
|
||||
SetRegisterCmd cmd = new SetRegisterCmd(alignmentReg, address, address,
|
||||
BigInteger.valueOf(alignmentValue));
|
||||
cmd.applyTo(program);
|
||||
if (alignmentValue == 0) {
|
||||
alignmentValue = 3;
|
||||
|
||||
+171
-145
@@ -32,24 +32,24 @@ public class ConstantPoolJava extends ConstantPool {
|
||||
private DataTypeManager dtManager = null;
|
||||
|
||||
//the following constants must agree with the definitions in JVM.slaspec
|
||||
public static final String CPOOL_ANEWARRAY = "0";
|
||||
public static final String CPOOL_CHECKCAST = "1";
|
||||
public static final String CPOOL_GETFIELD = "2";
|
||||
public static final String CPOOL_GETSTATIC = "3";
|
||||
public static final String CPOOL_LDC = "4"; //also used for ldc_w
|
||||
public static final String CPOOL_LDC2_W = "5";
|
||||
public static final String CPOOL_INSTANCEOF = "6";
|
||||
public static final String CPOOL_INVOKEDYNAMIC = "7";
|
||||
public static final String CPOOL_ANEWARRAY = "0";
|
||||
public static final String CPOOL_CHECKCAST = "1";
|
||||
public static final String CPOOL_GETFIELD = "2";
|
||||
public static final String CPOOL_GETSTATIC = "3";
|
||||
public static final String CPOOL_LDC = "4"; //also used for ldc_w
|
||||
public static final String CPOOL_LDC2_W = "5";
|
||||
public static final String CPOOL_INSTANCEOF = "6";
|
||||
public static final String CPOOL_INVOKEDYNAMIC = "7";
|
||||
public static final String CPOOL_INVOKEINTERFACE = "8";
|
||||
public static final String CPOOL_INVOKESPECIAL = "9";
|
||||
public static final String CPOOL_INVOKESTATIC = "10";
|
||||
public static final String CPOOL_INVOKEVIRTUAL = "11";
|
||||
public static final String CPOOL_MULTIANEWARRAY = "12";
|
||||
public static final String CPOOL_NEW = "13";
|
||||
public static final String CPOOL_NEWARRAY = "14";
|
||||
public static final String CPOOL_PUTSTATIC = "15";
|
||||
public static final String CPOOL_PUTFIELD = "16";
|
||||
public static final String CPOOL_ARRAYLENGTH = "17";
|
||||
public static final String CPOOL_INVOKESPECIAL = "9";
|
||||
public static final String CPOOL_INVOKESTATIC = "10";
|
||||
public static final String CPOOL_INVOKEVIRTUAL = "11";
|
||||
public static final String CPOOL_MULTIANEWARRAY = "12";
|
||||
public static final String CPOOL_NEW = "13";
|
||||
public static final String CPOOL_NEWARRAY = "14";
|
||||
public static final String CPOOL_PUTSTATIC = "15";
|
||||
public static final String CPOOL_PUTFIELD = "16";
|
||||
public static final String CPOOL_ARRAYLENGTH = "17";
|
||||
|
||||
public ConstantPoolJava(Program program) throws IOException {
|
||||
ClassFileAnalysisState analysisState = ClassFileAnalysisState.getState(program);
|
||||
@@ -58,43 +58,68 @@ public class ConstantPoolJava extends ConstantPool {
|
||||
dtManager = program.getDataTypeManager();
|
||||
}
|
||||
|
||||
private void fillinMethod(int name_and_type_index, Record res,JavaInvocationType methodType) {
|
||||
ConstantPoolNameAndTypeInfo methodNameAndType = (ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index];
|
||||
private void fillinMethod(int index, int name_and_type_index, Record res,
|
||||
JavaInvocationType methodType) {
|
||||
ConstantPoolNameAndTypeInfo methodNameAndType =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index];
|
||||
int name_index = methodNameAndType.getNameIndex();
|
||||
res.tag = ConstantPool.POINTER_METHOD;
|
||||
res.token = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
|
||||
|
||||
if (methodType.equals(JavaInvocationType.INVOKE_STATIC)) {
|
||||
AbstractConstantPoolReferenceInfo poolRef =
|
||||
(AbstractConstantPoolReferenceInfo) constantPool[index];
|
||||
ConstantPoolClassInfo classInfo =
|
||||
(ConstantPoolClassInfo) constantPool[poolRef.getClassIndex()];
|
||||
int classNameIndex = classInfo.getNameIndex();
|
||||
String fullyQualifiedName =
|
||||
((ConstantPoolUtf8Info) constantPool[classNameIndex]).getString();
|
||||
String className = getClassName(fullyQualifiedName);
|
||||
res.token =
|
||||
className + "." + ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
}
|
||||
else {
|
||||
res.token = ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
}
|
||||
|
||||
int descriptor_index = methodNameAndType.getDescriptorIndex();
|
||||
ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
|
||||
String descriptor = descriptorInfo.getString();
|
||||
FunctionDefinitionDataType funcDef = new FunctionDefinitionDataType(res.token);
|
||||
res.type = new PointerDataType(funcDef);
|
||||
DataType returnType = DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor, dtManager);
|
||||
|
||||
String uniqueifier = Integer.toHexString(index);
|
||||
FunctionDefinitionDataType funcDef =
|
||||
new FunctionDefinitionDataType(uniqueifier + "_" + res.token);
|
||||
DataType returnType =
|
||||
DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor, dtManager);
|
||||
funcDef.setReturnType(returnType);
|
||||
List<DataType> params = DescriptorDecoder.getDataTypeList(descriptor, dtManager);
|
||||
ParameterDefinitionImpl[] paramDefs;
|
||||
|
||||
//invokestatic and invokedynamic don't have a this pointer on the stack
|
||||
if (methodType.equals(JavaInvocationType.INVOKE_STATIC) || methodType.equals(JavaInvocationType.INVOKE_DYNAMIC)){
|
||||
if (methodType.equals(JavaInvocationType.INVOKE_STATIC) ||
|
||||
methodType.equals(JavaInvocationType.INVOKE_DYNAMIC)) {
|
||||
paramDefs = new ParameterDefinitionImpl[params.size()];
|
||||
for (int i = 0, max = params.size(); i < max; ++i){
|
||||
ParameterDefinitionImpl currentParam = new ParameterDefinitionImpl("", params.get(i), null);
|
||||
paramDefs[i]= currentParam;
|
||||
for (int i = 0, max = params.size(); i < max; ++i) {
|
||||
ParameterDefinitionImpl currentParam =
|
||||
new ParameterDefinitionImpl("", params.get(i), null);
|
||||
paramDefs[i] = currentParam;
|
||||
}
|
||||
res.hasThisPtr = false;
|
||||
}
|
||||
//invokeinterface, invokespecial, and invokevirtual do have a this pointer
|
||||
else {
|
||||
paramDefs = new ParameterDefinitionImpl[params.size() + 1];
|
||||
ParameterDefinitionImpl thisParam = new ParameterDefinitionImpl("objectRef", new Pointer32DataType(DataType.VOID), null);
|
||||
ParameterDefinitionImpl thisParam = new ParameterDefinitionImpl("objectRef",
|
||||
new Pointer32DataType(DataType.VOID), null);
|
||||
paramDefs[0] = thisParam;
|
||||
for (int i = 1, max = params.size(); i <= max; ++i){
|
||||
ParameterDefinitionImpl currentParam = new ParameterDefinitionImpl("", params.get(i-1), null);
|
||||
paramDefs[i]= currentParam;
|
||||
for (int i = 1, max = params.size(); i <= max; ++i) {
|
||||
ParameterDefinitionImpl currentParam =
|
||||
new ParameterDefinitionImpl("", params.get(i - 1), null);
|
||||
paramDefs[i] = currentParam;
|
||||
}
|
||||
res.hasThisPtr = true;
|
||||
}
|
||||
|
||||
funcDef.setArguments(paramDefs);
|
||||
res.type = new PointerDataType(funcDef);
|
||||
}
|
||||
|
||||
//ref array does not include the first element passed to the cpool operator.
|
||||
@@ -109,38 +134,33 @@ public class ConstantPoolJava extends ConstantPool {
|
||||
* type of the elements of the new array. We use the cpool operator to
|
||||
* look up the string token corresponding to the primitive type.
|
||||
*/
|
||||
if (op.equals(CPOOL_NEWARRAY)){
|
||||
if (op.equals(CPOOL_NEWARRAY)) {
|
||||
res.tag = ConstantPool.POINTER_METHOD;
|
||||
res.token = ArrayMethods.getPrimitiveArrayToken((int)ref[0]);
|
||||
res.token = ArrayMethods.getPrimitiveArrayToken((int) ref[0]);
|
||||
DataType elementType = ArrayMethods.getArrayBaseType((int) ref[0], dtManager);
|
||||
res.type = dtManager.getPointer(elementType);
|
||||
return res;
|
||||
}
|
||||
/*arraylength instruction does not reference the constant pool */
|
||||
if (op.equals(CPOOL_ARRAYLENGTH)){
|
||||
if (op.equals(CPOOL_ARRAYLENGTH)) {
|
||||
res.tag = ConstantPool.ARRAY_LENGTH;
|
||||
res.token = "length";
|
||||
res.type = new PointerDataType(DWordDataType.dataType);
|
||||
res.type = IntegerDataType.dataType;
|
||||
return res;
|
||||
}
|
||||
|
||||
AbstractConstantPoolInfoJava poolRef = constantPool[(int)ref[0]];
|
||||
short name_and_type_index;
|
||||
ConstantPoolNameAndTypeInfo fieldNameAndType;
|
||||
short descriptor_index;
|
||||
ConstantPoolUtf8Info descriptorInfo;
|
||||
String descriptor;
|
||||
StringBuilder sb = null;
|
||||
String[] parts = null;
|
||||
switch(op){
|
||||
AbstractConstantPoolInfoJava poolRef = constantPool[(int) ref[0]];
|
||||
int name_and_type_index;
|
||||
switch (op) {
|
||||
case CPOOL_ANEWARRAY:
|
||||
case CPOOL_NEW:
|
||||
res.tag = ConstantPool.CLASS_REFERENCE;
|
||||
int name_index = ((ConstantPoolClassInfo)poolRef).getNameIndex();
|
||||
String fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
|
||||
parts = fullyQualifiedName.split("/");
|
||||
res.token = parts[parts.length-1];
|
||||
sb = new StringBuilder();
|
||||
int name_index = ((ConstantPoolClassInfo) poolRef).getNameIndex();
|
||||
String fullyQualifiedName =
|
||||
((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
String[] parts = fullyQualifiedName.split("/");
|
||||
res.token = parts[parts.length - 1];
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String part : parts) {
|
||||
sb.append(CategoryPath.DELIMITER_CHAR);
|
||||
sb.append(part);
|
||||
@@ -148,12 +168,13 @@ public class ConstantPoolJava extends ConstantPool {
|
||||
DataTypePath dataPath = new DataTypePath(sb.toString(), res.token);
|
||||
res.type = new PointerDataType(dtManager.getDataType(dataPath));
|
||||
break;
|
||||
//TODO
|
||||
case CPOOL_CHECKCAST:
|
||||
res.tag = ConstantPool.CHECK_CAST;
|
||||
res.token = "checkcast";
|
||||
setTypeNameInfo(poolRef,res);
|
||||
break;
|
||||
setTypeNameInfo(poolRef, res);
|
||||
res.tag = ConstantPool.CHECK_CAST;
|
||||
PointerDataType pointerType = (PointerDataType) res.type;
|
||||
String typeName = pointerType.getDataType().getDisplayName();
|
||||
res.token = "checkcast(" + typeName + ")";
|
||||
break;
|
||||
case CPOOL_INSTANCEOF:
|
||||
res.tag = ConstantPool.INSTANCE_OF;
|
||||
res.token = "instanceof";
|
||||
@@ -161,154 +182,159 @@ public class ConstantPoolJava extends ConstantPool {
|
||||
break;
|
||||
case CPOOL_GETFIELD:
|
||||
case CPOOL_PUTFIELD:
|
||||
name_and_type_index = ((ConstantPoolFieldReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
fieldNameAndType = (ConstantPoolNameAndTypeInfo)constantPool[name_and_type_index];
|
||||
name_index = fieldNameAndType.getNameIndex();
|
||||
res.tag = ConstantPool.POINTER_FIELD;
|
||||
res.token = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
|
||||
descriptor_index = fieldNameAndType.getDescriptorIndex();
|
||||
descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
|
||||
descriptor = descriptorInfo.getString();
|
||||
DataType type = DescriptorDecoder.getDataTypeOfDescriptor(descriptor, dtManager);
|
||||
res.type = new PointerDataType(type);
|
||||
break;
|
||||
//for references to static fields, we want the class name to be part of the token
|
||||
case CPOOL_GETSTATIC:
|
||||
case CPOOL_PUTSTATIC:
|
||||
name_and_type_index = ((ConstantPoolFieldReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
int class_index = ((ConstantPoolFieldReferenceInfo)poolRef).getClassIndex();
|
||||
fieldNameAndType = (ConstantPoolNameAndTypeInfo)constantPool[name_and_type_index];
|
||||
name_index = fieldNameAndType.getNameIndex();
|
||||
ConstantPoolClassInfo classInfo = (ConstantPoolClassInfo)constantPool[class_index];
|
||||
int classNameIndex = classInfo.getNameIndex();
|
||||
fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[classNameIndex]).getString();
|
||||
res.tag = ConstantPool.POINTER_FIELD;
|
||||
String className = getClassName(fullyQualifiedName);
|
||||
res.token = className + "." + ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
|
||||
descriptor_index = fieldNameAndType.getDescriptorIndex();
|
||||
descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
|
||||
descriptor = descriptorInfo.getString();
|
||||
type = DescriptorDecoder.getDataTypeOfDescriptor(descriptor, dtManager);
|
||||
res.type = new PointerDataType(type);
|
||||
//res.type = type;
|
||||
handlePutAndGetOps(poolRef, res, op);
|
||||
break;
|
||||
case CPOOL_INVOKEDYNAMIC:
|
||||
name_and_type_index = ((ConstantPoolInvokeDynamicInfo)poolRef).getNameAndTypeIndex();
|
||||
fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_DYNAMIC);
|
||||
name_and_type_index =
|
||||
((ConstantPoolInvokeDynamicInfo) poolRef).getNameAndTypeIndex();
|
||||
|
||||
fillinMethod((int) ref[0], name_and_type_index, res,
|
||||
JavaInvocationType.INVOKE_DYNAMIC);
|
||||
break;
|
||||
case CPOOL_INVOKEINTERFACE:
|
||||
name_and_type_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_INTERFACE);
|
||||
name_and_type_index =
|
||||
((ConstantPoolInterfaceMethodReferenceInfo) poolRef).getNameAndTypeIndex();
|
||||
fillinMethod((int) ref[0], name_and_type_index, res,
|
||||
JavaInvocationType.INVOKE_INTERFACE);
|
||||
break;
|
||||
case CPOOL_INVOKESPECIAL:
|
||||
if (poolRef instanceof ConstantPoolMethodReferenceInfo) {
|
||||
name_and_type_index = ((ConstantPoolMethodReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
}
|
||||
else{
|
||||
name_and_type_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
}
|
||||
fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_SPECIAL);
|
||||
|
||||
AbstractConstantPoolReferenceInfo refInfo =
|
||||
(AbstractConstantPoolReferenceInfo) poolRef;
|
||||
name_and_type_index = refInfo.getNameAndTypeIndex();
|
||||
fillinMethod((int) ref[0], name_and_type_index, res,
|
||||
JavaInvocationType.INVOKE_SPECIAL);
|
||||
break;
|
||||
case CPOOL_INVOKESTATIC:
|
||||
if (poolRef instanceof ConstantPoolMethodReferenceInfo) {
|
||||
name_and_type_index = ((ConstantPoolMethodReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
class_index = ((ConstantPoolMethodReferenceInfo)poolRef).getClassIndex();
|
||||
|
||||
}
|
||||
else{
|
||||
name_and_type_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
class_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getClassIndex();
|
||||
}
|
||||
classInfo = (ConstantPoolClassInfo)constantPool[class_index];
|
||||
classNameIndex = classInfo.getNameIndex();
|
||||
fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[classNameIndex]).getString();
|
||||
className = getClassName(fullyQualifiedName);
|
||||
fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_STATIC);
|
||||
res.token = className + "." + res.token;
|
||||
refInfo = (AbstractConstantPoolReferenceInfo) poolRef;
|
||||
name_and_type_index = refInfo.getNameAndTypeIndex();
|
||||
fillinMethod((int) ref[0], name_and_type_index, res,
|
||||
JavaInvocationType.INVOKE_STATIC);
|
||||
break;
|
||||
case CPOOL_INVOKEVIRTUAL:
|
||||
name_and_type_index = ((ConstantPoolMethodReferenceInfo)poolRef).getNameAndTypeIndex();
|
||||
fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_VIRTUAL);
|
||||
name_and_type_index =
|
||||
((ConstantPoolMethodReferenceInfo) poolRef).getNameAndTypeIndex();
|
||||
fillinMethod((int) ref[0], name_and_type_index, res,
|
||||
JavaInvocationType.INVOKE_VIRTUAL);
|
||||
break;
|
||||
//in this case, the constant pool entry can be a reference to:
|
||||
//int, float, string literal, or a symbolic reference to a class,
|
||||
//method type, or method handle
|
||||
|
||||
//in this case, the constant pool entry can be a reference to:
|
||||
//int, float, string literal, or a symbolic reference to a class,
|
||||
//method type, or method handle
|
||||
case CPOOL_LDC:
|
||||
if (poolRef instanceof ConstantPoolIntegerInfo) {
|
||||
res.tag = ConstantPool.PRIMITIVE;
|
||||
res.token = "int";
|
||||
res.value = ((ConstantPoolIntegerInfo)poolRef).getValue();
|
||||
res.value = ((ConstantPoolIntegerInfo) poolRef).getValue();
|
||||
res.type = IntegerDataType.dataType;
|
||||
}
|
||||
else if (poolRef instanceof ConstantPoolFloatInfo) {
|
||||
res.tag = ConstantPool.PRIMITIVE;
|
||||
res.token = "float";
|
||||
res.value = ((ConstantPoolFloatInfo)poolRef).getRawBytes() & 0xffffffffL;
|
||||
res.value = ((ConstantPoolFloatInfo) poolRef).getRawBytes() & 0xffffffffL;
|
||||
res.type = FloatDataType.dataType;
|
||||
}
|
||||
else if (poolRef instanceof ConstantPoolStringInfo) {
|
||||
int string_index = ((ConstantPoolStringInfo)poolRef).getStringIndex();
|
||||
int string_index = ((ConstantPoolStringInfo) poolRef).getStringIndex();
|
||||
res.tag = ConstantPool.STRING_LITERAL;
|
||||
res.byteData = ((ConstantPoolUtf8Info) constantPool[string_index]).getBytes();
|
||||
res.type = DescriptorDecoder.getReferenceTypeOfDescriptor("java/lang/String", dtManager, false);
|
||||
res.type = DescriptorDecoder.getReferenceTypeOfDescriptor("java/lang/String",
|
||||
dtManager, false);
|
||||
}
|
||||
else if (poolRef instanceof ConstantPoolClassInfo){
|
||||
else if (poolRef instanceof ConstantPoolClassInfo) {
|
||||
res.tag = ConstantPool.CLASS_REFERENCE;
|
||||
name_index = ((ConstantPoolClassInfo)poolRef).getNameIndex();
|
||||
fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
|
||||
className = getClassName(fullyQualifiedName);
|
||||
res.token = className + ".class";
|
||||
res.type = DescriptorDecoder.getReferenceTypeOfDescriptor(fullyQualifiedName, dtManager, false);
|
||||
name_index = ((ConstantPoolClassInfo) poolRef).getNameIndex();
|
||||
fullyQualifiedName =
|
||||
((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
String className = getClassName(fullyQualifiedName);
|
||||
res.token = className + ".class";
|
||||
res.type = DescriptorDecoder.getReferenceTypeOfDescriptor(fullyQualifiedName,
|
||||
dtManager, false);
|
||||
}
|
||||
//standard java compilers don't seem to emit the following two
|
||||
else if (poolRef instanceof ConstantPoolMethodTypeInfo){
|
||||
else if (poolRef instanceof ConstantPoolMethodTypeInfo) {
|
||||
res.tag = ConstantPool.POINTER_METHOD;
|
||||
name_index = ((ConstantPoolMethodTypeInfo)poolRef).getDescriptorIndex();
|
||||
res.token = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
|
||||
name_index = ((ConstantPoolMethodTypeInfo) poolRef).getDescriptorIndex();
|
||||
res.token = ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
res.type = dtManager.getPointer(DWordDataType.dataType);
|
||||
}
|
||||
//TODO set the token?
|
||||
else if (poolRef instanceof ConstantPoolMethodHandleInfo){
|
||||
else if (poolRef instanceof ConstantPoolMethodHandleInfo) {
|
||||
res.tag = ConstantPool.POINTER_METHOD;
|
||||
res.type = dtManager.getPointer(DWordDataType.dataType);
|
||||
}
|
||||
break;
|
||||
//must be a constant of type long or double
|
||||
//according to JVM spec
|
||||
//must be a constant of type long or double
|
||||
//according to JVM spec
|
||||
case CPOOL_LDC2_W:
|
||||
if (poolRef instanceof ConstantPoolLongInfo) {
|
||||
res.tag = ConstantPool.PRIMITIVE;
|
||||
res.token = "long";
|
||||
res.value = ((ConstantPoolLongInfo)poolRef).getValue();
|
||||
res.value = ((ConstantPoolLongInfo) poolRef).getValue();
|
||||
res.type = LongDataType.dataType;
|
||||
}
|
||||
else {
|
||||
res.tag = ConstantPool.PRIMITIVE;
|
||||
res.token = "double";
|
||||
res.value = ((ConstantPoolDoubleInfo)poolRef).getRawBytes();
|
||||
res.value = ((ConstantPoolDoubleInfo) poolRef).getRawBytes();
|
||||
res.type = DoubleDataType.dataType;
|
||||
}
|
||||
break;
|
||||
case CPOOL_MULTIANEWARRAY:
|
||||
res.tag = ConstantPool.POINTER_METHOD;
|
||||
res.tag = ConstantPool.CLASS_REFERENCE;
|
||||
res.type = new PointerDataType(DataType.VOID);
|
||||
int nameIndex = ((ConstantPoolClassInfo) poolRef).getNameIndex();
|
||||
ConstantPoolUtf8Info utf8Info = (ConstantPoolUtf8Info) constantPool[nameIndex];
|
||||
String classNameWithSemicolon = utf8Info.getString();
|
||||
res.token = DescriptorDecoder.getTypeNameFromDescriptor(classNameWithSemicolon, false, false);
|
||||
res.token = DescriptorDecoder.getTypeNameFromDescriptor(classNameWithSemicolon,
|
||||
false, false);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private void handlePutAndGetOps(AbstractConstantPoolInfoJava poolRef, Record res, String op) {
|
||||
|
||||
int name_and_type_index = ((ConstantPoolFieldReferenceInfo) poolRef).getNameAndTypeIndex();
|
||||
ConstantPoolNameAndTypeInfo fieldNameAndType =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index];
|
||||
int name_index = fieldNameAndType.getNameIndex();
|
||||
switch (op) {
|
||||
case CPOOL_GETFIELD:
|
||||
case CPOOL_PUTFIELD:
|
||||
res.token = ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
break;
|
||||
case CPOOL_GETSTATIC:
|
||||
case CPOOL_PUTSTATIC:
|
||||
int class_index = ((ConstantPoolFieldReferenceInfo) poolRef).getClassIndex();
|
||||
ConstantPoolClassInfo classInfo = (ConstantPoolClassInfo) constantPool[class_index];
|
||||
int classNameIndex = classInfo.getNameIndex();
|
||||
String fullyQualifiedName =
|
||||
((ConstantPoolUtf8Info) constantPool[classNameIndex]).getString();
|
||||
String className = getClassName(fullyQualifiedName);
|
||||
res.token =
|
||||
className + "." + ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid op: " + op);
|
||||
}
|
||||
|
||||
res.tag = ConstantPool.POINTER_FIELD;
|
||||
|
||||
int descriptor_index = fieldNameAndType.getDescriptorIndex();
|
||||
ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
|
||||
String descriptor = descriptorInfo.getString();
|
||||
DataType type = DescriptorDecoder.getDataTypeOfDescriptor(descriptor, dtManager);
|
||||
res.type = new PointerDataType(type);
|
||||
}
|
||||
|
||||
private void setTypeNameInfo(AbstractConstantPoolInfoJava poolRef, Record res) {
|
||||
int name_index = ((ConstantPoolClassInfo)poolRef).getNameIndex();
|
||||
String fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
|
||||
int name_index = ((ConstantPoolClassInfo) poolRef).getNameIndex();
|
||||
String fullyQualifiedName = ((ConstantPoolUtf8Info) constantPool[name_index]).getString();
|
||||
String[] parts = null;
|
||||
StringBuilder sb = null;
|
||||
if (fullyQualifiedName.startsWith("[")){
|
||||
if (fullyQualifiedName.startsWith("[")) {
|
||||
//TODO: how to get instanceof X to display, where X is an array type?
|
||||
//need to decide how to handle multidimensional arrays
|
||||
//remove the brackets
|
||||
@@ -318,7 +344,7 @@ public class ConstantPoolJava extends ConstantPool {
|
||||
for (String part : parts) {
|
||||
sb.append(CategoryPath.DELIMITER_CHAR);
|
||||
sb.append(part);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
parts = fullyQualifiedName.split("/");
|
||||
@@ -328,17 +354,17 @@ public class ConstantPoolJava extends ConstantPool {
|
||||
sb.append(part);
|
||||
}
|
||||
}
|
||||
DataTypePath dataPath = new DataTypePath(sb.toString(), parts[parts.length-1]);
|
||||
DataTypePath dataPath = new DataTypePath(sb.toString(), parts[parts.length - 1]);
|
||||
res.type = new PointerDataType(dtManager.getDataType(dataPath));
|
||||
|
||||
|
||||
}
|
||||
|
||||
private String getClassName(String fullyQualifiedName){
|
||||
private String getClassName(String fullyQualifiedName) {
|
||||
int lastSlash = fullyQualifiedName.lastIndexOf("/");
|
||||
return fullyQualifiedName.substring(lastSlash+1, fullyQualifiedName.length());
|
||||
return fullyQualifiedName.substring(lastSlash + 1, fullyQualifiedName.length());
|
||||
}
|
||||
|
||||
public AbstractConstantPoolInfoJava[] getConstantPool(){
|
||||
public AbstractConstantPoolInfoJava[] getConstantPool() {
|
||||
return constantPool;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ public class InjectInvokeDynamic extends InjectPayloadJava {
|
||||
InjectContext injectContext = getInjectContext(program, context);
|
||||
AbstractConstantPoolInfoJava[] constantPool = getConstantPool(program);
|
||||
int constantPoolIndex = (int) injectContext.inputlist.get(0).getOffset();
|
||||
String pcodeText = InvokeMethods.getPcodeForInvoke(constantPoolIndex, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
|
||||
String pcodeText = InvokeMethods.getPcodeForInvokeDynamic(constantPoolIndex, constantPool);
|
||||
return pcodeText;
|
||||
}
|
||||
|
||||
|
||||
-43
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+86
-29
@@ -38,7 +38,7 @@ public class InvokeMethods {
|
||||
static final String PARAM_SPACE = "parameterSpace";
|
||||
|
||||
//private constructor to enforce noninstantiability
|
||||
private InvokeMethods(){
|
||||
private InvokeMethods() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@@ -50,24 +50,28 @@ public class InvokeMethods {
|
||||
* @param type - the JavaInvocationType of the invocation
|
||||
* @return - the pcode as a string
|
||||
*/
|
||||
|
||||
public static String getPcodeForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) {
|
||||
public static String getPcodeForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool,
|
||||
JavaInvocationType type) {
|
||||
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
String descriptor = DescriptorDecoder.getDescriptorForInvoke(offset, constantPool, type);
|
||||
List<JavaComputationalCategory> categories = DescriptorDecoder.getParameterCategories(descriptor);
|
||||
boolean includeThisPointer = type.equals(JavaInvocationType.INVOKE_VIRTUAL) || type.equals(JavaInvocationType.INVOKE_SPECIAL) || type.equals(JavaInvocationType.INVOKE_INTERFACE);
|
||||
|
||||
String descriptor = DescriptorDecoder.getDescriptorForInvoke(offset, constantPool, type);
|
||||
List<JavaComputationalCategory> categories =
|
||||
DescriptorDecoder.getParameterCategories(descriptor);
|
||||
boolean includeThisPointer = type.equals(JavaInvocationType.INVOKE_VIRTUAL) ||
|
||||
type.equals(JavaInvocationType.INVOKE_SPECIAL) ||
|
||||
type.equals(JavaInvocationType.INVOKE_INTERFACE);
|
||||
|
||||
int stackPurge = DescriptorDecoder.getStackPurge(descriptor);
|
||||
if (includeThisPointer){
|
||||
if (includeThisPointer) {
|
||||
stackPurge += 4;
|
||||
}
|
||||
emitPcodeToMoveParams(pCode, categories, includeThisPointer, stackPurge);
|
||||
emitPcodeToResolveMethodReference(pCode, offset, constantPool, type);
|
||||
PcodeTextEmitter.emitIndirectCall(pCode, CALL_TARGET);
|
||||
|
||||
JavaComputationalCategory retType = DescriptorDecoder.getReturnCategoryOfMethodDescriptor(descriptor);
|
||||
switch (retType){
|
||||
|
||||
JavaComputationalCategory retType =
|
||||
DescriptorDecoder.getReturnCategoryOfMethodDescriptor(descriptor);
|
||||
switch (retType) {
|
||||
case CAT_1:
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, CAT_1_RETURN);
|
||||
break;
|
||||
@@ -80,6 +84,42 @@ public class InvokeMethods {
|
||||
return pCode.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits the pcode for an invoke instruction.
|
||||
* @param offset - the index of the constant pool element containing a symbolic reference
|
||||
* to a method or a call site specifier.
|
||||
* @param constantPool - the constant pool
|
||||
* @return - the pcode as a string
|
||||
*/
|
||||
public static String getPcodeForInvokeDynamic(int offset,
|
||||
AbstractConstantPoolInfoJava[] constantPool) {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
String invokeDynamicDescriptor = DescriptorDecoder.getDescriptorForInvoke(offset,
|
||||
constantPool, JavaInvocationType.INVOKE_DYNAMIC);
|
||||
List<JavaComputationalCategory> categories =
|
||||
DescriptorDecoder.getParameterCategories(invokeDynamicDescriptor);
|
||||
|
||||
int stackPurge = DescriptorDecoder.getStackPurge(invokeDynamicDescriptor);
|
||||
|
||||
emitPcodeToMoveParams(pCode, categories, false, stackPurge);
|
||||
emitPcodeToResolveMethodReference(pCode, offset, constantPool,
|
||||
JavaInvocationType.INVOKE_DYNAMIC);
|
||||
PcodeTextEmitter.emitIndirectCall(pCode, CALL_TARGET);
|
||||
|
||||
JavaComputationalCategory retType =
|
||||
DescriptorDecoder.getReturnCategoryOfMethodDescriptor(invokeDynamicDescriptor);
|
||||
switch (retType) {
|
||||
case CAT_1:
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, CAT_1_RETURN);
|
||||
break;
|
||||
case CAT_2:
|
||||
PcodeTextEmitter.emitPushCat2Value(pCode, CAT_2_RETURN);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return pCode.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits pcode to move the parameters from the stack to the space parameterSpace
|
||||
@@ -89,21 +129,26 @@ public class InvokeMethods {
|
||||
* @param categories - the list of computational categories on the top of the stack
|
||||
* @param includeThisPointer - true if the first element on the stack is an implicit this parameter
|
||||
*/
|
||||
static void emitPcodeToMoveParams(StringBuilder pCode, List<JavaComputationalCategory> categories, boolean includeThisPointer, int totalSize){
|
||||
|
||||
static void emitPcodeToMoveParams(StringBuilder pCode,
|
||||
List<JavaComputationalCategory> categories, boolean includeThisPointer, int totalSize) {
|
||||
|
||||
//pop the parameters off of the stack
|
||||
for (int i = categories.size() - 1; i >= 0; --i){
|
||||
switch (categories.get(i)){
|
||||
for (int i = categories.size() - 1; i >= 0; --i) {
|
||||
switch (categories.get(i)) {
|
||||
case CAT_1:
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER + Integer.toString(i));
|
||||
totalSize -= 4;
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize) + ":4", PARAMETER + Integer.toString(i));
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4,
|
||||
Integer.toString(totalSize) + ":4", PARAMETER + Integer.toString(i));
|
||||
break;
|
||||
case CAT_2:
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER + Integer.toString(i));
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize-8) + ":4", PARAMETER + Integer.toString(i));
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4,
|
||||
Integer.toString(totalSize - 8) + ":4", PARAMETER + Integer.toString(i));
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER_PART2 + Integer.toString(i));
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize-4) + ":4", PARAMETER_PART2 + Integer.toString(i));
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4,
|
||||
Integer.toString(totalSize - 4) + ":4",
|
||||
PARAMETER_PART2 + Integer.toString(i));
|
||||
totalSize -= 8;
|
||||
break;
|
||||
default:
|
||||
@@ -111,15 +156,15 @@ public class InvokeMethods {
|
||||
}
|
||||
}
|
||||
//pop off the this pointer if there is one
|
||||
if (includeThisPointer){
|
||||
if (includeThisPointer) {
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, THIS);
|
||||
totalSize -= 4;
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize) + ":4", THIS);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4,
|
||||
Integer.toString(totalSize) + ":4", THIS);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Emits pcode to assign the result of a cpool op to the call_target register for an invocation.
|
||||
* @param pCode - the pcode buffer
|
||||
@@ -127,25 +172,37 @@ public class InvokeMethods {
|
||||
* @param constantPool - the constant pool
|
||||
* @param type - the type of the invocation
|
||||
*/
|
||||
static void emitPcodeToResolveMethodReference(StringBuilder pCode, int offset, AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type){
|
||||
switch (type){
|
||||
static void emitPcodeToResolveMethodReference(StringBuilder pCode, int offset,
|
||||
AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) {
|
||||
switch (type) {
|
||||
case INVOKE_DYNAMIC:
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
|
||||
ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset),
|
||||
ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
|
||||
break;
|
||||
case INVOKE_INTERFACE:
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKEINTERFACE);
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
|
||||
ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset),
|
||||
ConstantPoolJava.CPOOL_INVOKEINTERFACE);
|
||||
break;
|
||||
case INVOKE_SPECIAL:
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKESPECIAL);
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
|
||||
ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset),
|
||||
ConstantPoolJava.CPOOL_INVOKESPECIAL);
|
||||
break;
|
||||
case INVOKE_STATIC:
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKESTATIC);
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
|
||||
ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset),
|
||||
ConstantPoolJava.CPOOL_INVOKESTATIC);
|
||||
break;
|
||||
case INVOKE_VIRTUAL:
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
|
||||
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
|
||||
ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset),
|
||||
ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unimplemented JavaMethodType: " + type.toString());
|
||||
throw new IllegalArgumentException(
|
||||
"Unimplemented JavaMethodType: " + type.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-18
@@ -79,18 +79,7 @@ import ghidra.program.model.listing.Program;
|
||||
* (Use/add to PcodeTextEmitter.java to actually emit pcode text)
|
||||
* See ConstantPoolJava.java for examples of the use of the CPOOL pcode op.
|
||||
*
|
||||
* TODO:
|
||||
* 1) For the lookupswitch op, the disassembly is correct but the decompilation is not.
|
||||
* There are several possible ways of modeling the instruction in pcode - either using
|
||||
* injection (SwitchMethods.java) or pcode (JVM.slaspec). In all cases, there seems to
|
||||
* be an issue with getting the decompiler to follow pointers to the various switch clauses.
|
||||
* The file LookupSwitchHex.java in the resource directory contains a class file with
|
||||
* 4 methods with switch statements. Currently the first method is modeled using a
|
||||
* pcode loop and the last three are modeled using pcode injection (which is possible because
|
||||
* there are actually 4 separate lookupswitch instructions, the only difference is the amount
|
||||
* of padding bytes).
|
||||
*
|
||||
* possible improvements:
|
||||
* possible improvements:
|
||||
*
|
||||
* 2) incorporate exceptions.
|
||||
* 6) decide how to display the information used in an invokedynamic instruction
|
||||
@@ -121,7 +110,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
|
||||
public static final String LDC = "ldcCallOther";
|
||||
public static final String LDC2_W = "ldc2_wCallOther";
|
||||
public static final String LDC_W = "ldc_wCallOther";
|
||||
public static final String LOOKUP_SWITCH = "lookupswitchCallOther";
|
||||
public static final String MULTIANEWARRAY = "multianewarrayCallOther";
|
||||
|
||||
public static final String PUTFIELD = "putFieldCallOther";
|
||||
@@ -149,7 +137,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
|
||||
implementedOps.add(LDC);
|
||||
implementedOps.add(LDC2_W);
|
||||
implementedOps.add(LDC_W);
|
||||
implementedOps.add(LOOKUP_SWITCH);
|
||||
implementedOps.add(MULTIANEWARRAY);
|
||||
implementedOps.add(PUTFIELD);
|
||||
implementedOps.add(PUTSTATIC);
|
||||
@@ -170,8 +157,9 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
|
||||
@Override
|
||||
protected InjectPayloadSleigh allocateInject(String sourceName, String name, int tp) {
|
||||
InjectPayloadJava payload = null;
|
||||
if (tp != InjectPayload.CALLOTHERFIXUP_TYPE)
|
||||
if (tp != InjectPayload.CALLOTHERFIXUP_TYPE) {
|
||||
return super.allocateInject(sourceName, name, tp);
|
||||
}
|
||||
switch (name) {
|
||||
case GETFIELD:
|
||||
payload = new InjectGetField(sourceName, language);
|
||||
@@ -199,9 +187,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
|
||||
case LDC_W:
|
||||
payload = new InjectLdc(sourceName, language);
|
||||
break;
|
||||
case LOOKUP_SWITCH:
|
||||
payload = new InjectLookupSwitch(sourceName, language);
|
||||
break;
|
||||
case MULTIANEWARRAY:
|
||||
payload = new InjectMultiANewArray(sourceName, language);
|
||||
break;
|
||||
|
||||
+94
-47
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package ghidra.app.util.pcodeInject;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* This is a utility class containing methods to emit pcode for decompile callbacks occurring during analysis of
|
||||
@@ -27,22 +26,22 @@ package ghidra.app.util.pcodeInject;
|
||||
*/
|
||||
public class PcodeTextEmitter {
|
||||
|
||||
static final String RAM = "ram";
|
||||
static final String RAM = "ram";
|
||||
|
||||
//private constructor to enforce noninstantiability
|
||||
private PcodeTextEmitter(){
|
||||
private PcodeTextEmitter() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Emits pcode to push a value of computational category 1 onto the stack.
|
||||
* @param pCode - StringBuilder to hold pcode.
|
||||
* @param valueName - name of varnode to push.
|
||||
*/
|
||||
public static void emitPushCat1Value(StringBuilder pCode, String valueName){
|
||||
public static void emitPushCat1Value(StringBuilder pCode, String valueName) {
|
||||
pCode.append("SP = SP - 4;\n*:4 SP = ");
|
||||
pCode.append(valueName);
|
||||
pCode.append(";\n");
|
||||
pCode.append(";\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,10 +49,10 @@ public class PcodeTextEmitter {
|
||||
* @param pCode - StringBuilder to hold pcode.
|
||||
* @param valueName - name of varnode to push.
|
||||
*/
|
||||
public static void emitPushCat2Value(StringBuilder pCode, String valueName){
|
||||
public static void emitPushCat2Value(StringBuilder pCode, String valueName) {
|
||||
pCode.append("SP = SP - 8;\n*:8 SP = ");
|
||||
pCode.append(valueName);
|
||||
pCode.append(";\n");
|
||||
pCode.append(";\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,9 +60,9 @@ public class PcodeTextEmitter {
|
||||
* @param pCode - StringBuilder to hold pcode.
|
||||
* @param destName - name of destination varnode.
|
||||
*/
|
||||
public static void emitPopCat2Value(StringBuilder pCode, String destName){
|
||||
public static void emitPopCat2Value(StringBuilder pCode, String destName) {
|
||||
pCode.append(destName);
|
||||
pCode.append(":8 = *:8 SP;\nSP = SP + 8;\n");
|
||||
pCode.append(":8 = *:8 SP;\nSP = SP + 8;\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,9 +70,9 @@ public class PcodeTextEmitter {
|
||||
* @param pCode - StringBuilder to hold pcode.
|
||||
* @param destName - name of destination varnode.
|
||||
*/
|
||||
public static void emitPopCat1Value(StringBuilder pCode, String destName){
|
||||
public static void emitPopCat1Value(StringBuilder pCode, String destName) {
|
||||
pCode.append(destName);
|
||||
pCode.append(":4 = *:4 SP;\nSP = SP + 4;\n");
|
||||
pCode.append(":4 = *:4 SP;\nSP = SP + 4;\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,56 +82,55 @@ public class PcodeTextEmitter {
|
||||
* @param pcodeop - name of pcodeop
|
||||
* @param args - zero or more arguments for the pcodeop
|
||||
*/
|
||||
public static void emitAssignVarnodeFromPcodeOpCall(StringBuilder pCode, String varnodeName, int size, String pcodeop, String... args){
|
||||
public static void emitAssignVarnodeFromPcodeOpCall(StringBuilder pCode, String varnodeName,
|
||||
int size, String pcodeop, String... args) {
|
||||
pCode.append(varnodeName);
|
||||
pCode.append(":");
|
||||
pCode.append(":");
|
||||
pCode.append(Integer.toString(size));
|
||||
pCode.append(" = ");
|
||||
pCode.append(" = ");
|
||||
pCode.append(pcodeop);
|
||||
pCode.append("(");
|
||||
for (int i = 0, numArgs = args.length; i < numArgs; ++i){
|
||||
for (int i = 0, numArgs = args.length; i < numArgs; ++i) {
|
||||
pCode.append(args[i]);
|
||||
if (i < numArgs - 1){
|
||||
if (i < numArgs - 1) {
|
||||
pCode.append(",");
|
||||
}
|
||||
}
|
||||
pCode.append(");\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Emits pcode to call a void black-box pcodeop
|
||||
* @param pCode StringBuilder to hold the pcode
|
||||
* @param pcodeop - name of pcodeop
|
||||
* @param args - zero or more arguments for the pcodeop
|
||||
*/
|
||||
public static void emitVoidPcodeOpCall(StringBuilder pCode, String pcodeop, String... args){
|
||||
public static void emitVoidPcodeOpCall(StringBuilder pCode, String pcodeop, String... args) {
|
||||
pCode.append(pcodeop);
|
||||
pCode.append("(");
|
||||
for (int i = 0, numArgs = args.length; i < numArgs; ++i){
|
||||
for (int i = 0, numArgs = args.length; i < numArgs; ++i) {
|
||||
pCode.append(args[i]);
|
||||
if (i < numArgs - 1){
|
||||
if (i < numArgs - 1) {
|
||||
pCode.append(",");
|
||||
}
|
||||
}
|
||||
pCode.append(");\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appends the pcode to assign an integer constant to a register
|
||||
* @param pCode
|
||||
* @param constantPool
|
||||
* @param index
|
||||
*/
|
||||
public static void emitAssignConstantToRegister(StringBuilder pCode, String register, int constant){
|
||||
public static void emitAssignConstantToRegister(StringBuilder pCode, String register,
|
||||
int constant) {
|
||||
pCode.append(register);
|
||||
pCode.append(" = 0x");
|
||||
pCode.append(Integer.toHexString(constant));
|
||||
pCode.append(";\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Appends the pcode to assign a register to the result of a pcode op call with arguments args
|
||||
* @param pCode
|
||||
@@ -140,32 +138,42 @@ public class PcodeTextEmitter {
|
||||
* @param pcodeop
|
||||
* @param args
|
||||
*/
|
||||
public static void emitAssignRegisterFromPcodeOpCall(StringBuilder pCode, String register, String pcodeop, String... args){
|
||||
public static void emitAssignRegisterFromPcodeOpCall(StringBuilder pCode, String register,
|
||||
String pcodeop, String... args) {
|
||||
pCode.append(register);
|
||||
pCode.append(" = ");
|
||||
pCode.append(pcodeop);
|
||||
pCode.append("(");
|
||||
for (int i = 0, numArgs = args.length; i < numArgs; ++i){
|
||||
for (int i = 0, numArgs = args.length; i < numArgs; ++i) {
|
||||
pCode.append(args[i]);
|
||||
if (i < numArgs - 1){
|
||||
if (i < numArgs - 1) {
|
||||
pCode.append(",");
|
||||
}
|
||||
}
|
||||
pCode.append(");\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appends the pcode to emit a label definition.
|
||||
* @param pCode
|
||||
* @param caseName
|
||||
*/
|
||||
public static void emitLabelDefinition(StringBuilder pCode, String caseName){
|
||||
public static void emitLabelDefinition(StringBuilder pCode, String caseName) {
|
||||
pCode.append("<");
|
||||
pCode.append(caseName);
|
||||
pCode.append(">\n");
|
||||
}
|
||||
|
||||
public static void emitWriteToMemory(StringBuilder pCode, String space, int size, String offset, String value){
|
||||
|
||||
/**
|
||||
* Appends the pcode to write to a value at an offset of a memory space
|
||||
* @param pCode buffer to append pcode
|
||||
* @param space name of space
|
||||
* @param size size of write
|
||||
* @param offset offset in space
|
||||
* @param value value to write
|
||||
*/
|
||||
public static void emitWriteToMemory(StringBuilder pCode, String space, int size, String offset,
|
||||
String value) {
|
||||
pCode.append("*[");
|
||||
pCode.append(space);
|
||||
pCode.append("]:");
|
||||
@@ -177,19 +185,25 @@ public class PcodeTextEmitter {
|
||||
pCode.append(";\n");
|
||||
}
|
||||
|
||||
public static void emitIndirectCall(StringBuilder pCode, String target){
|
||||
/**
|
||||
* Appends the pcode to emit an indirect call
|
||||
* @param pCode buffer to append to
|
||||
* @param target varnode to call indirectly
|
||||
*/
|
||||
public static void emitIndirectCall(StringBuilder pCode, String target) {
|
||||
pCode.append("call [");
|
||||
pCode.append(target);
|
||||
pCode.append("];\n");
|
||||
}
|
||||
|
||||
public static void emitAddToStackPointer(StringBuilder pCode, int amount){
|
||||
pCode.append("SP = SP + ");
|
||||
pCode.append(Integer.toString(amount));
|
||||
pCode.append(";\n");
|
||||
}
|
||||
|
||||
public static void emitSignExtension(StringBuilder pCode, String dest, int size, String src){
|
||||
|
||||
/**
|
||||
* Appends the pcode to sign-extend the value src into dest
|
||||
* @param pCode buffer to append to
|
||||
* @param dest target varnode
|
||||
* @param size size of target varnode
|
||||
* @param src size of source varnode
|
||||
*/
|
||||
public static void emitSignExtension(StringBuilder pCode, String dest, int size, String src) {
|
||||
pCode.append(dest);
|
||||
pCode.append(":");
|
||||
pCode.append(Integer.toString(size));
|
||||
@@ -197,8 +211,15 @@ public class PcodeTextEmitter {
|
||||
pCode.append(src);
|
||||
pCode.append(");\n");
|
||||
}
|
||||
|
||||
public static void emitZeroExtension(StringBuilder pCode, String dest, int size, String src){
|
||||
|
||||
/**
|
||||
* Appends the pcode to zero-extend the value src into dest
|
||||
* @param pCode buffer to append to
|
||||
* @param dest target varnode
|
||||
* @param size size of target varnode
|
||||
* @param src size of source varnode
|
||||
*/
|
||||
public static void emitZeroExtension(StringBuilder pCode, String dest, int size, String src) {
|
||||
pCode.append(dest);
|
||||
pCode.append(":");
|
||||
pCode.append(Integer.toString(size));
|
||||
@@ -206,8 +227,15 @@ public class PcodeTextEmitter {
|
||||
pCode.append(src);
|
||||
pCode.append(");\n");
|
||||
}
|
||||
|
||||
public static void emitTruncate(StringBuilder pCode, String dest, int size, String src){
|
||||
|
||||
/**
|
||||
* Appends the pcode truncate src into dest
|
||||
* @param pCode buffer to append to
|
||||
* @param dest target varnode
|
||||
* @param size size of target varnode
|
||||
* @param src size of source varnode
|
||||
*/
|
||||
public static void emitTruncate(StringBuilder pCode, String dest, int size, String src) {
|
||||
pCode.append(dest);
|
||||
pCode.append(" = ");
|
||||
pCode.append(src);
|
||||
@@ -215,6 +243,25 @@ public class PcodeTextEmitter {
|
||||
pCode.append(Integer.toString(size));
|
||||
pCode.append(";\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Appends the pcode to assign a varnode from a dereference of another varnode
|
||||
* @param pCode buffer to append to
|
||||
* @param lhs target varnode
|
||||
* @param size size of pointed-to value
|
||||
* @param rhs varnode to dereference
|
||||
*/
|
||||
public static void emitAssignVarnodeFromDereference(StringBuilder pCode, String lhs, int size,
|
||||
String rhs) {
|
||||
pCode.append(lhs);
|
||||
pCode.append(":");
|
||||
pCode.append(Integer.toString(size));
|
||||
pCode.append(" = ");
|
||||
pCode.append("*:");
|
||||
pCode.append(Integer.toString(size));
|
||||
pCode.append(" ");
|
||||
pCode.append(rhs);
|
||||
pCode.append(";\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+176
-104
@@ -16,10 +16,7 @@
|
||||
package ghidra.app.util.pcodeInject;
|
||||
|
||||
import ghidra.javaclass.format.DescriptorDecoder;
|
||||
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolFieldReferenceInfo;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolNameAndTypeInfo;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
|
||||
import ghidra.javaclass.format.constantpool.*;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -37,14 +34,15 @@ import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
|
||||
public class ReferenceMethods {
|
||||
|
||||
static final String VALUE = "value";
|
||||
static final String TEMP = "temp";
|
||||
static final String TEMP_1 = "temp_1";
|
||||
static final String TEMP_2 = "temp_2";
|
||||
static final String NEW_VALUE = "newValue";
|
||||
static final String OBJECT_REF = "objectRef";
|
||||
static final String FIELD_OFFSET = "fieldOffset";
|
||||
static final String STATIC_OFFSET = "staticOffset";
|
||||
|
||||
//private constructor to enforce noninstantiability
|
||||
private ReferenceMethods(){
|
||||
private ReferenceMethods() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@@ -54,44 +52,63 @@ public class ReferenceMethods {
|
||||
* @param constantPool - the constant pool of the class file
|
||||
* @return - the pcode string
|
||||
*/
|
||||
public static String getPcodeForGetStatic(int index, AbstractConstantPoolInfoJava[] constantPool) {
|
||||
public static String getPcodeForGetStatic(int index,
|
||||
AbstractConstantPoolInfoJava[] constantPool) {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
//determine the computational category and push a value of the correct size onto the operand stack
|
||||
String descriptor = getDescriptorForFieldRef(constantPool, index);
|
||||
|
||||
switch (descriptor.charAt(0)){
|
||||
|
||||
switch (descriptor.charAt(0)) {
|
||||
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_CHAR: //char
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension
|
||||
case DescriptorDecoder.BASE_TYPE_FLOAT: //float
|
||||
case DescriptorDecoder.BASE_TYPE_INT: //int
|
||||
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 4,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 4, TEMP_1);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
|
||||
case DescriptorDecoder.BASE_TYPE_LONG: //long
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 8, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitPushCat2Value(pCode,VALUE);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 8,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETSTATIC);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 8, TEMP_1);
|
||||
PcodeTextEmitter.emitPushCat2Value(pCode, VALUE);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
|
||||
}
|
||||
@@ -104,49 +121,68 @@ public class ReferenceMethods {
|
||||
* @param constantPool - the constant pool of the class file
|
||||
* @return - the pcode string
|
||||
*/
|
||||
public static String getPcodeForPutStatic(int index, AbstractConstantPoolInfoJava[] constantPool){
|
||||
public static String getPcodeForPutStatic(int index,
|
||||
AbstractConstantPoolInfoJava[] constantPool) {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
String descriptor = getDescriptorForFieldRef(constantPool, index);
|
||||
|
||||
switch (descriptor.charAt(0)){
|
||||
|
||||
switch (descriptor.charAt(0)) {
|
||||
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET, TEMP);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET, TEMP);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_CHAR: //char
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET, TEMP);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET, TEMP);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension
|
||||
case DescriptorDecoder.BASE_TYPE_FLOAT: //float
|
||||
case DescriptorDecoder.BASE_TYPE_INT: //int
|
||||
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, STATIC_OFFSET, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, STATIC_OFFSET,
|
||||
NEW_VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
|
||||
case DescriptorDecoder.BASE_TYPE_LONG: //long
|
||||
PcodeTextEmitter.emitPopCat2Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, STATIC_OFFSET, NEW_VALUE);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTSTATIC);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, STATIC_OFFSET,
|
||||
NEW_VALUE);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
|
||||
}
|
||||
@@ -159,50 +195,69 @@ public class ReferenceMethods {
|
||||
* @param constantPool
|
||||
* @return - the pcode string
|
||||
*/
|
||||
public static String getPcodeForGetField(int index, AbstractConstantPoolInfoJava[] constantPool) {
|
||||
public static String getPcodeForGetField(int index,
|
||||
AbstractConstantPoolInfoJava[] constantPool) {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
|
||||
String descriptor = getDescriptorForFieldRef(constantPool, index);
|
||||
|
||||
switch (descriptor.charAt(0)){
|
||||
|
||||
switch (descriptor.charAt(0)) {
|
||||
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_CHAR: //char
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1);
|
||||
PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1);
|
||||
PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension
|
||||
case DescriptorDecoder.BASE_TYPE_FLOAT: //float
|
||||
case DescriptorDecoder.BASE_TYPE_INT: //int
|
||||
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode,VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 4,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 4, TEMP_1);
|
||||
PcodeTextEmitter.emitPushCat1Value(pCode, VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
|
||||
case DescriptorDecoder.BASE_TYPE_LONG: //long
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 8, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitPushCat2Value(pCode,VALUE);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 8,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_GETFIELD);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 8, TEMP_1);
|
||||
PcodeTextEmitter.emitPushCat2Value(pCode, VALUE);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
|
||||
}
|
||||
@@ -215,64 +270,81 @@ public class ReferenceMethods {
|
||||
* @param constantPool - the constant pool
|
||||
* @return - the pcode
|
||||
*/
|
||||
public static String getPcodeForPutField(int index, AbstractConstantPoolInfoJava[] constantPool) {
|
||||
public static String getPcodeForPutField(int index,
|
||||
AbstractConstantPoolInfoJava[] constantPool) {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
|
||||
//determine the computational category and push a value of the correct size onto the operand stack
|
||||
String descriptor = getDescriptorForFieldRef(constantPool, index);
|
||||
|
||||
|
||||
switch (descriptor.charAt(0)){
|
||||
|
||||
switch (descriptor.charAt(0)) {
|
||||
case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET, TEMP);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET, TEMP);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_CHAR: //char
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET, TEMP);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_SHORT: //signed short
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET, TEMP);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET,
|
||||
TEMP_1);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension
|
||||
case DescriptorDecoder.BASE_TYPE_FLOAT: //float
|
||||
case DescriptorDecoder.BASE_TYPE_INT: //int
|
||||
case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, FIELD_OFFSET, NEW_VALUE);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, FIELD_OFFSET,
|
||||
NEW_VALUE);
|
||||
break;
|
||||
case DescriptorDecoder.BASE_TYPE_DOUBLE: //double
|
||||
case DescriptorDecoder.BASE_TYPE_LONG: //long
|
||||
PcodeTextEmitter.emitPopCat2Value(pCode, NEW_VALUE);
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF);
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, FIELD_OFFSET, NEW_VALUE);
|
||||
break;
|
||||
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4,
|
||||
ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index),
|
||||
ConstantPoolJava.CPOOL_PUTFIELD);
|
||||
PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, FIELD_OFFSET,
|
||||
NEW_VALUE);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid descriptor: " + descriptor);
|
||||
}
|
||||
return pCode.toString();
|
||||
|
||||
|
||||
|
||||
/*JavaComputationalCategory category = DescriptorDecoder.getComputationalCategoryOfDescriptor(descriptor);
|
||||
switch (category){
|
||||
case CAT_1:
|
||||
@@ -295,21 +367,21 @@ public class ReferenceMethods {
|
||||
return pCode.toString();*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the descriptor of a field reference in the constant pool
|
||||
* @param constantPool
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
static String getDescriptorForFieldRef(AbstractConstantPoolInfoJava[] constantPool, int index){
|
||||
ConstantPoolFieldReferenceInfo fieldRef = (ConstantPoolFieldReferenceInfo) constantPool[index];
|
||||
static String getDescriptorForFieldRef(AbstractConstantPoolInfoJava[] constantPool, int index) {
|
||||
ConstantPoolFieldReferenceInfo fieldRef =
|
||||
(ConstantPoolFieldReferenceInfo) constantPool[index];
|
||||
int nameAndTypeIndex = fieldRef.getNameAndTypeIndex();
|
||||
ConstantPoolNameAndTypeInfo nameAndTypeInfo = (ConstantPoolNameAndTypeInfo) constantPool[nameAndTypeIndex];
|
||||
ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
|
||||
return descriptorInfo.getString();
|
||||
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
|
||||
(ConstantPoolNameAndTypeInfo) constantPool[nameAndTypeIndex];
|
||||
ConstantPoolUtf8Info descriptorInfo =
|
||||
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
|
||||
return descriptorInfo.getString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.util.pcodeInject;
|
||||
|
||||
/**
|
||||
*
|
||||
* This is a utility class for generating pcode for the lookupswitch operation.
|
||||
*
|
||||
* This class is evolving and may eventually be replaced.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.ByteProvider;
|
||||
import ghidra.app.util.bin.MemoryByteProvider;
|
||||
import ghidra.program.model.lang.InjectContext;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
public class SwitchMethods {
|
||||
|
||||
static final String KEY = "key";
|
||||
static final String SWITCH_TARGET = "switch_target";
|
||||
|
||||
public static String getPcodeForLookupSwitch(InjectContext injectContext, Program program) throws IOException {
|
||||
StringBuilder pCode = new StringBuilder();
|
||||
|
||||
int defaultAddr = (int) injectContext.inputlist.get(0).getOffset();
|
||||
int numPairs = (int) injectContext.inputlist.get(1).getOffset();
|
||||
int padding = (int) injectContext.inputlist.get(2).getOffset();
|
||||
|
||||
PcodeTextEmitter.emitPopCat1Value(pCode, KEY);
|
||||
|
||||
int target = (int) (injectContext.baseAddr.getOffset() + defaultAddr);
|
||||
PcodeTextEmitter.emitAssignConstantToRegister(pCode, SWITCH_TARGET, target);
|
||||
ByteProvider provider = new MemoryByteProvider(program.getMemory(),injectContext.baseAddr);
|
||||
byte[] bytes = provider.readBytes(1 + padding + 8, 8 * numPairs);
|
||||
for (int i = 0, length = bytes.length ; i < length; i += 8){
|
||||
int match = ((bytes[i] << 24) & 0xff000000) | ((bytes[i+1] << 16) & 0xff0000) | ((bytes[i+2] <<8) & 0xff00) | (bytes[i+3] & 0xff);
|
||||
int offset = ((bytes[i+4] << 24) & 0xff000000) | ((bytes[i+5] << 16) & 0xff0000) | ((bytes[i+6] <<8) & 0xff00) | (bytes[i+7] & 0xff);
|
||||
target = (int) (injectContext.baseAddr.getOffset() + offset);
|
||||
pCode.append("if (key != " + match +") goto <test"+i+">;\n");
|
||||
pCode.append(SWITCH_TARGET);
|
||||
pCode.append(" = inst_start + " +offset+ ";\n");
|
||||
//uncomment this to have the decompiler display multiple switch(address) statements
|
||||
//pCode.append("goto [switch_target];\n");
|
||||
PcodeTextEmitter.emitLabelDefinition(pCode, "test"+i);
|
||||
}
|
||||
pCode.append("SP=SP;\n");
|
||||
provider.close();
|
||||
return pCode.toString();
|
||||
}
|
||||
}
|
||||
|
||||
+256
-312
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,23 +15,33 @@
|
||||
*/
|
||||
package ghidra.javaclass.flags;
|
||||
|
||||
public final class ClassFileFlags {
|
||||
public enum ClassFileFlags {
|
||||
|
||||
/** Declared public; may be accessed from outside its package. */
|
||||
public final static short ACC_PUBLIC = 0x0001;
|
||||
ACC_PUBLIC(0x0001),
|
||||
/** Declared final; no subclasses allowed. */
|
||||
public final static short ACC_FINAL = 0x0010;
|
||||
ACC_FINAL(0x0010),
|
||||
/** Treat superclass methods specially when invoked by the invokespecial instruction. */
|
||||
public final static short ACC_SUPER = 0x0020;
|
||||
ACC_SUPER(0x0020),
|
||||
/** Is an interface, not a class. */
|
||||
public final static short ACC_INTERFACE = 0x0200;
|
||||
ACC_INTERFACE(0x0200),
|
||||
/** Declared abstract; must not be instantiated. */
|
||||
public final static short ACC_ABSTRACT = 0x0400;
|
||||
ACC_ABSTRACT(0x0400),
|
||||
/** Declared synthetic; not present in the source code. */
|
||||
public final static short ACC_SYNTHETIC = 0x1000;
|
||||
ACC_SYNTHETIC(0x1000),
|
||||
/** Declared as an annotation type. */
|
||||
public final static short ACC_ANNOTATION = 0x2000;
|
||||
ACC_ANNOTATION(0x2000),
|
||||
/** Declared as an enum type. */
|
||||
public final static short ACC_ENUM = 0x4000;
|
||||
ACC_ENUM(0x4000);
|
||||
|
||||
private int value;
|
||||
|
||||
private ClassFileFlags(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+19
-12
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,25 +15,33 @@
|
||||
*/
|
||||
package ghidra.javaclass.flags;
|
||||
|
||||
final class FieldInfoAccessFlags {
|
||||
|
||||
public enum FieldInfoAccessFlags {
|
||||
/** Declared public; may be accessed from outside its package. */
|
||||
public final short ACC_PUBLIC = 0x0001;
|
||||
ACC_PUBLIC(0x0001),
|
||||
/** Declared private; usable only within the defining class. */
|
||||
public final short ACC_PRIVATE = 0x0002;
|
||||
ACC_PRIVATE(0x0002),
|
||||
/** Declared protected; may be accessed within subclasses. */
|
||||
public final short ACC_PROTECTED = 0x0004;
|
||||
ACC_PROTECTED(0x0004),
|
||||
/** Declared static. */
|
||||
public final short ACC_STATIC = 0x0008;
|
||||
ACC_STATIC(0x0008),
|
||||
/** Declared final; never directly assigned to after object construction (JLS ?17.5). */
|
||||
public final short ACC_FINAL = 0x0010;
|
||||
ACC_FINAL(0x0010),
|
||||
/** Declared volatile; cannot be cached. */
|
||||
public final short ACC_VOLATILE = 0x0040;
|
||||
ACC_VOLATILE(0x00400),
|
||||
/** Declared transient; not written or read by a persistent object manager. */
|
||||
public final short ACC_TRANSIENT = 0x0080;
|
||||
ACC_TRANSIENT(0x0080),
|
||||
/** Declared synthetic; not present in the source code. */
|
||||
public final short ACC_SYNTHETIC = 0x1000;
|
||||
ACC_SYNTHETIC(0x1000),
|
||||
/** Declared as an element of an enum. */
|
||||
public final short ACC_ENUM = 0x4000;
|
||||
ACC_ENUM(0x4000);
|
||||
|
||||
private int value;
|
||||
|
||||
private FieldInfoAccessFlags(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
+64
-14
@@ -15,31 +15,81 @@
|
||||
*/
|
||||
package ghidra.javaclass.flags;
|
||||
|
||||
public final class MethodsInfoAccessFlags {
|
||||
|
||||
public enum MethodsInfoAccessFlags {
|
||||
/** Declared public; may be accessed from outside its package. */
|
||||
public final static short ACC_PUBLIC = 0x0001;
|
||||
ACC_PUBLIC(0x0001),
|
||||
/** Declared private; accessible only within the defining class. */
|
||||
public final static short ACC_PRIVATE = 0x0002;
|
||||
ACC_PRIVATE(0x0002),
|
||||
/** Declared protected; may be accessed within subclasses. */
|
||||
public final static short ACC_PROTECTED = 0x0004;
|
||||
ACC_PROTECTED(0x0004),
|
||||
/** Declared static. */
|
||||
public final static short ACC_STATIC = 0x0008;
|
||||
ACC_STATIC(0x0008),
|
||||
/** Declared final; must not be overridden (5.4.5). */
|
||||
public final static short ACC_FINAL = 0x0010;
|
||||
ACC_FINAL(0x0010),
|
||||
/** Declared synchronized; invocation is wrapped by a monitor use. */
|
||||
public final static short ACC_SYNCHRONIZED = 0x0020;
|
||||
ACC_SYNCHRONIZED(0x0020),
|
||||
/** A bridge method, generated by the compiler. */
|
||||
public final static short ACC_BRIDGE = 0x0040;
|
||||
ACC_BRIDGE(0x0040),
|
||||
/** Declared with variable number of arguments. */
|
||||
public final static short ACC_VARARGS = 0x0080;
|
||||
ACC_VARARGS(0x0080),
|
||||
/** Declared native; implemented in a language other than Java. */
|
||||
public final static short ACC_NATIVE = 0x0100;
|
||||
ACC_NATIVE(0x0100),
|
||||
/** Declared abstract; no implementation is provided. */
|
||||
public final static short ACC_ABSTRACT = 0x0400;
|
||||
ACC_ABSTRACT(0x0400),
|
||||
/** Declared strictfp; floating-point mode is FP-strict. */
|
||||
public final static short ACC_STRICT = 0x0800;
|
||||
ACC_STRICT(0x0800),
|
||||
/** Declared synthetic; not present in the source code. */
|
||||
public final static short ACC_SYNTHETIC = 0x1000;
|
||||
ACC_SYNTHETIC(0x1000);
|
||||
|
||||
private final int value;
|
||||
|
||||
private MethodsInfoAccessFlags(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a text representation for a given set of access flags.
|
||||
* Here are some examples:
|
||||
* <DL>
|
||||
* <DD><CODE>"public static final"</CODE>,</DD>
|
||||
* <DD><CODE>"package private"</CODE>, or</DD>
|
||||
* <DD><CODE>"protected transient"</CODE>.</DD>
|
||||
* </DL>
|
||||
* Note: only access flags that map to Java modifier keywords are returned.
|
||||
* @param access the mask of flags denoting access permission.
|
||||
* @return a text representation of the access flags.
|
||||
*/
|
||||
public static String toString(int access) {
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
if ((access & ACC_PUBLIC.value) == ACC_PUBLIC.value) {
|
||||
stringBuffer.append("public ");
|
||||
}
|
||||
if ((access & ACC_PRIVATE.value) == ACC_PRIVATE.value) {
|
||||
stringBuffer.append("private ");
|
||||
}
|
||||
if ((access & ACC_PROTECTED.value) == ACC_PROTECTED.value) {
|
||||
stringBuffer.append("protected ");
|
||||
}
|
||||
if ((access & ACC_STATIC.value) == ACC_STATIC.value) {
|
||||
stringBuffer.append("static ");
|
||||
}
|
||||
if ((access & ACC_FINAL.value) == ACC_FINAL.value) {
|
||||
stringBuffer.append("final ");
|
||||
}
|
||||
if ((access & ACC_SYNCHRONIZED.value) == ACC_SYNCHRONIZED.value) {
|
||||
stringBuffer.append("synchronized ");
|
||||
}
|
||||
if ((access & ACC_NATIVE.value) == ACC_NATIVE.value) {
|
||||
stringBuffer.append("native ");
|
||||
}
|
||||
if ((access & ACC_ABSTRACT.value) == ACC_ABSTRACT.value) {
|
||||
stringBuffer.append("abstract ");
|
||||
}
|
||||
return stringBuffer.toString().trim();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.javaclass.format;
|
||||
|
||||
/**
|
||||
* A utility class defining access flags and access utility methods.
|
||||
* Access flags are as defined by the Java Virtual Machine Specification
|
||||
* Second Edition, tables 4.1, 4.4, 4.5 and 4.7.
|
||||
*/
|
||||
public abstract class AccessFlagsJava {
|
||||
|
||||
/** Declared public, may be accessed from outside its package. */
|
||||
public static final int PUBLIC = 0x0001;
|
||||
|
||||
/** Declared private, usable only within the defining class. */
|
||||
public static final int PRIVATE = 0x0002;
|
||||
|
||||
/** Declared protected, may be accessed within subclasses. */
|
||||
public static final int PROTECTED = 0x0004;
|
||||
|
||||
/** Declared static. */
|
||||
public static final int STATIC = 0x0008;
|
||||
|
||||
/**
|
||||
* Declared final. For classes this means no subclassing allowed.
|
||||
* For fields it means no further assignment allowed after initialization.
|
||||
* For methods it means that the method cannot be overridden.
|
||||
*/
|
||||
public static final int FINAL = 0x0010;
|
||||
|
||||
/** Declared synchronized; invocation is wrapped in a monitor lock. */
|
||||
public static final int SYNCHRONIZED = 0x0020;
|
||||
|
||||
/**
|
||||
* Treat superclass methods specially when invoked by the
|
||||
* <i>invokespecial</i> instruction. This access only applies to
|
||||
* classes, and shares the same value as SYNCHRONIZED.
|
||||
*/
|
||||
public static final int SUPER = 0x0020;
|
||||
|
||||
/** Declared volatile; cannot be cached. */
|
||||
public static final int VOLATILE = 0x0040;
|
||||
|
||||
/** A bridge method, generated by the compiler. */
|
||||
public static final int BRIDGE = 0x0040;
|
||||
|
||||
/**
|
||||
* Declared transient; not written or read by a persistent object
|
||||
* manager
|
||||
*/
|
||||
public static final int TRANSIENT = 0x0080;
|
||||
|
||||
/** Declared with a variable number of arguments. */
|
||||
public static final int VARARGS = 0x0080;
|
||||
|
||||
/** Declared native; implemented in a language other than Java. */
|
||||
public static final int NATIVE = 0x0100;
|
||||
|
||||
/** Is an interface, not a class. */
|
||||
public static final int INTERFACE = 0x0200;
|
||||
|
||||
/** Declared abstract; must not be instantiated. */
|
||||
public static final int ABSTRACT = 0x0400;
|
||||
|
||||
/** Declared strictfp; floating point mode is FP-strict. */
|
||||
public static final int STRICT = 0x0800;
|
||||
|
||||
/** Declared synthetic, not present in the source file. */
|
||||
public static final int SYNTHETIC = 0x1000;
|
||||
|
||||
/** Declared as an annotation type. */
|
||||
public static final int ANNOTATION = 0x2000;
|
||||
|
||||
/**
|
||||
* For classes, declared as an enum type. For fields, declared as
|
||||
* an element of an enum.
|
||||
*/
|
||||
public static final int ENUM = 0x4000;
|
||||
|
||||
/**
|
||||
* Return a text representation for a given set of access flags.
|
||||
* Here are some examples:
|
||||
* <DL>
|
||||
* <DD><CODE>"public static final"</CODE>,</DD>
|
||||
* <DD><CODE>"package private"</CODE>, or</DD>
|
||||
* <DD><CODE>"protected transient"</CODE>.</DD>
|
||||
* </DL>
|
||||
* Note: only access flags that map to Java modifier keywords are returned.
|
||||
* @param access the mask of flags denoting access permission.
|
||||
* @return a text representation of the access flags.
|
||||
*/
|
||||
public static String toString( int access, boolean isClass ) {
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
if ( ( access & PUBLIC ) == PUBLIC ) {
|
||||
stringBuffer.append( "public " );
|
||||
}
|
||||
if ( ( access & PRIVATE ) == PRIVATE ) {
|
||||
stringBuffer.append( "private " );
|
||||
}
|
||||
if ( ( access & PROTECTED ) == PROTECTED ) {
|
||||
stringBuffer.append( "protected " );
|
||||
}
|
||||
if ( ( access & STATIC ) == STATIC ) {
|
||||
stringBuffer.append( "static " );
|
||||
}
|
||||
if ( ( access & FINAL ) == FINAL ) {
|
||||
stringBuffer.append( "final " );
|
||||
}
|
||||
if ( !isClass && ( access & SYNCHRONIZED ) == SYNCHRONIZED ) {
|
||||
stringBuffer.append( "synchronized " );
|
||||
}
|
||||
if ( ( access & VOLATILE ) == VOLATILE ) {
|
||||
stringBuffer.append( "volatile ");
|
||||
}
|
||||
if ( ( access & TRANSIENT ) == TRANSIENT ) {
|
||||
stringBuffer.append( "transient " );
|
||||
}
|
||||
if ( ( access & NATIVE) == NATIVE ) {
|
||||
stringBuffer.append( "native " );
|
||||
}
|
||||
if ( ( access & ABSTRACT ) == ABSTRACT && ( access & INTERFACE ) == 0) {//interfaces are always abstract, so drop the abstract keyword
|
||||
stringBuffer.append( "abstract " );
|
||||
}
|
||||
// trim trailing space
|
||||
return stringBuffer.toString();
|
||||
}
|
||||
|
||||
public static boolean isStatic( int access ) {
|
||||
return ( ( access & STATIC ) == STATIC );
|
||||
}
|
||||
|
||||
public static final boolean isPublic( int access ) {
|
||||
return ( ( access & PUBLIC ) == PUBLIC );
|
||||
}
|
||||
|
||||
public static final boolean isProtected( int access ) {
|
||||
return ( ( access & PROTECTED ) == PROTECTED );
|
||||
}
|
||||
|
||||
public static final boolean isPackagePrivate( int access ) {
|
||||
return ( ( access & ( PUBLIC | PRIVATE | PROTECTED ) ) == 0 );
|
||||
}
|
||||
|
||||
public static final boolean isPrivate( int access ) {
|
||||
return ( ( access & PRIVATE ) == PRIVATE );
|
||||
}
|
||||
|
||||
public static final boolean isInterface( int access ) {
|
||||
return ( ( access & INTERFACE ) == INTERFACE );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,22 +15,16 @@
|
||||
*/
|
||||
package ghidra.javaclass.format;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.javaclass.format.attributes.AbstractAttributeInfo;
|
||||
import ghidra.javaclass.format.attributes.AttributeFactory;
|
||||
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolDoubleInfo;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolFactory;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolLongInfo;
|
||||
import ghidra.program.model.data.ArrayDataType;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.javaclass.format.constantpool.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -85,9 +79,9 @@ public class ClassFileJava implements StructConverter {
|
||||
minorVersion = reader.readNextShort();
|
||||
majorVersion = reader.readNextShort();
|
||||
constantPoolCount = reader.readNextShort();
|
||||
constantPool = new AbstractConstantPoolInfoJava[constantPoolCount];
|
||||
constantPool = new AbstractConstantPoolInfoJava[getConstantPoolCount()];
|
||||
//NOTE: start at index 1 per JVM specification!!!
|
||||
for (int i = 1; i < constantPoolCount; i++) {
|
||||
for (int i = 1; i < getConstantPoolCount(); i++) {
|
||||
constantPool[i] = ConstantPoolFactory.get(reader);
|
||||
|
||||
//From section 4.4.5 of JVM specification:
|
||||
@@ -97,7 +91,7 @@ public class ClassFileJava implements StructConverter {
|
||||
///located at index n+2. The constant_pool index n+1 must be valid but is considered
|
||||
//unusable.
|
||||
if (constantPool[i] instanceof ConstantPoolLongInfo ||
|
||||
constantPool[i] instanceof ConstantPoolDoubleInfo) {
|
||||
constantPool[i] instanceof ConstantPoolDoubleInfo) {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
@@ -105,20 +99,20 @@ public class ClassFileJava implements StructConverter {
|
||||
thisClass = reader.readNextShort();
|
||||
superClass = reader.readNextShort();
|
||||
interfacesCount = reader.readNextShort();
|
||||
interfaces = reader.readNextShortArray(interfacesCount);
|
||||
interfaces = reader.readNextShortArray(getInterfacesCount());
|
||||
fieldsCount = reader.readNextShort();
|
||||
fields = new FieldInfoJava[fieldsCount];
|
||||
for (int i = 0; i < fieldsCount; i++) {
|
||||
fields = new FieldInfoJava[getFieldsCount()];
|
||||
for (int i = 0; i < getFieldsCount(); i++) {
|
||||
fields[i] = new FieldInfoJava(reader, this);
|
||||
}
|
||||
methodsCount = reader.readNextShort();
|
||||
methods = new MethodInfoJava[methodsCount];
|
||||
for (int i = 0; i < methodsCount; i++) {
|
||||
methods = new MethodInfoJava[getMethodsCount()];
|
||||
for (int i = 0; i < getMethodsCount(); i++) {
|
||||
methods[i] = new MethodInfoJava(reader, this);
|
||||
}
|
||||
attributesCount = reader.readNextShort();
|
||||
attributes = new AbstractAttributeInfo[attributesCount];
|
||||
for (int i = 0; i < attributesCount; i++) {
|
||||
attributes = new AbstractAttributeInfo[getAttributesCount()];
|
||||
for (int i = 0; i < getAttributesCount(); i++) {
|
||||
attributes[i] = AttributeFactory.get(reader, getConstantPool());
|
||||
}
|
||||
}
|
||||
@@ -173,8 +167,8 @@ public class ClassFileJava implements StructConverter {
|
||||
* exception for constants of type long and double noted in ?4.4.5.
|
||||
* @return the number of entries in the constant_pool table plus one
|
||||
*/
|
||||
public short getConstantPoolCount() {
|
||||
return constantPoolCount;
|
||||
public int getConstantPoolCount() {
|
||||
return constantPoolCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,8 +201,8 @@ public class ClassFileJava implements StructConverter {
|
||||
* defined by this class file.
|
||||
* @return a valid index into the constant_pool table to a CONSTANT_Class_info
|
||||
*/
|
||||
public short getThisClass() {
|
||||
return thisClass;
|
||||
public int getThisClass() {
|
||||
return thisClass & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,8 +222,8 @@ public class ClassFileJava implements StructConverter {
|
||||
* must be a CONSTANT_Class_info structure representing the class Object.
|
||||
* @return a valid index into the constant_pool table to a CONSTANT_Class_info
|
||||
*/
|
||||
public short getSuperClass() {
|
||||
return superClass;
|
||||
public int getSuperClass() {
|
||||
return superClass & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,8 +231,8 @@ public class ClassFileJava implements StructConverter {
|
||||
* superinterfaces of this class or interface type.
|
||||
* @return the number of direct superinterfaces of this class
|
||||
*/
|
||||
public short getInterfacesCount() {
|
||||
return interfacesCount;
|
||||
public int getInterfacesCount() {
|
||||
return interfacesCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,10 +242,11 @@ public class ClassFileJava implements StructConverter {
|
||||
* CONSTANT_Class_info (?4.4.1) structure representing an interface that is a
|
||||
* direct superinterface of this class or interface type, in the left-to-right order
|
||||
* given in the source for the type.
|
||||
* @return an array of interfaces
|
||||
* @param i entry
|
||||
* @return interface index
|
||||
*/
|
||||
public short[] getInterfaces() {
|
||||
return interfaces;
|
||||
public int getInterfacesEntry(int i) {
|
||||
return interfaces[i] & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,8 +256,8 @@ public class ClassFileJava implements StructConverter {
|
||||
* interface type.
|
||||
* @return the number of field_info structures in the fields table
|
||||
*/
|
||||
public short getFieldsCount() {
|
||||
return fieldsCount;
|
||||
public int getFieldsCount() {
|
||||
return fieldsCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -282,8 +277,8 @@ public class ClassFileJava implements StructConverter {
|
||||
* structures in the methods table.
|
||||
* @return the number of method_info structures in the methods table
|
||||
*/
|
||||
public short getMethodsCount() {
|
||||
return methodsCount;
|
||||
public int getMethodsCount() {
|
||||
return methodsCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,8 +304,8 @@ public class ClassFileJava implements StructConverter {
|
||||
* in the attributes table of this class.
|
||||
* @return the number of attributes in the attributes table
|
||||
*/
|
||||
public short getAttributesCount() {
|
||||
return attributesCount;
|
||||
public int getAttributesCount() {
|
||||
return attributesCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -370,14 +365,14 @@ public class ClassFileJava implements StructConverter {
|
||||
structure.add(WORD, "super_class", null);
|
||||
structure.add(WORD, "interfaces_count", null);
|
||||
|
||||
if (interfacesCount > 0) {
|
||||
DataType array = new ArrayDataType(WORD, interfacesCount, WORD.getLength());
|
||||
if (getInterfacesCount() > 0) {
|
||||
DataType array = new ArrayDataType(WORD, getInterfacesCount(), WORD.getLength());
|
||||
structure.add(array, "interfaces", null);
|
||||
}
|
||||
|
||||
structure.add(WORD, "field_count", null);
|
||||
|
||||
if (fieldsCount > 0) {
|
||||
if (getFieldsCount() > 0) {
|
||||
Structure fieldStruct = new StructureDataType("fields", 0);
|
||||
for (int i = 0; i < fields.length; ++i) {
|
||||
fieldStruct.add(fields[i].toDataType(), "field_" + i, null);
|
||||
@@ -387,7 +382,7 @@ public class ClassFileJava implements StructConverter {
|
||||
|
||||
structure.add(WORD, "method_count", null);
|
||||
|
||||
if (methodsCount > 0) {
|
||||
if (getMethodsCount() > 0) {
|
||||
Structure methodsStruct = new StructureDataType("methods", 0);
|
||||
for (int i = 0; i < methods.length; ++i) {
|
||||
methodsStruct.add(methods[i].toDataType(), "methods_" + i, null);
|
||||
@@ -396,7 +391,7 @@ public class ClassFileJava implements StructConverter {
|
||||
}
|
||||
|
||||
structure.add(WORD, "attributes_count", null);
|
||||
if (attributesCount > 0){
|
||||
if (getAttributesCount() > 0) {
|
||||
Structure attributesStruct = new StructureDataType("attributes", 0);
|
||||
for (int i = 0; i < attributes.length; ++i) {
|
||||
attributesStruct.add(attributes[i].toDataType(), "attributes_" + i, null);
|
||||
|
||||
+165
-100
File diff suppressed because it is too large
Load Diff
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package ghidra.javaclass.format;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.javaclass.format.attributes.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -48,18 +48,18 @@ public class FieldInfoJava implements StructConverter {
|
||||
private short nameIndex;
|
||||
private short descriptorIndex;
|
||||
private short attributesCount;
|
||||
private AbstractAttributeInfo [] attributes;
|
||||
private AbstractAttributeInfo[] attributes;
|
||||
|
||||
public FieldInfoJava( BinaryReader reader, ClassFileJava classFile ) throws IOException {
|
||||
public FieldInfoJava(BinaryReader reader, ClassFileJava classFile) throws IOException {
|
||||
_offset = reader.getPointerIndex();
|
||||
|
||||
accessFlags = reader.readNextShort();
|
||||
nameIndex = reader.readNextShort();
|
||||
descriptorIndex = reader.readNextShort();
|
||||
attributesCount = reader.readNextShort();
|
||||
attributes = new AbstractAttributeInfo[ attributesCount ];
|
||||
for ( int i = 0 ; i < attributesCount ; i++ ) {
|
||||
attributes[ i ] = AttributeFactory.get( reader, classFile.getConstantPool() );
|
||||
accessFlags = reader.readNextShort();
|
||||
nameIndex = reader.readNextShort();
|
||||
descriptorIndex = reader.readNextShort();
|
||||
attributesCount = reader.readNextShort();
|
||||
attributes = new AbstractAttributeInfo[getAttributesCount()];
|
||||
for (int i = 0; i < getAttributesCount(); i++) {
|
||||
attributes[i] = AttributeFactory.get(reader, classFile.getConstantPool());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,8 +84,8 @@ public class FieldInfoJava implements StructConverter {
|
||||
* unqualified name denoting a field.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getNameIndex() {
|
||||
return nameIndex;
|
||||
public int getNameIndex() {
|
||||
return nameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,8 +95,8 @@ public class FieldInfoJava implements StructConverter {
|
||||
* descriptor.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getDescriptorIndex() {
|
||||
return descriptorIndex;
|
||||
public int getDescriptorIndex() {
|
||||
return descriptorIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,8 +104,8 @@ public class FieldInfoJava implements StructConverter {
|
||||
* attributes of this field.
|
||||
* @return the number of additional attributes
|
||||
*/
|
||||
public short getAttributesCount() {
|
||||
return attributesCount;
|
||||
public int getAttributesCount() {
|
||||
return attributesCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,13 +137,13 @@ public class FieldInfoJava implements StructConverter {
|
||||
* information.
|
||||
* @return
|
||||
*/
|
||||
public AbstractAttributeInfo [] getAttributes() {
|
||||
public AbstractAttributeInfo[] getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public ConstantValueAttribute getConstantValueAttribute() {
|
||||
for ( AbstractAttributeInfo attributeInfo : attributes ) {
|
||||
if ( attributeInfo instanceof ConstantValueAttribute ) {
|
||||
for (AbstractAttributeInfo attributeInfo : attributes) {
|
||||
if (attributeInfo instanceof ConstantValueAttribute) {
|
||||
return (ConstantValueAttribute) attributeInfo;
|
||||
}
|
||||
}
|
||||
@@ -152,17 +152,17 @@ public class FieldInfoJava implements StructConverter {
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "field_info" + "|" + attributesCount + "|";
|
||||
String name = "field_info" + "|" + attributesCount + "|";
|
||||
|
||||
Structure structure = new StructureDataType( name, 0 );
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
|
||||
structure.add( WORD, "access_flags", null );
|
||||
structure.add( WORD, "name_index", null );
|
||||
structure.add( WORD, "descriptor_index", null );
|
||||
structure.add( WORD, "attributes_count", null );
|
||||
structure.add(WORD, "access_flags", null);
|
||||
structure.add(WORD, "name_index", null);
|
||||
structure.add(WORD, "descriptor_index", null);
|
||||
structure.add(WORD, "attributes_count", null);
|
||||
|
||||
for ( int i = 0 ; i < attributes.length ; ++i ) {
|
||||
structure.add( attributes[ i ].toDataType(), "attributes_" + i, null );
|
||||
for (int i = 0; i < attributes.length; ++i) {
|
||||
structure.add(attributes[i].toDataType(), "attributes_" + i, null);
|
||||
}
|
||||
|
||||
return structure;
|
||||
|
||||
@@ -15,42 +15,38 @@
|
||||
*/
|
||||
package ghidra.javaclass.format;
|
||||
|
||||
import ghidra.framework.options.Options;
|
||||
import java.util.Arrays;
|
||||
|
||||
import ghidra.app.util.opinion.JavaLoader;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class JavaClassUtil {
|
||||
|
||||
|
||||
public final static long LOOKUP_ADDRESS = 0xE0000000L;
|
||||
//65536 is the maximum size of the methods_count item in a class file
|
||||
public static final long METHOD_INDEX_SIZE = 65536 * 4;
|
||||
|
||||
public final static boolean isClassFile(Program program) {
|
||||
Options options = program.getOptions(Program.PROGRAM_INFO);
|
||||
String firmwarePath = options.getString("Firmware Path", "");
|
||||
|
||||
if (program.getExecutablePath().toLowerCase().endsWith(".class") ||
|
||||
firmwarePath.toLowerCase().endsWith(".class")) {
|
||||
byte[] bytes = new byte[4];
|
||||
try {
|
||||
Address address = program.getAddressFactory().getAddressSpace("constantPool").getMinAddress();
|
||||
program.getMemory().getBytes(address, bytes);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.info(JavaClassUtil.class, e.getLocalizedMessage());
|
||||
}
|
||||
return Arrays.equals(bytes, JavaClassConstants.MAGIC_BYTES);
|
||||
byte[] bytes = new byte[4];
|
||||
try {
|
||||
Address address = program.getAddressFactory().getAddressSpace(
|
||||
JavaLoader.CONSTANT_POOL).getMinAddress();
|
||||
program.getMemory().getBytes(address, bytes);
|
||||
}
|
||||
return false;
|
||||
catch (Exception e) {
|
||||
Msg.info(JavaClassUtil.class, e.getLocalizedMessage());
|
||||
return false;
|
||||
}
|
||||
return Arrays.equals(bytes, JavaClassConstants.MAGIC_BYTES);
|
||||
}
|
||||
|
||||
public static Address toLookupAddress( Program program, int methodIndex ) {
|
||||
AddressFactory addressFactory = program.getAddressFactory( );
|
||||
AddressSpace defaultAddressSpace = addressFactory.getDefaultAddressSpace( );
|
||||
return defaultAddressSpace.getAddress( JavaClassUtil.LOOKUP_ADDRESS + ( methodIndex * 4 ) );
|
||||
|
||||
public static Address toLookupAddress(Program program, int methodIndex) {
|
||||
AddressFactory addressFactory = program.getAddressFactory();
|
||||
AddressSpace defaultAddressSpace = addressFactory.getDefaultAddressSpace();
|
||||
return defaultAddressSpace.getAddress(JavaClassUtil.LOOKUP_ADDRESS + (methodIndex * 4));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,15 +15,16 @@
|
||||
*/
|
||||
package ghidra.javaclass.format;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.javaclass.flags.MethodsInfoAccessFlags;
|
||||
import ghidra.javaclass.format.attributes.*;
|
||||
import ghidra.javaclass.format.constantpool.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Each method, including each instance initialization method (2.9) and the class or
|
||||
* interface initialization method (2.9), is described by a method_info structure. No
|
||||
@@ -58,8 +59,8 @@ public class MethodInfoJava implements StructConverter {
|
||||
nameIndex = reader.readNextShort();
|
||||
descriptorIndex = reader.readNextShort();
|
||||
attributesCount = reader.readNextShort();
|
||||
attributes = new AbstractAttributeInfo[attributesCount];
|
||||
for (int i = 0; i < attributesCount; i++) {
|
||||
attributes = new AbstractAttributeInfo[getAttributesCount()];
|
||||
for (int i = 0; i < getAttributesCount(); i++) {
|
||||
attributes[i] = AttributeFactory.get(reader, classFile.getConstantPool());
|
||||
}
|
||||
}
|
||||
@@ -81,13 +82,14 @@ public class MethodInfoJava implements StructConverter {
|
||||
public short getAccessFlags() {
|
||||
return accessFlags;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return boolean encoding whether the method is static
|
||||
*/
|
||||
public boolean isStatic(){
|
||||
return AccessFlagsJava.isStatic(accessFlags);
|
||||
public boolean isStatic() {
|
||||
return (MethodsInfoAccessFlags.ACC_STATIC.getValue() &
|
||||
accessFlags) == MethodsInfoAccessFlags.ACC_STATIC.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,8 +100,8 @@ public class MethodInfoJava implements StructConverter {
|
||||
* denoting a method.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getNameIndex() {
|
||||
return nameIndex;
|
||||
public int getNameIndex() {
|
||||
return nameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,8 +110,8 @@ public class MethodInfoJava implements StructConverter {
|
||||
* CONSTANT_Utf8_info structure representing a valid method descriptor.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getDescriptorIndex() {
|
||||
return descriptorIndex;
|
||||
public int getDescriptorIndex() {
|
||||
return descriptorIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,8 +119,8 @@ public class MethodInfoJava implements StructConverter {
|
||||
* attributes of this method.
|
||||
* @return the number of additional attributes of this method
|
||||
*/
|
||||
public short getAttributesCount() {
|
||||
return attributesCount;
|
||||
public int getAttributesCount() {
|
||||
return attributesCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,11 +180,13 @@ public class MethodInfoJava implements StructConverter {
|
||||
ConstantPoolUtf8Info methodDescriptor =
|
||||
(ConstantPoolUtf8Info) constantPool[descriptorIndex];
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
stringBuffer.append(AccessFlagsJava.toString(accessFlags, false).trim());
|
||||
stringBuffer.append(MethodsInfoAccessFlags.toString(accessFlags));
|
||||
|
||||
if (!methodName.getString().equals("<clinit>")) {
|
||||
if (methodName.getString().equals("<clinit>")) {
|
||||
stringBuffer.append(" (class initializer)");
|
||||
}
|
||||
else {
|
||||
stringBuffer.append(' ');
|
||||
|
||||
if (methodName.getString().equals("<init>")) {//replace constructors with name of this class
|
||||
ConstantPoolClassInfo thisClass =
|
||||
(ConstantPoolClassInfo) constantPool[classFile.getThisClass()];
|
||||
@@ -205,13 +209,12 @@ public class MethodInfoJava implements StructConverter {
|
||||
stringBuffer.append(methodName.getString());
|
||||
}
|
||||
|
||||
stringBuffer.append('(');
|
||||
|
||||
CodeAttribute codeAttribute = getCodeAttribute();
|
||||
if (codeAttribute != null) {
|
||||
LocalVariableTableAttribute localVariableTable =
|
||||
codeAttribute.getLocalVariableTableAttribute();
|
||||
if (localVariableTable != null) {
|
||||
stringBuffer.append('(');
|
||||
LocalVariableJava[] localVariables = localVariableTable.getLocalVariables();
|
||||
int startIndex = getParametersStartIndex();
|
||||
for (int i = startIndex; i < localVariables.length; ++i) {
|
||||
@@ -224,22 +227,28 @@ public class MethodInfoJava implements StructConverter {
|
||||
ConstantPoolUtf8Info parameterDescriptor =
|
||||
(ConstantPoolUtf8Info) constantPool[localVariables[i].getDescriptorIndex()];
|
||||
|
||||
stringBuffer.append(DescriptorDecoder.decodeType(parameterDescriptor,
|
||||
false));
|
||||
stringBuffer.append(DescriptorDecoder.getTypeNameFromDescriptor(
|
||||
parameterDescriptor.getString(), false, true));
|
||||
stringBuffer.append(" ");
|
||||
stringBuffer.append(parameterName);
|
||||
|
||||
}
|
||||
}
|
||||
stringBuffer.append(')');
|
||||
}
|
||||
else {
|
||||
stringBuffer.append(
|
||||
DescriptorDecoder.getParameterString(methodDescriptor.getString()));
|
||||
}
|
||||
}
|
||||
|
||||
stringBuffer.append(')');
|
||||
ExceptionsAttribute exceptionsAttribute = getExceptionsAttribute();
|
||||
if (exceptionsAttribute != null) {
|
||||
int i = 0;
|
||||
for (short s : exceptionsAttribute.getExceptionIndexTable()) {
|
||||
ConstantPoolClassInfo exceptionClass = (ConstantPoolClassInfo) constantPool[s];
|
||||
for (int k = 0; k < exceptionsAttribute.getNumberOfExceptions(); k++) {
|
||||
ConstantPoolClassInfo exceptionClass =
|
||||
(ConstantPoolClassInfo) constantPool[exceptionsAttribute.getExceptionIndexTableEntry(
|
||||
k)];
|
||||
ConstantPoolUtf8Info exceptionClassName =
|
||||
(ConstantPoolUtf8Info) constantPool[exceptionClass.getNameIndex()];
|
||||
String className = exceptionClassName.getString();
|
||||
@@ -265,7 +274,7 @@ public class MethodInfoJava implements StructConverter {
|
||||
* otherwise skip index 0 because it contains the 'this' parameter.
|
||||
*/
|
||||
private int getParametersStartIndex() {
|
||||
return AccessFlagsJava.isStatic(accessFlags) ? 0 : 1;
|
||||
return isStatic() ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,7 +308,8 @@ public class MethodInfoJava implements StructConverter {
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "method_info" + "|" + nameIndex + "|" + descriptorIndex + "|" + attributesCount + "|";
|
||||
String name =
|
||||
"method_info" + "|" + nameIndex + "|" + descriptorIndex + "|" + attributesCount + "|";
|
||||
|
||||
Structure structure = new StructureDataType(name, 0);
|
||||
|
||||
|
||||
+10
-11
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,12 +15,12 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -94,11 +93,11 @@ public abstract class AbstractAttributeInfo implements StructConverter {
|
||||
private short attributeNameIndex;
|
||||
private int attributeLength;
|
||||
|
||||
protected AbstractAttributeInfo( BinaryReader reader ) throws IOException {
|
||||
protected AbstractAttributeInfo(BinaryReader reader) throws IOException {
|
||||
_offset = reader.getPointerIndex();
|
||||
|
||||
attributeNameIndex = reader.readNextShort();
|
||||
attributeLength = reader.readNextInt();
|
||||
attributeLength = reader.readNextInt();
|
||||
}
|
||||
|
||||
public long getOffset() {
|
||||
@@ -112,8 +111,8 @@ public abstract class AbstractAttributeInfo implements StructConverter {
|
||||
* @see AttributesConstants
|
||||
* @return the attribute_name_index
|
||||
*/
|
||||
public short getAttributeNameIndex() {
|
||||
return attributeNameIndex;
|
||||
public int getAttributeNameIndex() {
|
||||
return attributeNameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,10 +126,10 @@ public abstract class AbstractAttributeInfo implements StructConverter {
|
||||
return attributeLength;
|
||||
}
|
||||
|
||||
protected StructureDataType getBaseStructure( String name ) {
|
||||
StructureDataType structure = new StructureDataType( name + "|" + attributeLength + "|", 0 );
|
||||
structure.add( WORD, "attribute_name_index", null );
|
||||
structure.add( DWORD, "attribute_length" , null );
|
||||
protected StructureDataType getBaseStructure(String name) {
|
||||
StructureDataType structure = new StructureDataType(name + "|" + attributeLength + "|", 0);
|
||||
structure.add(WORD, "attribute_name_index", null);
|
||||
structure.add(DWORD, "attribute_length", null);
|
||||
return structure;
|
||||
}
|
||||
}
|
||||
|
||||
+41
-47
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.javaclass.format.DescriptorDecoder;
|
||||
@@ -22,8 +24,6 @@ import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -69,38 +69,35 @@ public class AnnotationElementValue implements StructConverter {
|
||||
private AnnotationJava annotation;
|
||||
|
||||
private short numberOfValues;
|
||||
private AnnotationElementValue [] values;
|
||||
private AnnotationElementValue[] values;
|
||||
|
||||
public AnnotationElementValue( BinaryReader reader ) throws IOException {
|
||||
public AnnotationElementValue(BinaryReader reader) throws IOException {
|
||||
tag = reader.readNextByte();
|
||||
|
||||
if ( tag == DescriptorDecoder.BASE_TYPE_BYTE ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_CHAR ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_INT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_SHORT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_LONG ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_FLOAT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_DOUBLE ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_BOOLEAN ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_STRING ) {
|
||||
if (tag == DescriptorDecoder.BASE_TYPE_BYTE || tag == DescriptorDecoder.BASE_TYPE_CHAR ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_INT || tag == DescriptorDecoder.BASE_TYPE_SHORT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_LONG || tag == DescriptorDecoder.BASE_TYPE_FLOAT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_DOUBLE ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_BOOLEAN ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_STRING) {
|
||||
|
||||
constantValueIndex = reader.readNextShort();
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_ENUM ) {
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_ENUM) {
|
||||
typeNameIndex = reader.readNextShort();
|
||||
constantNameIndex = reader.readNextShort();
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_CLASS ) {
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_CLASS) {
|
||||
classInfoIndex = reader.readNextShort();
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_ANNOTATION ) {
|
||||
annotation = new AnnotationJava( reader );
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_ANNOTATION) {
|
||||
annotation = new AnnotationJava(reader);
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_ARRAY ) {
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_ARRAY) {
|
||||
numberOfValues = reader.readNextShort();
|
||||
values = new AnnotationElementValue[ numberOfValues ];
|
||||
for ( int i = 0 ; i < numberOfValues ; ++i ) {
|
||||
values[ i ] = new AnnotationElementValue( reader );
|
||||
values = new AnnotationElementValue[numberOfValues & 0xffff];
|
||||
for (int i = 0; i < (numberOfValues & 0xffff); ++i) {
|
||||
values[i] = new AnnotationElementValue(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,8 +135,8 @@ public class AnnotationElementValue implements StructConverter {
|
||||
* for the field type designated by the tag item, as specified in Table 4.24.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getConstantValueIndex() {
|
||||
return constantValueIndex;
|
||||
public int getConstantValueIndex() {
|
||||
return constantValueIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,11 +148,11 @@ public class AnnotationElementValue implements StructConverter {
|
||||
* element_value structure.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getTypeNameIndex() {
|
||||
if ( tag != DescriptorDecoder.BASE_TYPE_ENUM ) {
|
||||
public int getTypeNameIndex() {
|
||||
if (tag != DescriptorDecoder.BASE_TYPE_ENUM) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return typeNameIndex;
|
||||
return typeNameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,11 +163,11 @@ public class AnnotationElementValue implements StructConverter {
|
||||
* structure.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getConstantNameIndex() {
|
||||
if ( tag != DescriptorDecoder.BASE_TYPE_ENUM ) {
|
||||
public int getConstantNameIndex() {
|
||||
if (tag != DescriptorDecoder.BASE_TYPE_ENUM) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return constantNameIndex;
|
||||
return constantNameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,8 +180,8 @@ public class AnnotationElementValue implements StructConverter {
|
||||
* For example, 'V' for Void.class, 'Ljava/lang/Object;' for Object, etc.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getClassInfoIndex() {
|
||||
return classInfoIndex;
|
||||
public int getClassInfoIndex() {
|
||||
return classInfoIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,32 +203,29 @@ public class AnnotationElementValue implements StructConverter {
|
||||
* array-typed value represented by this element_value structure.
|
||||
* @return nested element value table
|
||||
*/
|
||||
public AnnotationElementValue [] getValues() {
|
||||
public AnnotationElementValue[] getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "element_value" +"|" + tag + "|";
|
||||
StructureDataType structure = new StructureDataType( name, 0 );
|
||||
String name = "element_value" + "|" + tag + "|";
|
||||
StructureDataType structure = new StructureDataType(name, 0);
|
||||
|
||||
if ( tag == DescriptorDecoder.BASE_TYPE_BYTE ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_CHAR ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_INT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_SHORT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_LONG ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_FLOAT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_DOUBLE ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_BOOLEAN ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_STRING ) {
|
||||
if (tag == DescriptorDecoder.BASE_TYPE_BYTE || tag == DescriptorDecoder.BASE_TYPE_CHAR ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_INT || tag == DescriptorDecoder.BASE_TYPE_SHORT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_LONG || tag == DescriptorDecoder.BASE_TYPE_FLOAT ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_DOUBLE ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_BOOLEAN ||
|
||||
tag == DescriptorDecoder.BASE_TYPE_STRING) {
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_ENUM ) {
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_ENUM) {
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_CLASS ) {
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_CLASS) {
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_ANNOTATION ) {
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_ANNOTATION) {
|
||||
}
|
||||
else if ( tag == DescriptorDecoder.BASE_TYPE_ARRAY ) {
|
||||
else if (tag == DescriptorDecoder.BASE_TYPE_ARRAY) {
|
||||
}
|
||||
|
||||
return structure;
|
||||
|
||||
+9
-10
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,14 +15,14 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -43,9 +42,9 @@ public class AnnotationElementValuePair implements StructConverter {
|
||||
private short elementNameIndex;
|
||||
private AnnotationElementValue value;
|
||||
|
||||
public AnnotationElementValuePair( BinaryReader reader ) throws IOException {
|
||||
public AnnotationElementValuePair(BinaryReader reader) throws IOException {
|
||||
elementNameIndex = reader.readNextShort();
|
||||
value = new AnnotationElementValue( reader );
|
||||
value = new AnnotationElementValue(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,8 +55,8 @@ public class AnnotationElementValuePair implements StructConverter {
|
||||
* element represented by this element_value_pairs entry.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getElementNameIndex() {
|
||||
return elementNameIndex;
|
||||
public int getElementNameIndex() {
|
||||
return elementNameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,9 +70,9 @@ public class AnnotationElementValuePair implements StructConverter {
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = new StructureDataType( "element_value_pair", 0 );
|
||||
structure.add( WORD, "element_name_index", null );
|
||||
structure.add( value.toDataType(), "element_value_pair", null );
|
||||
StructureDataType structure = new StructureDataType("element_value_pair", 0);
|
||||
structure.add(WORD, "element_name_index", null);
|
||||
structure.add(value.toDataType(), "element_value_pair", null);
|
||||
return structure;
|
||||
}
|
||||
}
|
||||
|
||||
+18
-18
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -45,14 +45,14 @@ public class AnnotationJava implements StructConverter {
|
||||
|
||||
private short typeIndex;
|
||||
private short numberOfElementValuePairs;
|
||||
private AnnotationElementValuePair [] elementValuePairs;
|
||||
private AnnotationElementValuePair[] elementValuePairs;
|
||||
|
||||
public AnnotationJava( BinaryReader reader ) throws IOException {
|
||||
public AnnotationJava(BinaryReader reader) throws IOException {
|
||||
typeIndex = reader.readNextShort();
|
||||
numberOfElementValuePairs = reader.readNextShort();
|
||||
elementValuePairs = new AnnotationElementValuePair[ numberOfElementValuePairs ];
|
||||
for ( int i = 0 ; i < numberOfElementValuePairs ; ++i ) {
|
||||
elementValuePairs[ i ] = new AnnotationElementValuePair( reader );
|
||||
elementValuePairs = new AnnotationElementValuePair[getNumberOfElementValuePairs()];
|
||||
for (int i = 0; i < getNumberOfElementValuePairs(); ++i) {
|
||||
elementValuePairs[i] = new AnnotationElementValuePair(reader);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,8 +64,8 @@ public class AnnotationJava implements StructConverter {
|
||||
* represented by this annotation structure.
|
||||
* @return valid index into the constant_pool table
|
||||
*/
|
||||
public short getTypeIndex() {
|
||||
return typeIndex;
|
||||
public int getTypeIndex() {
|
||||
return typeIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,26 +77,26 @@ public class AnnotationJava implements StructConverter {
|
||||
* annotation.
|
||||
* @return the number of element-value pairs of the annotation
|
||||
*/
|
||||
public short getNumberOfElementValuePairs() {
|
||||
return numberOfElementValuePairs;
|
||||
public int getNumberOfElementValuePairs() {
|
||||
return numberOfElementValuePairs & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element value pair table for this annotation.
|
||||
* @return the element value pair table
|
||||
*/
|
||||
public AnnotationElementValuePair [] getElementValuePairs() {
|
||||
public AnnotationElementValuePair[] getElementValuePairs() {
|
||||
return elementValuePairs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "annotation" +"|" + numberOfElementValuePairs + "|";
|
||||
StructureDataType structure = new StructureDataType( name, 0 );
|
||||
structure.add( WORD, "type_index", null );
|
||||
structure.add( WORD, "num_element_value_pairs", null );
|
||||
for ( int i = 0 ; i < elementValuePairs.length ; ++i ) {
|
||||
structure.add( elementValuePairs[ i ].toDataType(), "element_value_pair_" + i, null );
|
||||
String name = "annotation" + "|" + numberOfElementValuePairs + "|";
|
||||
StructureDataType structure = new StructureDataType(name, 0);
|
||||
structure.add(WORD, "type_index", null);
|
||||
structure.add(WORD, "num_element_value_pairs", null);
|
||||
for (int i = 0; i < elementValuePairs.length; ++i) {
|
||||
structure.add(elementValuePairs[i].toDataType(), "element_value_pair_" + i, null);
|
||||
}
|
||||
return structure;
|
||||
}
|
||||
|
||||
+63
-71
@@ -15,90 +15,82 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
|
||||
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class AttributeFactory {
|
||||
|
||||
public static AbstractAttributeInfo get( BinaryReader reader, AbstractConstantPoolInfoJava [] constantPool ) throws IOException {
|
||||
|
||||
int attributeNameIndex = reader.readShort( reader.getPointerIndex() );
|
||||
public static AbstractAttributeInfo get(BinaryReader reader,
|
||||
AbstractConstantPoolInfoJava[] constantPool) throws IOException {
|
||||
|
||||
if ( attributeNameIndex < 1 || attributeNameIndex >= constantPool.length ) {
|
||||
throw new RuntimeException( "invalid index");
|
||||
int attributeNameIndex = reader.readShort(reader.getPointerIndex());
|
||||
|
||||
if (attributeNameIndex < 1 || attributeNameIndex >= constantPool.length) {
|
||||
throw new RuntimeException("invalid index");
|
||||
}
|
||||
|
||||
if ( !( constantPool[ attributeNameIndex ] instanceof ConstantPoolUtf8Info ) ) {
|
||||
if (!(constantPool[attributeNameIndex] instanceof ConstantPoolUtf8Info)) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
ConstantPoolUtf8Info utf8 = (ConstantPoolUtf8Info) constantPool[ attributeNameIndex ];
|
||||
ConstantPoolUtf8Info utf8 = (ConstantPoolUtf8Info) constantPool[attributeNameIndex];
|
||||
|
||||
if ( utf8.getString().equals( AttributesConstants.ConstantValue ) ) {
|
||||
return new ConstantValueAttribute( reader );
|
||||
switch (utf8.getString()) {
|
||||
case AttributesConstants.AnnotationDefault:
|
||||
return new AnnotationDefaultAttribute(reader);
|
||||
case AttributesConstants.BootstrapMethods:
|
||||
return new BootstrapMethodsAttribute(reader);
|
||||
case AttributesConstants.Code:
|
||||
return new CodeAttribute(reader, constantPool);
|
||||
case AttributesConstants.ConstantValue:
|
||||
return new ConstantValueAttribute(reader);
|
||||
case AttributesConstants.Deprecated:
|
||||
return new DeprecatedAttribute(reader);
|
||||
case AttributesConstants.EnclosingMethod:
|
||||
return new EnclosingMethodAttribute(reader);
|
||||
case AttributesConstants.Exceptions:
|
||||
return new ExceptionsAttribute(reader);
|
||||
case AttributesConstants.InnerClasses:
|
||||
return new InnerClassesAttribute(reader);
|
||||
case AttributesConstants.LineNumberTable:
|
||||
return new LineNumberTableAttribute(reader);
|
||||
case AttributesConstants.LocalVariableTable:
|
||||
return new LocalVariableTableAttribute(reader, constantPool);
|
||||
case AttributesConstants.LocalVariableTypeTable:
|
||||
return new LocalVariableTypeTableAttribute(reader);
|
||||
case AttributesConstants.ModuleMainClass:
|
||||
return new ModuleMainClassAttribute(reader);
|
||||
case AttributesConstants.ModulePackages:
|
||||
return new ModulePackagesAttribute(reader);
|
||||
case AttributesConstants.NestHost:
|
||||
return new NestHostAttribute(reader);
|
||||
case AttributesConstants.NestMembers:
|
||||
return new NestMembersAttribute(reader);
|
||||
case AttributesConstants.RuntimeInvisibleAnnotations:
|
||||
return new RuntimeInvisibleAnnotationsAttribute(reader);
|
||||
case AttributesConstants.RuntimeInvisibleParameterAnnotations:
|
||||
return new RuntimeParameterAnnotationsAttribute(reader, false /*invisible*/ );
|
||||
case AttributesConstants.RuntimeVisibleAnnotations:
|
||||
return new RuntimeVisibleAnnotationsAttribute(reader);
|
||||
case AttributesConstants.RuntimeVisibleParameterAnnotations:
|
||||
return new RuntimeParameterAnnotationsAttribute(reader, true /*visible*/ );
|
||||
case AttributesConstants.Signature:
|
||||
return new SignatureAttribute(reader);
|
||||
case AttributesConstants.SourceDebugExtension:
|
||||
return new SourceDebugExtensionAttribute(reader);
|
||||
case AttributesConstants.SourceFile:
|
||||
return new SourceFileAttribute(reader);
|
||||
case AttributesConstants.StackMapTable:
|
||||
return new StackMapTableAttribute(reader);
|
||||
case AttributesConstants.Synthetic:
|
||||
return new SyntheticAttribute(reader);
|
||||
case AttributesConstants.Module:
|
||||
return new ModuleAttribute(reader);
|
||||
default:
|
||||
throw new RuntimeException("Unknown attribute type: " + utf8.getString());
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.Code ) ) {
|
||||
return new CodeAttribute( reader, constantPool );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.StackMapTable ) ) {
|
||||
return new StackMapTableAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.Exceptions ) ) {
|
||||
return new ExceptionsAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.InnerClasses ) ) {
|
||||
return new InnerClassesAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.EnclosingMethod ) ) {
|
||||
return new EnclosingMethodAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.Synthetic ) ) {
|
||||
return new SyntheticAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.Signature ) ) {
|
||||
return new SignatureAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.SourceFile ) ) {
|
||||
return new SourceFileAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.SourceDebugExtension ) ) {
|
||||
return new SourceDebugExtensionAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.LineNumberTable ) ) {
|
||||
return new LineNumberTableAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.LocalVariableTable ) ) {
|
||||
return new LocalVariableTableAttribute( reader, constantPool );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.LocalVariableTypeTable ) ) {
|
||||
return new LocalVariableTypeTableAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.Deprecated ) ) {
|
||||
return new DeprecatedAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.RuntimeVisibleAnnotations ) ) {
|
||||
return new RuntimeVisibleAnnotationsAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.RuntimeInvisibleAnnotations ) ) {
|
||||
return new RuntimeInvisibleAnnotationsAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.RuntimeVisibleParameterAnnotations ) ) {
|
||||
return new RuntimeParameterAnnotationsAttribute( reader, true /*visible*/ );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.RuntimeInvisibleParameterAnnotations ) ) {
|
||||
return new RuntimeParameterAnnotationsAttribute( reader, false /*invisible*/ );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.AnnotationDefault ) ) {
|
||||
return new AnnotationDefaultAttribute( reader );
|
||||
}
|
||||
else if ( utf8.getString().equals( AttributesConstants.BootstrapMethods ) ) {
|
||||
return new BootstrapMethodsAttribute( reader );
|
||||
}
|
||||
|
||||
throw new RuntimeException( "Unknown attribute type: " + utf8.getString() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-3
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,9 +33,16 @@ public final class AttributesConstants {
|
||||
public final static String Deprecated = "Deprecated";
|
||||
public final static String RuntimeVisibleAnnotations = "RuntimeVisibleAnnotations";
|
||||
public final static String RuntimeInvisibleAnnotations = "RuntimeInvisibleAnnotations";
|
||||
public final static String RuntimeVisibleParameterAnnotations = "RuntimeVisibleParameterAnnotations";
|
||||
public final static String RuntimeInvisibleParameterAnnotations = "RuntimeInvisibleParameterAnnotations";
|
||||
public final static String RuntimeVisibleParameterAnnotations =
|
||||
"RuntimeVisibleParameterAnnotations";
|
||||
public final static String RuntimeInvisibleParameterAnnotations =
|
||||
"RuntimeInvisibleParameterAnnotations";
|
||||
public final static String AnnotationDefault = "AnnotationDefault";
|
||||
public final static String BootstrapMethods = "BootstrapMethods";
|
||||
public final static String Module = "Module";
|
||||
public final static String ModulePackages = "ModulePackages";
|
||||
public final static String ModuleMainClass = "ModuleMainClass";
|
||||
public final static String NestHost = "NestHost";
|
||||
public final static String NestMembers = "NestMembers";
|
||||
|
||||
}
|
||||
|
||||
+18
-20
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,9 +19,7 @@ import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.ArrayDataType;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
/**
|
||||
@@ -34,12 +31,12 @@ public class BootstrapMethods implements StructConverter {
|
||||
|
||||
private short bootstrapMethodsReference;
|
||||
private short numberOfBootstrapArguments;
|
||||
private short [] bootstrapArguments;
|
||||
private short[] bootstrapArguments;
|
||||
|
||||
public BootstrapMethods( BinaryReader reader ) throws IOException {
|
||||
public BootstrapMethods(BinaryReader reader) throws IOException {
|
||||
bootstrapMethodsReference = reader.readNextShort();
|
||||
numberOfBootstrapArguments = reader.readNextShort();
|
||||
bootstrapArguments = reader.readNextShortArray( numberOfBootstrapArguments & 0xffff );
|
||||
bootstrapArguments = reader.readNextShortArray(getNumberOfBootstrapArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,8 +52,8 @@ public class BootstrapMethods implements StructConverter {
|
||||
*
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getBootstrapMethodsReference() {
|
||||
return bootstrapMethodsReference;
|
||||
public int getBootstrapMethodsReference() {
|
||||
return bootstrapMethodsReference & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,8 +61,8 @@ public class BootstrapMethods implements StructConverter {
|
||||
* items in the bootstrap_arguments array.
|
||||
* @return the number of items in the bootstrap_arguments array
|
||||
*/
|
||||
public short getNumberOfBootstrapArguments() {
|
||||
return numberOfBootstrapArguments;
|
||||
public int getNumberOfBootstrapArguments() {
|
||||
return numberOfBootstrapArguments & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,20 +77,21 @@ public class BootstrapMethods implements StructConverter {
|
||||
* CONSTANT_Double_info,
|
||||
* CONSTANT_MethodHandle_info, or
|
||||
* CONSTANT_MethodType_info structure.
|
||||
* @return
|
||||
* @param i entry
|
||||
* @return index
|
||||
*/
|
||||
public short [] getBootstrapArguments() {
|
||||
return bootstrapArguments;
|
||||
public int getBootstrapArgumentsEntry(int i) {
|
||||
return bootstrapArguments[i] & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = new StructureDataType( "bootstrap_methods", 0 );
|
||||
structure.add( WORD, "bootstrap_method_ref", null );
|
||||
structure.add( WORD, "num_bootstrap_arguments", null );
|
||||
if ( numberOfBootstrapArguments > 0 ) {
|
||||
DataType array = new ArrayDataType( WORD, numberOfBootstrapArguments, WORD.getLength() );
|
||||
structure.add( array, "bootstrapArguments", null );
|
||||
StructureDataType structure = new StructureDataType("bootstrap_methods", 0);
|
||||
structure.add(WORD, "bootstrap_method_ref", null);
|
||||
structure.add(WORD, "num_bootstrap_arguments", null);
|
||||
if (numberOfBootstrapArguments > 0) {
|
||||
DataType array = new ArrayDataType(WORD, numberOfBootstrapArguments, WORD.getLength());
|
||||
structure.add(array, "bootstrapArguments", null);
|
||||
}
|
||||
return structure;
|
||||
}
|
||||
|
||||
+15
-15
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -55,33 +55,33 @@ import java.io.IOException;
|
||||
public class BootstrapMethodsAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short numberOfBootstrapMethods;
|
||||
private BootstrapMethods [] bootstrapMethods;
|
||||
private BootstrapMethods[] bootstrapMethods;
|
||||
|
||||
public BootstrapMethodsAttribute( BinaryReader reader ) throws IOException {
|
||||
public BootstrapMethodsAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
|
||||
numberOfBootstrapMethods = reader.readNextShort();
|
||||
|
||||
bootstrapMethods = new BootstrapMethods[ numberOfBootstrapMethods ];
|
||||
for ( int i = 0 ; i < numberOfBootstrapMethods ; ++i ) {
|
||||
bootstrapMethods[ i ] = new BootstrapMethods( reader );
|
||||
bootstrapMethods = new BootstrapMethods[getNumberOfBootstrapMethods()];
|
||||
for (int i = 0; i < getNumberOfBootstrapMethods(); ++i) {
|
||||
bootstrapMethods[i] = new BootstrapMethods(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public short getNumberOfBootstrapMethods() {
|
||||
return numberOfBootstrapMethods;
|
||||
public int getNumberOfBootstrapMethods() {
|
||||
return numberOfBootstrapMethods & 0xffff;
|
||||
}
|
||||
|
||||
public BootstrapMethods[] getBootstrapMethods(){
|
||||
|
||||
public BootstrapMethods[] getBootstrapMethods() {
|
||||
return bootstrapMethods;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = getBaseStructure( "BootstrapMethods_attribute" );
|
||||
structure.add( WORD, "num_bootstrap_methods", null );
|
||||
for ( int i = 0 ; i < bootstrapMethods.length ; ++i ) {
|
||||
structure.add( bootstrapMethods[ i ].toDataType(), "bootstrap_methods" + i, null );
|
||||
StructureDataType structure = getBaseStructure("BootstrapMethods_attribute");
|
||||
structure.add(WORD, "num_bootstrap_methods", null);
|
||||
for (int i = 0; i < bootstrapMethods.length; ++i) {
|
||||
structure.add(bootstrapMethods[i].toDataType(), "bootstrap_methods" + i, null);
|
||||
}
|
||||
return structure;
|
||||
}
|
||||
|
||||
+14
-14
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -80,13 +80,13 @@ public class CodeAttribute extends AbstractAttributeInfo {
|
||||
_codeOffset = reader.getPointerIndex();
|
||||
code = reader.readNextByteArray(codeLength);
|
||||
exceptionTableLength = reader.readNextShort();
|
||||
exceptionTable = new ExceptionHandlerJava[exceptionTableLength];
|
||||
for (int i = 0; i < exceptionTableLength; i++) {
|
||||
exceptionTable = new ExceptionHandlerJava[getExceptionTableLength()];
|
||||
for (int i = 0; i < getExceptionTableLength(); i++) {
|
||||
exceptionTable[i] = new ExceptionHandlerJava(reader);
|
||||
}
|
||||
attributesCount = reader.readNextShort();
|
||||
attributes = new AbstractAttributeInfo[attributesCount];
|
||||
for (int i = 0; i < attributesCount; i++) {
|
||||
attributes = new AbstractAttributeInfo[getAttributesCount()];
|
||||
for (int i = 0; i < getAttributesCount(); i++) {
|
||||
attributes[i] = AttributeFactory.get(reader, constantPool);
|
||||
}
|
||||
}
|
||||
@@ -96,8 +96,8 @@ public class CodeAttribute extends AbstractAttributeInfo {
|
||||
* operand stack of this method at any point during execution of the method.
|
||||
* @return the maximum depth of the operand stack
|
||||
*/
|
||||
public short getMaxStack() {
|
||||
return maxStack;
|
||||
public int getMaxStack() {
|
||||
return maxStack & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,8 +111,8 @@ public class CodeAttribute extends AbstractAttributeInfo {
|
||||
* @return the number of local variables in the
|
||||
* local variable array allocated upon invocation of this method
|
||||
*/
|
||||
public short getMaxLocals() {
|
||||
return maxLocals;
|
||||
public int getMaxLocals() {
|
||||
return maxLocals & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,8 +148,8 @@ public class CodeAttribute extends AbstractAttributeInfo {
|
||||
* in the exception_table table.
|
||||
* @return the number of entries in the exception_table table
|
||||
*/
|
||||
public short getExceptionTableLength() {
|
||||
return exceptionTableLength;
|
||||
public int getExceptionTableLength() {
|
||||
return exceptionTableLength & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,8 +168,8 @@ public class CodeAttribute extends AbstractAttributeInfo {
|
||||
* the Code attribute.
|
||||
* @return the number of attributes of the Code attribute
|
||||
*/
|
||||
public short getAttributesCount() {
|
||||
return attributesCount;
|
||||
public int getAttributesCount() {
|
||||
return attributesCount & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+9
-10
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -56,8 +55,8 @@ public class ConstantValueAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short constantValueIndex;
|
||||
|
||||
public ConstantValueAttribute( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public ConstantValueAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
constantValueIndex = reader.readNextShort();
|
||||
}
|
||||
|
||||
@@ -80,15 +79,15 @@ public class ConstantValueAttribute extends AbstractAttributeInfo {
|
||||
* </pre>
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getConstantValueIndex() {
|
||||
return constantValueIndex;
|
||||
public int getConstantValueIndex() {
|
||||
return constantValueIndex & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = getBaseStructure( "ConstantValue_attribute" );
|
||||
structure.add( WORD, "constantvalue_index", null );
|
||||
StructureDataType structure = getBaseStructure("ConstantValue_attribute");
|
||||
structure.add(WORD, "constantvalue_index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+11
-12
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -46,8 +45,8 @@ public class EnclosingMethodAttribute extends AbstractAttributeInfo {
|
||||
private short classIndex;
|
||||
private short methodIndex;
|
||||
|
||||
public EnclosingMethodAttribute( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public EnclosingMethodAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
|
||||
classIndex = reader.readNextShort();
|
||||
methodIndex = reader.readNextShort();
|
||||
@@ -60,8 +59,8 @@ public class EnclosingMethodAttribute extends AbstractAttributeInfo {
|
||||
* encloses the declaration of the current class.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getClassIndex() {
|
||||
return classIndex;
|
||||
public int getClassIndex() {
|
||||
return classIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,15 +73,15 @@ public class EnclosingMethodAttribute extends AbstractAttributeInfo {
|
||||
* type of a method in the class referenced by the class_index attribute above.
|
||||
* @return a valid index into the constant_pool table, or zero
|
||||
*/
|
||||
public short getMethodIndex() {
|
||||
return methodIndex;
|
||||
public int getMethodIndex() {
|
||||
return methodIndex & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = getBaseStructure( "EnclosingMethod_attribute" );
|
||||
structure.add( WORD, "class_index", null );
|
||||
structure.add( WORD, "method_index", null );
|
||||
StructureDataType structure = getBaseStructure("EnclosingMethod_attribute");
|
||||
structure.add(WORD, "class_index", null);
|
||||
structure.add(WORD, "method_index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
||||
+22
-19
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -32,10 +32,10 @@ public class ExceptionHandlerJava implements StructConverter {
|
||||
private short endPC;
|
||||
private short handlerPC;
|
||||
private short catchType;
|
||||
|
||||
public ExceptionHandlerJava( BinaryReader reader ) throws IOException {
|
||||
startPC = reader.readNextShort();
|
||||
endPC = reader.readNextShort();
|
||||
|
||||
public ExceptionHandlerJava(BinaryReader reader) throws IOException {
|
||||
startPC = reader.readNextShort();
|
||||
endPC = reader.readNextShort();
|
||||
handlerPC = reader.readNextShort();
|
||||
catchType = reader.readNextShort();
|
||||
}
|
||||
@@ -54,9 +54,10 @@ public class ExceptionHandlerJava implements StructConverter {
|
||||
* [start_pc, end_pc].
|
||||
* @return a valid index into the code array
|
||||
*/
|
||||
public short getStartPC() {
|
||||
return startPC;
|
||||
public int getStartPC() {
|
||||
return startPC & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* The values of the two items start_pc and end_pc indicate the ranges in the
|
||||
* code array at which the exception handler is active.
|
||||
@@ -72,18 +73,20 @@ public class ExceptionHandlerJava implements StructConverter {
|
||||
* [start_pc, end_pc].
|
||||
* @return a valid index into the code array
|
||||
*/
|
||||
public short getEndPC() {
|
||||
return endPC;
|
||||
public int getEndPC() {
|
||||
return endPC & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of the handler_pc item indicates the start of the exception
|
||||
* handler. The value of the item must be a valid index into the code array
|
||||
* and must be the index of the opcode of an instruction.
|
||||
* @return the start of the exception handler
|
||||
*/
|
||||
public short getHandlerPC() {
|
||||
return handlerPC;
|
||||
public int getHandlerPC() {
|
||||
return handlerPC & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the value of the catch_type item is nonzero, it must be a valid index
|
||||
* into the constant_pool table. The constant_pool entry at that index
|
||||
@@ -96,17 +99,17 @@ public class ExceptionHandlerJava implements StructConverter {
|
||||
* for all exceptions. This is used to implement finally (?3.13).
|
||||
* @return the value of the catch_type item
|
||||
*/
|
||||
public short getCatchType() {
|
||||
return catchType;
|
||||
public int getCatchType() {
|
||||
return catchType & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
Structure structure = new StructureDataType( "exception_handler", 0 );
|
||||
structure.add( WORD, "start_pc", null );
|
||||
structure.add( WORD, "end_pc", null );
|
||||
structure.add( WORD, "handler_pc", null );
|
||||
structure.add( WORD, "catch_type", null );
|
||||
Structure structure = new StructureDataType("exception_handler", 0);
|
||||
structure.add(WORD, "start_pc", null);
|
||||
structure.add(WORD, "end_pc", null);
|
||||
structure.add(WORD, "handler_pc", null);
|
||||
structure.add(WORD, "catch_type", null);
|
||||
return structure;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,12 +15,12 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -49,7 +48,7 @@ public class ExceptionsAttribute extends AbstractAttributeInfo {
|
||||
super(reader);
|
||||
|
||||
numberOfExceptions = reader.readNextShort();
|
||||
exceptionIndexTable = reader.readNextShortArray(numberOfExceptions);
|
||||
exceptionIndexTable = reader.readNextShortArray(getNumberOfExceptions());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,8 +56,8 @@ public class ExceptionsAttribute extends AbstractAttributeInfo {
|
||||
* in the exception_index_table.
|
||||
* @return the number of entries in the exception_index_table
|
||||
*/
|
||||
public short getNumberOfExceptions() {
|
||||
return numberOfExceptions;
|
||||
public int getNumberOfExceptions() {
|
||||
return numberOfExceptions & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,10 +65,11 @@ public class ExceptionsAttribute extends AbstractAttributeInfo {
|
||||
* the constant_pool table. The constant_pool entry referenced by each table
|
||||
* item must be a CONSTANT_Class_info structure representing a class
|
||||
* type that this method is declared to throw.
|
||||
* @return the exception_index_table array
|
||||
* @param i entry
|
||||
* @return index
|
||||
*/
|
||||
public short[] getExceptionIndexTable() {
|
||||
return exceptionIndexTable;
|
||||
public int getExceptionIndexTableEntry(int i) {
|
||||
return exceptionIndexTable[i] & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+14
-15
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,14 +15,14 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -44,7 +43,7 @@ public class InnerClass implements StructConverter {
|
||||
private short innerNameIndex;
|
||||
private short innerClassAccessFlags;
|
||||
|
||||
public InnerClass( BinaryReader reader ) throws IOException {
|
||||
public InnerClass(BinaryReader reader) throws IOException {
|
||||
innerClassInfoIndex = reader.readNextShort();
|
||||
outerClassInfoIndex = reader.readNextShort();
|
||||
innerNameIndex = reader.readNextShort();
|
||||
@@ -58,8 +57,8 @@ public class InnerClass implements StructConverter {
|
||||
* items in the classes array entry give information about C.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getInnerClassInfoIndex() {
|
||||
return innerClassInfoIndex;
|
||||
public int getInnerClassInfoIndex() {
|
||||
return innerClassInfoIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,8 +73,8 @@ public class InnerClass implements StructConverter {
|
||||
* interface of which C is a member.
|
||||
* @return a valid index into the constant_pool table, or zero
|
||||
*/
|
||||
public short getOuterClassInfoIndex() {
|
||||
return outerClassInfoIndex;
|
||||
public int getOuterClassInfoIndex() {
|
||||
return outerClassInfoIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,8 +87,8 @@ public class InnerClass implements StructConverter {
|
||||
* compiled.
|
||||
* @return a valid index into the constant_pool table, or zero
|
||||
*/
|
||||
public short getInnerNameIndex() {
|
||||
return innerNameIndex;
|
||||
public int getInnerNameIndex() {
|
||||
return innerNameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,11 +106,11 @@ public class InnerClass implements StructConverter {
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = new StructureDataType( "inner_class", 0 );
|
||||
structure.add( WORD, "inner_class_info_index", null );
|
||||
structure.add( WORD, "outer_class_info_index", null );
|
||||
structure.add( WORD, "inner_name_index", null );
|
||||
structure.add( WORD, "inner_class_access_flags", null );
|
||||
StructureDataType structure = new StructureDataType("inner_class", 0);
|
||||
structure.add(WORD, "inner_class_info_index", null);
|
||||
structure.add(WORD, "outer_class_info_index", null);
|
||||
structure.add(WORD, "inner_name_index", null);
|
||||
structure.add(WORD, "inner_class_access_flags", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
||||
+17
-17
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -50,15 +49,15 @@ import java.io.IOException;
|
||||
public class InnerClassesAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short numberOfInnerClasses;
|
||||
private InnerClass [] innerClasses;
|
||||
private InnerClass[] innerClasses;
|
||||
|
||||
public InnerClassesAttribute( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public InnerClassesAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
|
||||
numberOfInnerClasses = reader.readNextShort();
|
||||
innerClasses = new InnerClass[ numberOfInnerClasses ];
|
||||
for ( int i = 0 ; i < numberOfInnerClasses ; i++ ) {
|
||||
innerClasses[ i ] = new InnerClass( reader );
|
||||
innerClasses = new InnerClass[getNumberOfInnerClasses()];
|
||||
for (int i = 0; i < getNumberOfInnerClasses(); i++) {
|
||||
innerClasses[i] = new InnerClass(reader);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,25 +65,26 @@ public class InnerClassesAttribute extends AbstractAttributeInfo {
|
||||
* The value of the number_of_classes item indicates the number of entries in
|
||||
* the classes array.
|
||||
* @return the number of entries in the classes array
|
||||
*/
|
||||
public short getNumberOfInnerClasses() {
|
||||
return numberOfInnerClasses;
|
||||
*/
|
||||
public int getNumberOfInnerClasses() {
|
||||
return numberOfInnerClasses & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array of inner classes.
|
||||
* @return array of inner classes.
|
||||
*/
|
||||
public InnerClass [] getInnerClasses() {
|
||||
public InnerClass[] getInnerClasses() {
|
||||
return innerClasses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = getBaseStructure( "InnerClasses_attribute" + "|" + numberOfInnerClasses + "|" );
|
||||
structure.add( WORD, "number_of_classes", null );
|
||||
for ( int i = 0 ; i < innerClasses.length ; ++i ) {
|
||||
structure.add( innerClasses[ i ].toDataType(), "inner_class_" + i, null );
|
||||
StructureDataType structure =
|
||||
getBaseStructure("InnerClasses_attribute" + "|" + numberOfInnerClasses + "|");
|
||||
structure.add(WORD, "number_of_classes", null);
|
||||
for (int i = 0; i < innerClasses.length; ++i) {
|
||||
structure.add(innerClasses[i].toDataType(), "inner_class_" + i, null);
|
||||
}
|
||||
|
||||
return structure;
|
||||
|
||||
+10
-11
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,14 +15,14 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -40,7 +39,7 @@ public class LineNumber implements StructConverter {
|
||||
private short startPC;
|
||||
private short lineNumber;
|
||||
|
||||
public LineNumber( BinaryReader reader ) throws IOException {
|
||||
public LineNumber(BinaryReader reader) throws IOException {
|
||||
startPC = reader.readNextShort();
|
||||
lineNumber = reader.readNextShort();
|
||||
}
|
||||
@@ -53,23 +52,23 @@ public class LineNumber implements StructConverter {
|
||||
* item of the Code attribute of which this LineNumberTable is an attribute.
|
||||
* @return index into the code array at which the code for a new line in the original source file begins
|
||||
*/
|
||||
public short getStartPC() {
|
||||
return startPC;
|
||||
public int getStartPC() {
|
||||
return startPC & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of the line_number item must give the corresponding line number in the original source file.
|
||||
* @return the corresponding line number in the original source file
|
||||
*/
|
||||
public short getLineNumber() {
|
||||
return lineNumber;
|
||||
public int getLineNumber() {
|
||||
return lineNumber & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = new StructureDataType( "line_number", 0 );
|
||||
structure.add( WORD, "start_pc", null );
|
||||
structure.add( WORD, "line_number", null );
|
||||
StructureDataType structure = new StructureDataType("line_number", 0);
|
||||
structure.add(WORD, "start_pc", null);
|
||||
structure.add(WORD, "line_number", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
||||
+12
-13
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -52,25 +51,25 @@ import java.io.IOException;
|
||||
public class LineNumberTableAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short lineNumberTableLength;
|
||||
private LineNumber [] lineNumberTable;
|
||||
private LineNumber[] lineNumberTable;
|
||||
|
||||
public LineNumberTableAttribute( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public LineNumberTableAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
|
||||
lineNumberTableLength = reader.readNextShort();
|
||||
lineNumberTable = new LineNumber[ lineNumberTableLength ];
|
||||
for ( int i = 0 ; i < lineNumberTableLength ; i++ ) {
|
||||
lineNumberTable[ i ] = new LineNumber( reader );
|
||||
lineNumberTable = new LineNumber[lineNumberTableLength & 0xffff];
|
||||
for (int i = 0; i < (lineNumberTableLength & 0xffff); i++) {
|
||||
lineNumberTable[i] = new LineNumber(reader);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "LineNumberTable_attribute" + "|" + lineNumberTableLength + "|";
|
||||
StructureDataType structure = getBaseStructure( name );
|
||||
structure.add( WORD, "line_number_table_length", null );
|
||||
for ( int i = 0 ; i < lineNumberTable.length ; ++i ) {
|
||||
structure.add( lineNumberTable[ i ].toDataType(), "line_number_" + i, null );
|
||||
StructureDataType structure = getBaseStructure(name);
|
||||
structure.add(WORD, "line_number_table_length", null);
|
||||
for (int i = 0; i < lineNumberTable.length; ++i) {
|
||||
structure.add(lineNumberTable[i].toDataType(), "line_number_" + i, null);
|
||||
}
|
||||
return structure;
|
||||
}
|
||||
|
||||
+23
-23
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.app.util.bin.StructConverter;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -90,12 +90,12 @@ public class LocalVariableJava implements StructConverter {
|
||||
private short descriptorIndex;
|
||||
private short index;
|
||||
|
||||
public LocalVariableJava( BinaryReader reader ) throws IOException {
|
||||
startPC = reader.readNextShort();
|
||||
length = reader.readNextShort();
|
||||
nameIndex = reader.readNextShort();
|
||||
public LocalVariableJava(BinaryReader reader) throws IOException {
|
||||
startPC = reader.readNextShort();
|
||||
length = reader.readNextShort();
|
||||
nameIndex = reader.readNextShort();
|
||||
descriptorIndex = reader.readNextShort();
|
||||
index = reader.readNextShort();
|
||||
index = reader.readNextShort();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,16 +111,16 @@ public class LocalVariableJava implements StructConverter {
|
||||
* or it must be the first index beyond the end of that code array.
|
||||
* @return the start PC
|
||||
*/
|
||||
public short getStartPC() {
|
||||
return startPC;
|
||||
public int getStartPC() {
|
||||
return startPC & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of this local variable in bytes.
|
||||
* @return the length of this local variable in bytes
|
||||
*/
|
||||
public short getLength() {
|
||||
return length;
|
||||
public int getLength() {
|
||||
return length & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,8 +130,8 @@ public class LocalVariableJava implements StructConverter {
|
||||
* name denoting a local variable.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getNameIndex() {
|
||||
return nameIndex;
|
||||
public int getNameIndex() {
|
||||
return nameIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,8 +141,8 @@ public class LocalVariableJava implements StructConverter {
|
||||
* encoding the type of a local variable in the source program.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getDescriptorIndex() {
|
||||
return descriptorIndex;
|
||||
public int getDescriptorIndex() {
|
||||
return descriptorIndex & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,18 +153,18 @@ public class LocalVariableJava implements StructConverter {
|
||||
* index and index + 1.
|
||||
* @return index in the local variable array
|
||||
*/
|
||||
public short getIndex() {
|
||||
return index;
|
||||
public int getIndex() {
|
||||
return index & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
Structure structure = new StructureDataType( "local_variable", 0 );
|
||||
structure.add( WORD, "start_pc", null );
|
||||
structure.add( WORD, "length", null );
|
||||
structure.add( WORD, "name_index", null );
|
||||
structure.add( WORD, "descriptor_index", null );
|
||||
structure.add( WORD, "index", null );
|
||||
Structure structure = new StructureDataType("local_variable", 0);
|
||||
structure.add(WORD, "start_pc", null);
|
||||
structure.add(WORD, "length", null);
|
||||
structure.add(WORD, "name_index", null);
|
||||
structure.add(WORD, "descriptor_index", null);
|
||||
structure.add(WORD, "index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
||||
+14
-13
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -53,28 +53,29 @@ import java.io.IOException;
|
||||
public class LocalVariableTableAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short localVariableTableLength;
|
||||
private LocalVariableJava [] localVariableTable;
|
||||
private LocalVariableJava[] localVariableTable;
|
||||
|
||||
public LocalVariableTableAttribute( BinaryReader reader, AbstractConstantPoolInfoJava [] constantPool ) throws IOException {
|
||||
super( reader );
|
||||
public LocalVariableTableAttribute(BinaryReader reader,
|
||||
AbstractConstantPoolInfoJava[] constantPool) throws IOException {
|
||||
super(reader);
|
||||
|
||||
localVariableTableLength = reader.readNextShort();
|
||||
localVariableTable = new LocalVariableJava[ localVariableTableLength ];
|
||||
for ( int i = 0 ; i < localVariableTableLength ; i++ ) {
|
||||
localVariableTable[ i ] = new LocalVariableJava( reader );
|
||||
localVariableTable = new LocalVariableJava[localVariableTableLength & 0xffff];
|
||||
for (int i = 0; i < (localVariableTableLength & 0xffff); i++) {
|
||||
localVariableTable[i] = new LocalVariableJava(reader);
|
||||
}
|
||||
}
|
||||
|
||||
public LocalVariableJava [] getLocalVariables() {
|
||||
public LocalVariableJava[] getLocalVariables() {
|
||||
return localVariableTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = getBaseStructure( "LocalVariableTable_attribute" );
|
||||
structure.add( WORD, "local_variable_table_length", null );
|
||||
for ( int i = 0 ; i < localVariableTable.length ; ++i ) {
|
||||
structure.add( localVariableTable[ i ].toDataType(), "local_variable_" + i, null );
|
||||
StructureDataType structure = getBaseStructure("LocalVariableTable_attribute");
|
||||
structure.add(WORD, "local_variable_table_length", null);
|
||||
for (int i = 0; i < localVariableTable.length; ++i) {
|
||||
structure.add(localVariableTable[i].toDataType(), "local_variable_" + i, null);
|
||||
}
|
||||
return structure;
|
||||
}
|
||||
|
||||
+478
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+57
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+77
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+58
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+77
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+16
-16
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -52,17 +52,17 @@ import java.io.IOException;
|
||||
public class RuntimeInvisibleAnnotationsAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short numberOfAnnotations;
|
||||
private AnnotationJava [] annotations;
|
||||
private AnnotationJava[] annotations;
|
||||
|
||||
public RuntimeInvisibleAnnotationsAttribute( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public RuntimeInvisibleAnnotationsAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
|
||||
numberOfAnnotations = reader.readNextShort();
|
||||
|
||||
annotations = new AnnotationJava[ numberOfAnnotations ];
|
||||
annotations = new AnnotationJava[getNumberOfAnnotations()];
|
||||
|
||||
for ( int i = 0 ; i < numberOfAnnotations ; ++i ) {
|
||||
annotations[ i ] = new AnnotationJava( reader );
|
||||
for (int i = 0; i < getNumberOfAnnotations(); ++i) {
|
||||
annotations[i] = new AnnotationJava(reader);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,8 +74,8 @@ public class RuntimeInvisibleAnnotationsAttribute extends AbstractAttributeInfo
|
||||
* may be directly attached to a program element.
|
||||
* @return the number of runtime-visible annotations
|
||||
*/
|
||||
public short getNumberOfAnnotations() {
|
||||
return numberOfAnnotations;
|
||||
public int getNumberOfAnnotations() {
|
||||
return numberOfAnnotations & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,17 +83,17 @@ public class RuntimeInvisibleAnnotationsAttribute extends AbstractAttributeInfo
|
||||
* annotation on a program element.
|
||||
* @return the annotations table
|
||||
*/
|
||||
public AnnotationJava [] getAnnotations() {
|
||||
public AnnotationJava[] getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = "RuntimeInvisibleAnnotations_attribute" +"|" + numberOfAnnotations + "|";
|
||||
StructureDataType structure = getBaseStructure( name );
|
||||
structure.add( WORD, "num_annotations", null );
|
||||
for ( int i = 0 ; i < annotations.length ; ++i ) {
|
||||
structure.add( annotations[ i ].toDataType(), "annotation_" + i, null );
|
||||
String name = "RuntimeInvisibleAnnotations_attribute" + "|" + numberOfAnnotations + "|";
|
||||
StructureDataType structure = getBaseStructure(name);
|
||||
structure.add(WORD, "num_annotations", null);
|
||||
for (int i = 0; i < annotations.length; ++i) {
|
||||
structure.add(annotations[i].toDataType(), "annotation_" + i, null);
|
||||
}
|
||||
return structure;
|
||||
}
|
||||
|
||||
+28
-26
@@ -15,15 +15,15 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -65,22 +65,24 @@ public class RuntimeParameterAnnotationsAttribute extends AbstractAttributeInfo
|
||||
private boolean _isVisible;
|
||||
|
||||
private byte numberOfParameters;
|
||||
private Map<Integer, AnnotationJava []> parameterAnnotations = new HashMap<Integer, AnnotationJava []>();
|
||||
private Map<Integer, AnnotationJava[]> parameterAnnotations =
|
||||
new HashMap<Integer, AnnotationJava[]>();
|
||||
|
||||
public RuntimeParameterAnnotationsAttribute( BinaryReader reader, boolean isVisible ) throws IOException {
|
||||
super( reader );
|
||||
public RuntimeParameterAnnotationsAttribute(BinaryReader reader, boolean isVisible)
|
||||
throws IOException {
|
||||
super(reader);
|
||||
|
||||
_isVisible = isVisible;
|
||||
|
||||
numberOfParameters = reader.readNextByte();
|
||||
|
||||
for ( int i = 0 ; i < numberOfParameters ; ++i ) {
|
||||
for (int i = 0; i < getNumberOfParameters(); ++i) {
|
||||
short numberOfAnnotations = reader.readNextShort();
|
||||
AnnotationJava [] annotations = new AnnotationJava[ numberOfAnnotations ];
|
||||
for ( int a = 0 ; a < numberOfAnnotations ; ++a ) {
|
||||
annotations[ a ] = new AnnotationJava( reader );
|
||||
AnnotationJava[] annotations = new AnnotationJava[(numberOfAnnotations & 0xffff)];
|
||||
for (int a = 0; a < (numberOfAnnotations & 0xffff); ++a) {
|
||||
annotations[a] = new AnnotationJava(reader);
|
||||
}
|
||||
parameterAnnotations.put( i, annotations );
|
||||
parameterAnnotations.put(i, annotations);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,8 +102,8 @@ public class RuntimeParameterAnnotationsAttribute extends AbstractAttributeInfo
|
||||
* (This duplicates information that could be extracted from the method descriptor.)
|
||||
* @return the number of parameters for this method
|
||||
*/
|
||||
public byte getNumberOfParameters() {
|
||||
return numberOfParameters;
|
||||
public int getNumberOfParameters() {
|
||||
return numberOfParameters & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,23 +122,23 @@ public class RuntimeParameterAnnotationsAttribute extends AbstractAttributeInfo
|
||||
* @param parameter the parameter index
|
||||
* @return the annotations for the given parameter
|
||||
*/
|
||||
public AnnotationJava [] getParameterAnnotations( int parameter ) {
|
||||
return parameterAnnotations.get( parameter );
|
||||
public AnnotationJava[] getParameterAnnotations(int parameter) {
|
||||
return parameterAnnotations.get(parameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
String name = _isVisible ?
|
||||
"RuntimeVisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|" :
|
||||
"RuntimeInvisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|";
|
||||
String name = _isVisible
|
||||
? "RuntimeVisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|"
|
||||
: "RuntimeInvisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|";
|
||||
|
||||
StructureDataType structure = getBaseStructure( name );
|
||||
structure.add( BYTE, "num_parameters", null );
|
||||
for ( int i = 0 ; i < numberOfParameters ; ++i ) {
|
||||
structure.add( WORD, "num_annotations_" + i, null );
|
||||
AnnotationJava [] annotations = parameterAnnotations.get( i );
|
||||
for ( int a = 0 ; a < annotations.length ; ++a ) {
|
||||
structure.add( annotations[ a ].toDataType(), "annotations_" + i + "_" + a, null );
|
||||
StructureDataType structure = getBaseStructure(name);
|
||||
structure.add(BYTE, "num_parameters", null);
|
||||
for (int i = 0; i < numberOfParameters; ++i) {
|
||||
structure.add(WORD, "num_annotations_" + i, null);
|
||||
AnnotationJava[] annotations = parameterAnnotations.get(i);
|
||||
for (int a = 0; a < annotations.length; ++a) {
|
||||
structure.add(annotations[a].toDataType(), "annotations_" + i + "_" + a, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-9
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -45,8 +44,8 @@ public class SignatureAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short signatureIndex;
|
||||
|
||||
public SignatureAttribute( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public SignatureAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
|
||||
signatureIndex = reader.readNextShort();
|
||||
}
|
||||
@@ -60,14 +59,14 @@ public class SignatureAttribute extends AbstractAttributeInfo {
|
||||
* type signature otherwise.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getSignatureIndex() {
|
||||
return signatureIndex;
|
||||
public int getSignatureIndex() {
|
||||
return signatureIndex & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = getBaseStructure( "Signature_attribute" );
|
||||
structure.add( WORD, "signature_index", null );
|
||||
StructureDataType structure = getBaseStructure("Signature_attribute");
|
||||
structure.add(WORD, "signature_index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
||||
+8
-9
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,13 +15,13 @@
|
||||
*/
|
||||
package ghidra.javaclass.format.attributes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.app.util.bin.BinaryReader;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.StructureDataType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
|
||||
* <p>
|
||||
@@ -43,8 +42,8 @@ public class SourceFileAttribute extends AbstractAttributeInfo {
|
||||
|
||||
private short sourceFileIndex;
|
||||
|
||||
public SourceFileAttribute( BinaryReader reader ) throws IOException {
|
||||
super( reader );
|
||||
public SourceFileAttribute(BinaryReader reader) throws IOException {
|
||||
super(reader);
|
||||
|
||||
sourceFileIndex = reader.readNextShort();
|
||||
}
|
||||
@@ -62,14 +61,14 @@ public class SourceFileAttribute extends AbstractAttributeInfo {
|
||||
* at the time the file name is actually used.
|
||||
* @return a valid index into the constant_pool table
|
||||
*/
|
||||
public short getSourceFileIndex() {
|
||||
return sourceFileIndex;
|
||||
public int getSourceFileIndex() {
|
||||
return sourceFileIndex & 0xffff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||
StructureDataType structure = getBaseStructure( "SourceFile_attribute" );
|
||||
structure.add( WORD, "sourcefile_index", null );
|
||||
StructureDataType structure = getBaseStructure("SourceFile_attribute");
|
||||
structure.add(WORD, "sourcefile_index", null);
|
||||
return structure;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user