GT_2757 fixed java stream decompile bug

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

View file

@ -48,26 +48,36 @@ public abstract class ConstantPool {
StringBuilder buf = new StringBuilder();
buf.append("<cpoolrec");
SpecXmlUtils.encodeUnsignedIntegerAttribute(buf, "ref", ref);
if (tag == STRING_LITERAL)
if (tag == STRING_LITERAL) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "string");
else if (tag == CLASS_REFERENCE)
}
else if (tag == CLASS_REFERENCE) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "classref");
else if (tag == POINTER_METHOD)
}
else if (tag == POINTER_METHOD) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "method");
else if (tag == POINTER_FIELD)
}
else if (tag == POINTER_FIELD) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "field");
else if (tag == ARRAY_LENGTH)
}
else if (tag == ARRAY_LENGTH) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "arraylength");
else if (tag == INSTANCE_OF)
}
else if (tag == INSTANCE_OF) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "instanceof");
else if (tag == CHECK_CAST)
}
else if (tag == CHECK_CAST) {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "checkcast");
else
}
else {
SpecXmlUtils.encodeStringAttribute(buf, "tag", "primitive");
if (hasThisPtr)
}
if (hasThisPtr) {
SpecXmlUtils.encodeBooleanAttribute(buf, "hasthis", true);
if (isConstructor)
}
if (isConstructor) {
SpecXmlUtils.encodeBooleanAttribute(buf, "constructor", true);
}
buf.append(">\n");
if (tag == PRIMITIVE) {
buf.append("<value>");

View file

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

View file

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

View file

@ -31,6 +31,7 @@ import ghidra.javaclass.format.attributes.CodeAttribute;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
import ghidra.program.model.address.*;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.lang.LanguageCompilerSpecPair;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Program;
@ -43,6 +44,8 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
private static final String JAVA_NAME = "Java Class File";
private Register alignmentReg;
public static final long CODE_OFFSET = 0x10000L;
public static final String CONSTANT_POOL = "constantPool";
@Override
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
@ -61,23 +64,25 @@ 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;
}
@Override
public String getName() {
@ -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");
@ -135,14 +140,13 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
}
private void createMethodLookupMemoryBlock(Program program, TaskMonitor monitor) {
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) {
@ -164,8 +168,7 @@ 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) {
@ -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];
String methodName = methodNameInfo.getString() + methodDescriptorInfo.getString();
MemoryBlock memoryBlock =
memory.createInitializedBlock(methodName, start,
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,8 +217,7 @@ public class JavaLoader extends AbstractLibrarySupportLoader {
int alignmentValue = 3;
while (addressIterator.hasNext()) {
Address address = addressIterator.next();
SetRegisterCmd cmd =
new SetRegisterCmd(alignmentReg, address, address,
SetRegisterCmd cmd = new SetRegisterCmd(alignmentReg, address, address,
BigInteger.valueOf(alignmentValue));
cmd.applyTo(program);
if (alignmentValue == 0) {

View file

@ -58,26 +58,49 @@ 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;
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);
ParameterDefinitionImpl currentParam =
new ParameterDefinitionImpl("", params.get(i), null);
paramDefs[i] = currentParam;
}
res.hasThisPtr = false;
@ -85,16 +108,18 @@ public class ConstantPoolJava extends ConstantPool {
//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);
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.
@ -120,27 +145,22 @@ public class ConstantPoolJava extends ConstantPool {
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;
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("/");
String fullyQualifiedName =
((ConstantPoolUtf8Info) constantPool[name_index]).getString();
String[] parts = fullyQualifiedName.split("/");
res.token = parts[parts.length - 1];
sb = new StringBuilder();
StringBuilder sb = new StringBuilder();
for (String part : parts) {
sb.append(CategoryPath.DELIMITER_CHAR);
sb.append(part);
@ -148,11 +168,12 @@ 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);
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;
@ -161,76 +182,43 @@ 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
@ -251,17 +239,19 @@ public class ConstantPoolJava extends ConstantPool {
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) {
res.tag = ConstantPool.CLASS_REFERENCE;
name_index = ((ConstantPoolClassInfo) poolRef).getNameIndex();
fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[name_index]).getString();
className = getClassName(fullyQualifiedName);
fullyQualifiedName =
((ConstantPoolUtf8Info) constantPool[name_index]).getString();
String className = getClassName(fullyQualifiedName);
res.token = className + ".class";
res.type = DescriptorDecoder.getReferenceTypeOfDescriptor(fullyQualifiedName, dtManager, false);
res.type = DescriptorDecoder.getReferenceTypeOfDescriptor(fullyQualifiedName,
dtManager, false);
}
//standard java compilers don't seem to emit the following two
else if (poolRef instanceof ConstantPoolMethodTypeInfo) {
res.tag = ConstantPool.POINTER_METHOD;
name_index = ((ConstantPoolMethodTypeInfo) poolRef).getDescriptorIndex();
@ -291,18 +281,54 @@ public class ConstantPoolJava extends ConstantPool {
}
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();

View file

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

View file

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

View file

@ -50,13 +50,16 @@ 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);
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) {
@ -66,7 +69,8 @@ public class InvokeMethods {
emitPcodeToResolveMethodReference(pCode, offset, constantPool, type);
PcodeTextEmitter.emitIndirectCall(pCode, CALL_TARGET);
JavaComputationalCategory retType = DescriptorDecoder.getReturnCategoryOfMethodDescriptor(descriptor);
JavaComputationalCategory retType =
DescriptorDecoder.getReturnCategoryOfMethodDescriptor(descriptor);
switch (retType) {
case CAT_1:
PcodeTextEmitter.emitPushCat1Value(pCode, CAT_1_RETURN);
@ -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,7 +129,8 @@ 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) {
@ -97,13 +138,17 @@ public class InvokeMethods {
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:
@ -114,12 +159,12 @@ public class InvokeMethods {
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){
static void emitPcodeToResolveMethodReference(StringBuilder pCode, int offset,
AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) {
switch (type) {
case INVOKE_DYNAMIC:
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset),
ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
break;
case INVOKE_INTERFACE:
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKEINTERFACE);
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset),
ConstantPoolJava.CPOOL_INVOKEINTERFACE);
break;
case INVOKE_SPECIAL:
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKESPECIAL);
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset),
ConstantPoolJava.CPOOL_INVOKESPECIAL);
break;
case INVOKE_STATIC:
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKESTATIC);
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset),
ConstantPoolJava.CPOOL_INVOKESTATIC);
break;
case INVOKE_VIRTUAL:
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset),
ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
break;
default:
throw new IllegalArgumentException("Unimplemented JavaMethodType: " + type.toString());
throw new IllegalArgumentException(
"Unimplemented JavaMethodType: " + type.toString());
}
}
}

View file

@ -79,17 +79,6 @@ 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:
*
* 2) incorporate exceptions.
@ -121,7 +110,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
public static final String LDC = "ldcCallOther";
public static final String LDC2_W = "ldc2_wCallOther";
public static final String LDC_W = "ldc_wCallOther";
public static final String LOOKUP_SWITCH = "lookupswitchCallOther";
public static final String MULTIANEWARRAY = "multianewarrayCallOther";
public static final String PUTFIELD = "putFieldCallOther";
@ -149,7 +137,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
implementedOps.add(LDC);
implementedOps.add(LDC2_W);
implementedOps.add(LDC_W);
implementedOps.add(LOOKUP_SWITCH);
implementedOps.add(MULTIANEWARRAY);
implementedOps.add(PUTFIELD);
implementedOps.add(PUTSTATIC);
@ -170,8 +157,9 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
@Override
protected InjectPayloadSleigh allocateInject(String sourceName, String name, int tp) {
InjectPayloadJava payload = null;
if (tp != InjectPayload.CALLOTHERFIXUP_TYPE)
if (tp != InjectPayload.CALLOTHERFIXUP_TYPE) {
return super.allocateInject(sourceName, name, tp);
}
switch (name) {
case GETFIELD:
payload = new InjectGetField(sourceName, language);
@ -199,9 +187,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary {
case LDC_W:
payload = new InjectLdc(sourceName, language);
break;
case LOOKUP_SWITCH:
payload = new InjectLookupSwitch(sourceName, language);
break;
case MULTIANEWARRAY:
payload = new InjectMultiANewArray(sourceName, language);
break;

View file

@ -15,7 +15,6 @@
*/
package ghidra.app.util.pcodeInject;
/**
*
* This is a utility class containing methods to emit pcode for decompile callbacks occurring during analysis of
@ -83,7 +82,8 @@ 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(Integer.toString(size));
@ -99,7 +99,6 @@ public class PcodeTextEmitter {
pCode.append(");\n");
}
/**
* Emits pcode to call a void black-box pcodeop
* @param pCode StringBuilder to hold the pcode
@ -118,21 +117,20 @@ public class PcodeTextEmitter {
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,7 +138,8 @@ 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);
@ -165,7 +164,16 @@ public class PcodeTextEmitter {
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,18 +185,24 @@ public class PcodeTextEmitter {
pCode.append(";\n");
}
/**
* Appends the pcode to emit an indirect call
* @param pCode buffer to append to
* @param target varnode to call indirectly
*/
public static void emitIndirectCall(StringBuilder pCode, String target) {
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");
}
/**
* 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(":");
@ -198,6 +212,13 @@ public class PcodeTextEmitter {
pCode.append(");\n");
}
/**
* Appends the pcode to zero-extend the value src into dest
* @param pCode buffer to append to
* @param dest target varnode
* @param size size of target varnode
* @param src size of source varnode
*/
public static void emitZeroExtension(StringBuilder pCode, String dest, int size, String src) {
pCode.append(dest);
pCode.append(":");
@ -207,6 +228,13 @@ public class PcodeTextEmitter {
pCode.append(");\n");
}
/**
* Appends the pcode truncate src into dest
* @param pCode buffer to append to
* @param dest target varnode
* @param size size of target varnode
* @param src size of source varnode
*/
public static void emitTruncate(StringBuilder pCode, String dest, int size, String src) {
pCode.append(dest);
pCode.append(" = ");
@ -216,5 +244,24 @@ public class PcodeTextEmitter {
pCode.append(";\n");
}
/**
* Appends the pcode to assign a varnode from a dereference of another varnode
* @param pCode buffer to append to
* @param lhs target varnode
* @param size size of pointed-to value
* @param rhs varnode to dereference
*/
public static void emitAssignVarnodeFromDereference(StringBuilder pCode, String lhs, int size,
String rhs) {
pCode.append(lhs);
pCode.append(":");
pCode.append(Integer.toString(size));
pCode.append(" = ");
pCode.append("*:");
pCode.append(Integer.toString(size));
pCode.append(" ");
pCode.append(rhs);
pCode.append(";\n");
}
}

View file

@ -16,10 +16,7 @@
package ghidra.app.util.pcodeInject;
import ghidra.javaclass.format.DescriptorDecoder;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
import ghidra.javaclass.format.constantpool.ConstantPoolFieldReferenceInfo;
import ghidra.javaclass.format.constantpool.ConstantPoolNameAndTypeInfo;
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
import ghidra.javaclass.format.constantpool.*;
/**
*
@ -37,7 +34,8 @@ 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";
@ -54,42 +52,61 @@ 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)) {
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.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.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.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.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.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.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:
@ -104,48 +121,67 @@ 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)) {
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);
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);
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);
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,7 +195,8 @@ 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);
@ -167,26 +204,38 @@ public class ReferenceMethods {
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.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.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.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.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
@ -194,13 +243,19 @@ public class ReferenceMethods {
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.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.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:
@ -215,41 +270,53 @@ 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)) {
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);
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);
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
@ -257,22 +324,27 @@ public class ReferenceMethods {
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);
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,7 +367,6 @@ public class ReferenceMethods {
return pCode.toString();*/
}
/**
* Returns the descriptor of a field reference in the constant pool
* @param constantPool
@ -303,13 +374,14 @@ public class ReferenceMethods {
* @return
*/
static String getDescriptorForFieldRef(AbstractConstantPoolInfoJava[] constantPool, int index) {
ConstantPoolFieldReferenceInfo fieldRef = (ConstantPoolFieldReferenceInfo) constantPool[index];
ConstantPoolFieldReferenceInfo fieldRef =
(ConstantPoolFieldReferenceInfo) constantPool[index];
int nameAndTypeIndex = fieldRef.getNameAndTypeIndex();
ConstantPoolNameAndTypeInfo nameAndTypeInfo = (ConstantPoolNameAndTypeInfo) constantPool[nameAndTypeIndex];
ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
ConstantPoolNameAndTypeInfo nameAndTypeInfo =
(ConstantPoolNameAndTypeInfo) constantPool[nameAndTypeIndex];
ConstantPoolUtf8Info descriptorInfo =
(ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()];
return descriptorInfo.getString();
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -19,12 +19,7 @@ import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.pcodeInject.*;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
import ghidra.javaclass.format.constantpool.ConstantPoolInterfaceMethodReferenceInfo;
import ghidra.javaclass.format.constantpool.ConstantPoolInvokeDynamicInfo;
import ghidra.javaclass.format.constantpool.ConstantPoolMethodReferenceInfo;
import ghidra.javaclass.format.constantpool.ConstantPoolNameAndTypeInfo;
import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info;
import ghidra.javaclass.format.constantpool.*;
import ghidra.program.model.data.*;
/**
@ -34,7 +29,6 @@ import ghidra.program.model.data.*;
*
*/
public class DescriptorDecoder {
public final static byte BASE_TYPE_BYTE = 'B';
@ -53,7 +47,6 @@ public class DescriptorDecoder {
public final static byte BASE_TYPE_ENUM = 'e';
public final static byte BASE_TYPE_ANNOTATION = '@';
//private constructor to enforce noninstantiability
private DescriptorDecoder() {
throw new AssertionError();
@ -83,27 +76,37 @@ public class DescriptorDecoder {
return stackPurge;
}
/**
* Returns the computational category of the return type of a method descriptor.
* @param methodDescriptor
* @return
*/
public static JavaComputationalCategory getReturnCategoryOfMethodDescriptor(String methodDescriptor){
public static JavaComputationalCategory getReturnCategoryOfMethodDescriptor(
String methodDescriptor) {
int closeParenIndex = methodDescriptor.indexOf(")");
if (closeParenIndex == -1) {
throw new IllegalArgumentException("Invalid method descriptor: " + methodDescriptor);
}
String returnDescriptor = methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
String returnDescriptor =
methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
return DescriptorDecoder.getComputationalCategoryOfDescriptor(returnDescriptor);
}
public static DataType getReturnTypeOfMethodDescriptor(String methodDescriptor, DataTypeManager dtManager){
/**
* Given a method descriptor, returns the data type of the return value of the corresponding
* method
* @param methodDescriptor descriptor of method
* @param dtManager data type manger for containing program
* @return data type of return value of method
*/
public static DataType getReturnTypeOfMethodDescriptor(String methodDescriptor,
DataTypeManager dtManager) {
int closeParenIndex = methodDescriptor.indexOf(")");
if (closeParenIndex == -1) {
throw new IllegalArgumentException("Invalid method descriptor: " + methodDescriptor);
}
String returnDescriptor = methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
String returnDescriptor =
methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
if (returnDescriptor.startsWith("[")) {
return getPointerType(returnDescriptor, dtManager);
}
@ -115,7 +118,8 @@ public class DescriptorDecoder {
* @param descriptor
* @return
*/
public static JavaComputationalCategory getComputationalCategoryOfDescriptor(String descriptor){
public static JavaComputationalCategory getComputationalCategoryOfDescriptor(
String descriptor) {
//all references to objects start with "L"
//all references to arrays start with "["
//all other descriptors are just one letter.
@ -144,7 +148,8 @@ public class DescriptorDecoder {
* @param methodDescriptor
* @return
*/
public static List<String> getTypeNameList(String methodDescriptor, boolean fullyQualifiedName, boolean replaceSlash) {
public static List<String> getTypeNameList(String methodDescriptor, boolean fullyQualifiedName,
boolean replaceSlash) {
ArrayList<String> typeNames = new ArrayList<>();
int closeParenIndex = methodDescriptor.indexOf(")");
String argString = methodDescriptor.substring(1, closeParenIndex);
@ -167,7 +172,9 @@ public class DescriptorDecoder {
else {
currentPosition++;
}
currentParamTypeName = getTypeNameFromDescriptor(argString.substring(initialBracket,currentPosition), fullyQualifiedName, replaceSlash);
currentParamTypeName =
getTypeNameFromDescriptor(argString.substring(initialBracket, currentPosition),
fullyQualifiedName, replaceSlash);
typeNames.add(currentParamTypeName);
continue;
}
@ -177,11 +184,14 @@ public class DescriptorDecoder {
switch (currentParam) {
case "L":
int semiColonIndex = argString.indexOf(";", currentPosition);
currentParamTypeName = getTypeNameFromDescriptor(argString.substring(currentPosition,semiColonIndex+1), fullyQualifiedName, replaceSlash);
currentParamTypeName = getTypeNameFromDescriptor(
argString.substring(currentPosition, semiColonIndex + 1),
fullyQualifiedName, replaceSlash);
currentPosition = semiColonIndex + 1; //advance past ;
break;
default:
currentParamTypeName = getTypeNameFromDescriptor(currentParam, fullyQualifiedName, replaceSlash);
currentParamTypeName =
getTypeNameFromDescriptor(currentParam, fullyQualifiedName, replaceSlash);
currentPosition++;
}
typeNames.add(currentParamTypeName);
@ -189,19 +199,19 @@ public class DescriptorDecoder {
}
//now add the the name of the return type
String returnType = methodDescriptor.substring(closeParenIndex+1, methodDescriptor.length());
String returnType =
methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length());
typeNames.add(getTypeNameFromDescriptor(returnType, fullyQualifiedName, replaceSlash));
return typeNames;
}
/**
* Returns the type name for a parameter descriptor
* @param descriptor
* @return
*/
public static String getTypeNameFromDescriptor(String descriptor, boolean fullyQualifiedName, boolean replaceSlash){
public static String getTypeNameFromDescriptor(String descriptor, boolean fullyQualifiedName,
boolean replaceSlash) {
if (descriptor.startsWith("L")) {
//leave off the initial L and the final ;
String name = descriptor.substring(1, descriptor.length() - 1);
@ -217,7 +227,8 @@ public class DescriptorDecoder {
}
if (descriptor.startsWith("[")) {
int dimension = descriptor.lastIndexOf("[") + 1;
String baseType = getTypeNameFromDescriptor(descriptor.replace("[", ""), fullyQualifiedName, replaceSlash);
String baseType = getTypeNameFromDescriptor(descriptor.replace("[", ""),
fullyQualifiedName, replaceSlash);
StringBuilder sb = new StringBuilder(baseType);
for (int i = 0; i < dimension; ++i) {
sb.append("[]");
@ -248,15 +259,16 @@ public class DescriptorDecoder {
}
}
public static DataType getReferenceTypeOfDescriptor(String descriptor, DataTypeManager dtManager, boolean includesLandSemi){
public static DataType getReferenceTypeOfDescriptor(String descriptor,
DataTypeManager dtManager, boolean includesLandSemi) {
if (includesLandSemi) {
descriptor = descriptor.substring(1, descriptor.length() - 1);
}
String[] parts = descriptor.split("/");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < parts.length; i++){
for (String part : parts) {
sb.append(CategoryPath.DELIMITER_CHAR);
sb.append(parts[i]);
sb.append(part);
}
DataTypePath dataPath = new DataTypePath(sb.toString(), parts[parts.length - 1]);
DataType referencedType = dtManager.getDataType(dataPath);
@ -297,10 +309,16 @@ public class DescriptorDecoder {
case BASE_TYPE_VOID: //void (only for return types)
return DataType.VOID;
default:
throw new IllegalArgumentException("Invalid computational category: " + descriptor);
throw new IllegalArgumentException("Invalid type descriptor: " + descriptor);
}
}
/**
* Returns the data type of a pointer to the type represented by descriptor
* @param descriptor description of base type
* @param dtManager data type manager of program
* @return pointer data type
*/
public static DataType getPointerType(String descriptor, DataTypeManager dtManager) {
int lastBracket = descriptor.lastIndexOf("[");
String baseTypeOfArray = descriptor.substring(lastBracket + 1, lastBracket + 2);
@ -334,7 +352,8 @@ public class DescriptorDecoder {
return dtManager.getPointer(DWordDataType.dataType);
default:
throw new IllegalArgumentException("Invalid array base type category: " + baseTypeOfArray);
throw new IllegalArgumentException(
"Invalid array base type category: " + baseTypeOfArray);
}
return dtManager.getPointer(baseType);
}
@ -353,7 +372,8 @@ public class DescriptorDecoder {
int len = argString.length();
while (currentPosition < len) {
String currentParam = argString.substring(currentPosition, currentPosition + 1);
JavaComputationalCategory category = DescriptorDecoder.getComputationalCategoryOfDescriptor(currentParam);
JavaComputationalCategory category =
DescriptorDecoder.getComputationalCategoryOfDescriptor(currentParam);
switch (category) {
case CAT_1:
@ -402,7 +422,8 @@ public class DescriptorDecoder {
* @param methodDescriptor
* @return
*/
public static List<DataType> getDataTypeList(String methodDescriptor, DataTypeManager dtManager) {
public static List<DataType> getDataTypeList(String methodDescriptor,
DataTypeManager dtManager) {
ArrayList<DataType> paramDataTypes = new ArrayList<>();
int closeParenIndex = methodDescriptor.indexOf(")");
String argString = methodDescriptor.substring(1, closeParenIndex);
@ -455,41 +476,63 @@ public class DescriptorDecoder {
* @param type
* @return
*/
public static String getDescriptorForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type){
public static String getDescriptorForInvoke(int offset,
AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) {
String descriptor = null;
int name_and_type_index = 0;
switch (type) {
case INVOKE_DYNAMIC:
ConstantPoolInvokeDynamicInfo dynamicInfo = (ConstantPoolInvokeDynamicInfo) constantPool[offset];
ConstantPoolInvokeDynamicInfo dynamicInfo =
(ConstantPoolInvokeDynamicInfo) constantPool[offset];
name_and_type_index = dynamicInfo.getNameAndTypeIndex();
break;
case INVOKE_INTERFACE:
ConstantPoolInterfaceMethodReferenceInfo interfaceInfo = (ConstantPoolInterfaceMethodReferenceInfo) constantPool[offset];
ConstantPoolInterfaceMethodReferenceInfo interfaceInfo =
(ConstantPoolInterfaceMethodReferenceInfo) constantPool[offset];
name_and_type_index = interfaceInfo.getNameAndTypeIndex();
break;
case INVOKE_SPECIAL:
case INVOKE_STATIC:
AbstractConstantPoolInfoJava poolElem = constantPool[offset];
if (poolElem instanceof ConstantPoolInterfaceMethodReferenceInfo) {
interfaceInfo = (ConstantPoolInterfaceMethodReferenceInfo) constantPool[offset];
name_and_type_index = interfaceInfo.getNameAndTypeIndex();
break;
}
if (poolElem instanceof ConstantPoolMethodReferenceInfo) {
ConstantPoolMethodReferenceInfo methodReferenceInfo =
(ConstantPoolMethodReferenceInfo) constantPool[offset];
name_and_type_index = methodReferenceInfo.getNameAndTypeIndex();
break;
}
throw new IllegalArgumentException(
"Unsupported type for invokestatic at constant pool element " + offset);
case INVOKE_SPECIAL:
case INVOKE_VIRTUAL:
ConstantPoolMethodReferenceInfo methodReferenceInfo = (ConstantPoolMethodReferenceInfo) constantPool[offset];
ConstantPoolMethodReferenceInfo methodReferenceInfo =
(ConstantPoolMethodReferenceInfo) constantPool[offset];
name_and_type_index = methodReferenceInfo.getNameAndTypeIndex();
break;
default:
throw new IllegalArgumentException("unimplemented method type: " + type.name());
}
ConstantPoolNameAndTypeInfo methodNameAndType = (ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index];
ConstantPoolNameAndTypeInfo methodNameAndType =
(ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index];
int descriptor_index = methodNameAndType.getDescriptorIndex();
ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index];
descriptor = descriptorInfo.getString();
return descriptor;
}
public final static String decodeType(ConstantPoolUtf8Info utf,
boolean useFullyQualifiedClassName) {
return DescriptorDecoder.getTypeNameFromDescriptor(utf.getString(), useFullyQualifiedClassName, true);
}
//no L, no ;
public static DataType resolveClassForString(String fullyQualifiedName, DataTypeManager dtm, DataType baseType){
/**
* Resolves the datatype represented by {@code fullyQualifiedName} with a base type of
* {@code baseType} into dtm
* @param fullyQualifiedName String representation of type
* @param dtm data type manager
* @param baseType base type
* @return data type represented by input string
*/
public static DataType resolveClassForString(String fullyQualifiedName, DataTypeManager dtm,
DataType baseType) {
fullyQualifiedName = CategoryPath.DELIMITER_CHAR + fullyQualifiedName;
CategoryPath catPath = new CategoryPath(fullyQualifiedName);
String[] parts = catPath.getPathElements();
@ -498,4 +541,26 @@ public class DescriptorDecoder {
return dataType;
}
/**
* Returns a String representing the types of the parameters of a method, e.g.
* (java.lang.String, java.lang.Integer) for a method with signature
* public static void test(String x, Integer y);
* @param descriptor method descriptor
* @return string representation of types of method parameters
*/
public static String getParameterString(String descriptor) {
List<String> paramTypeNames = getTypeNameList(descriptor, true, true);
StringBuilder sb = new StringBuilder();
sb.append("(");
//don't append the last element of the list, which is the return type
for (int i = 0, max = paramTypeNames.size() - 1; i < max; ++i) {
sb.append(paramTypeNames.get(i));
if (i < max - 1) {
sb.append(", ");
}
}
sb.append(")");
return sb.toString();
}
}

View file

@ -15,14 +15,14 @@
*/
package ghidra.javaclass.format;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.javaclass.format.attributes.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -57,8 +57,8 @@ public class FieldInfoJava 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());
}
}
@ -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;
}
/**

View file

@ -15,13 +15,13 @@
*/
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;
@ -29,23 +29,19 @@ public class JavaClassUtil {
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();
Address address = program.getAddressFactory().getAddressSpace(
JavaLoader.CONSTANT_POOL).getMinAddress();
program.getMemory().getBytes(address, bytes);
}
catch (Exception e) {
Msg.info(JavaClassUtil.class, e.getLocalizedMessage());
return false;
}
return Arrays.equals(bytes, JavaClassConstants.MAGIC_BYTES);
}
return false;
}
public static Address toLookupAddress(Program program, int methodIndex) {
AddressFactory addressFactory = program.getAddressFactory();

View file

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

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,12 +15,12 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.StructureDataType;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -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;
}
/**

View file

@ -15,6 +15,8 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.javaclass.format.DescriptorDecoder;
@ -22,8 +24,6 @@ import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -74,12 +74,9 @@ public class AnnotationElementValue implements StructConverter {
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 ||
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) {
@ -98,8 +95,8 @@ public class AnnotationElementValue implements StructConverter {
}
else if (tag == DescriptorDecoder.BASE_TYPE_ARRAY) {
numberOfValues = reader.readNextShort();
values = new AnnotationElementValue[ numberOfValues ];
for ( int i = 0 ; i < numberOfValues ; ++i ) {
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() {
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() {
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;
}
/**
@ -215,12 +212,9 @@ public class AnnotationElementValue implements StructConverter {
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 ||
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) {

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,14 +15,14 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -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;
}
/**

View file

@ -15,14 +15,14 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -50,8 +50,8 @@ public class AnnotationJava implements StructConverter {
public AnnotationJava(BinaryReader reader) throws IOException {
typeIndex = reader.readNextShort();
numberOfElementValuePairs = reader.readNextShort();
elementValuePairs = new AnnotationElementValuePair[ numberOfElementValuePairs ];
for ( int i = 0 ; i < numberOfElementValuePairs ; ++i ) {
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,8 +77,8 @@ 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;
}
/**

View file

@ -15,15 +15,16 @@
*/
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 {
public static AbstractAttributeInfo get(BinaryReader reader,
AbstractConstantPoolInfoJava[] constantPool) throws IOException {
int attributeNameIndex = reader.readShort(reader.getPointerIndex());
@ -37,68 +38,59 @@ public class AttributeFactory {
ConstantPoolUtf8Info utf8 = (ConstantPoolUtf8Info) constantPool[attributeNameIndex];
if ( utf8.getString().equals( AttributesConstants.ConstantValue ) ) {
return new ConstantValueAttribute( reader );
}
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 ) ) {
switch (utf8.getString()) {
case AttributesConstants.AnnotationDefault:
return new AnnotationDefaultAttribute(reader);
}
else if ( utf8.getString().equals( AttributesConstants.BootstrapMethods ) ) {
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());
}
}
}

View file

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

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,9 +19,7 @@ import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.ArrayDataType;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
@ -39,7 +36,7 @@ public class BootstrapMethods implements StructConverter {
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,10 +77,11 @@ 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

View file

@ -15,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -62,14 +62,14 @@ public class BootstrapMethodsAttribute extends AbstractAttributeInfo {
numberOfBootstrapMethods = reader.readNextShort();
bootstrapMethods = new BootstrapMethods[ numberOfBootstrapMethods ];
for ( int i = 0 ; i < numberOfBootstrapMethods ; ++i ) {
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() {

View file

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

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -80,8 +79,8 @@ 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

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -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,8 +73,8 @@ 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

View file

@ -15,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -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,8 +99,8 @@ 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

View file

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

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,14 +15,14 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -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;
}
/**

View file

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

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,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>
@ -53,16 +52,16 @@ 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

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -58,8 +57,8 @@ public class LineNumberTableAttribute extends AbstractAttributeInfo {
super(reader);
lineNumberTableLength = reader.readNextShort();
lineNumberTable = new LineNumber[ lineNumberTableLength ];
for ( int i = 0 ; i < lineNumberTableLength ; i++ ) {
lineNumberTable = new LineNumber[lineNumberTableLength & 0xffff];
for (int i = 0; i < (lineNumberTableLength & 0xffff); i++) {
lineNumberTable[i] = new LineNumber(reader);
}
}

View file

@ -15,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -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,8 +153,8 @@ 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

View file

@ -15,14 +15,14 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -55,12 +55,13 @@ public class LocalVariableTableAttribute extends AbstractAttributeInfo {
private short localVariableTableLength;
private LocalVariableJava[] localVariableTable;
public LocalVariableTableAttribute( BinaryReader reader, AbstractConstantPoolInfoJava [] constantPool ) throws IOException {
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 = new LocalVariableJava[localVariableTableLength & 0xffff];
for (int i = 0; i < (localVariableTableLength & 0xffff); i++) {
localVariableTable[i] = new LocalVariableJava(reader);
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -15,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -59,9 +59,9 @@ public class RuntimeInvisibleAnnotationsAttribute extends AbstractAttributeInfo
numberOfAnnotations = reader.readNextShort();
annotations = new AnnotationJava[ numberOfAnnotations ];
annotations = new AnnotationJava[getNumberOfAnnotations()];
for ( int i = 0 ; i < numberOfAnnotations ; ++i ) {
for (int i = 0; i < getNumberOfAnnotations(); ++i) {
annotations[i] = new AnnotationJava(reader);
}
}
@ -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;
}
/**

View file

@ -15,15 +15,15 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -65,19 +65,21 @@ 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 {
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 ) {
AnnotationJava[] annotations = new AnnotationJava[(numberOfAnnotations & 0xffff)];
for (int a = 0; a < (numberOfAnnotations & 0xffff); ++a) {
annotations[a] = new AnnotationJava(reader);
}
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;
}
/**
@ -126,9 +128,9 @@ public class RuntimeParameterAnnotationsAttribute extends AbstractAttributeInfo
@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);

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -60,8 +59,8 @@ 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

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +15,13 @@
*/
package ghidra.javaclass.format.attributes;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -62,8 +61,8 @@ 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

View file

@ -15,11 +15,11 @@
*/
package ghidra.javaclass.format.constantpool;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter;
import java.io.IOException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>

View file

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

View file

@ -18,9 +18,7 @@ package ghidra.javaclass.format.constantpool;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
@ -60,8 +58,8 @@ public class ConstantPoolClassInfo extends AbstractConstantPoolInfoJava {
* interface name encoded in internal form (?4.2.1).
* @return a valid index into the constant_pool table
*/
public short getNameIndex() {
return nameIndex;
public int getNameIndex() {
return nameIndex & 0xffff;
}
@Override

View file

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

View file

@ -15,10 +15,10 @@
*/
package ghidra.javaclass.format.constantpool;
import ghidra.app.util.bin.BinaryReader;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
public class ConstantPoolFactory {
public static AbstractConstantPoolInfoJava get(BinaryReader reader) throws IOException {
@ -67,10 +67,22 @@ public class ConstantPoolFactory {
case ConstantPoolTagsJava.CONSTANT_Utf8:
return new ConstantPoolUtf8Info(reader);
case ConstantPoolTagsJava.CONSTANT_Dynamic:
return new ConstantPoolDynamicInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Module:
return new ConstantPoolModuleInfo(reader);
case ConstantPoolTagsJava.CONSTANT_Package:
return new ConstantPoolPackageInfo(reader);
case 0:
return null;
default:
throw new IllegalArgumentException(
"Unsupport Constant Pool Entry Type: " + reader.peekNextByte());
}
throw new RuntimeException();
}
}

View file

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

View file

@ -15,14 +15,11 @@
*/
package ghidra.javaclass.format.constantpool;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
@ -39,7 +36,7 @@ import java.io.IOException;
public class ConstantPoolMethodHandleInfo extends AbstractConstantPoolInfoJava {
private byte referenceKind;
private int referenceIndex;
private short referenceIndex;
public ConstantPoolMethodHandleInfo(BinaryReader reader) throws IOException {
super(reader);
@ -101,7 +98,7 @@ public class ConstantPoolMethodHandleInfo extends AbstractConstantPoolInfoJava {
* @return a valid index into the constant_pool table
*/
public int getReferenceIndex() {
return referenceIndex;
return referenceIndex & 0xffff;
}
@Override

View file

@ -18,9 +18,7 @@ package ghidra.javaclass.format.constantpool;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
@ -49,8 +47,8 @@ public class ConstantPoolMethodTypeInfo extends AbstractConstantPoolInfoJava {
* CONSTANT_Utf8_info structure representing a method descriptor.
* @return a valid index into the constant_pool table
*/
public short getDescriptorIndex() {
return descriptorIndex;
public int getDescriptorIndex() {
return descriptorIndex & 0xffff;
}
@Override

View file

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

View file

@ -15,14 +15,12 @@
*/
package ghidra.javaclass.format.constantpool;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
* <p>
@ -55,8 +53,8 @@ public class ConstantPoolNameAndTypeInfo extends AbstractConstantPoolInfoJava {
* method.
* @return a valid index into the constant_pool table to the name
*/
public short getNameIndex() {
return nameIndex;
public int getNameIndex() {
return nameIndex & 0xffff;
}
/**
@ -66,8 +64,8 @@ public class ConstantPoolNameAndTypeInfo extends AbstractConstantPoolInfoJava {
* or method descriptor.
* @return a valid index into the constant_pool table to the descriptor
*/
public short getDescriptorIndex() {
return descriptorIndex;
public int getDescriptorIndex() {
return descriptorIndex & 0xffff;
}
@Override

View file

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

View file

@ -18,9 +18,7 @@ package ghidra.javaclass.format.constantpool;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
@ -51,8 +49,8 @@ public class ConstantPoolStringInfo extends AbstractConstantPoolInfoJava {
* code points to which the String object is to be initialized.
* @return a valid index into the constant_pool table
*/
public short getStringIndex() {
return stringIndex;
public int getStringIndex() {
return stringIndex & 0xffff;
}
@Override

View file

@ -30,6 +30,9 @@ public final class ConstantPoolTagsJava {
public final static byte CONSTANT_Utf8 = 1;
public final static byte CONSTANT_MethodHandle = 15;
public final static byte CONSTANT_MethodType = 16;
public final static byte CONSTANT_Dynamic = 17;
public final static byte CONSTANT_InvokeDynamic = 18;
public final static byte CONSTANT_Module = 19;
public final static byte CONSTANT_Package = 20;
}

View file

@ -46,7 +46,7 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
public ConstantPoolUtf8Info(BinaryReader reader) throws IOException {
super(reader);
length = reader.readNextShort();
bytes = reader.readNextByteArray( length );
bytes = reader.readNextByteArray(getLength());
}
/**
@ -55,8 +55,8 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava {
* structure are not null-terminated.
* @return the number of bytes in the bytes array
*/
public short getLength() {
return length;
public int getLength() {
return length & 0xffff;
}
/**

View file

@ -28,7 +28,6 @@ import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
public class InvokeMethodsTest {
@Test
public void testEmitPcodeToResolveMethodReferenceInvokeDynamic() throws IOException {
short bootstrap = 0;
@ -42,13 +41,17 @@ public class InvokeMethodsTest {
TestClassFileCreator.appendUtf8(classFile, "(I)I"); //4 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
StringBuilder pCode = new StringBuilder();
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
JavaInvocationType.INVOKE_DYNAMIC);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
assertEquals("incorrect pcode for dynamic invocation", expected.toString(), pCode.toString());
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
assertEquals("incorrect pcode for dynamic invocation", expected.toString(),
pCode.toString());
}
@Test
@ -65,13 +68,18 @@ public class InvokeMethodsTest {
TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
StringBuilder pCode = new StringBuilder();
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_INTERFACE);
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
JavaInvocationType.INVOKE_INTERFACE);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1", ConstantPoolJava.CPOOL_INVOKEINTERFACE);
assertEquals("incorrect pcode for interface method invocation", expected.toString(), pCode.toString());
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1",
ConstantPoolJava.CPOOL_INVOKEINTERFACE);
assertEquals("incorrect pcode for interface method invocation", expected.toString(),
pCode.toString());
}
@Test
@ -88,13 +96,18 @@ public class InvokeMethodsTest {
TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
StringBuilder pCode = new StringBuilder();
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_SPECIAL);
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
JavaInvocationType.INVOKE_SPECIAL);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1", ConstantPoolJava.CPOOL_INVOKESPECIAL);
assertEquals("incorrect pcode for special method invocation", expected.toString(), pCode.toString());
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1",
ConstantPoolJava.CPOOL_INVOKESPECIAL);
assertEquals("incorrect pcode for special method invocation", expected.toString(),
pCode.toString());
}
@Test
@ -111,13 +124,17 @@ public class InvokeMethodsTest {
TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
StringBuilder pCode = new StringBuilder();
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_STATIC);
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
JavaInvocationType.INVOKE_STATIC);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKESTATIC);
assertEquals("incorrect pcode for static method invocation", expected.toString(), pCode.toString());
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKESTATIC);
assertEquals("incorrect pcode for static method invocation", expected.toString(),
pCode.toString());
}
@Test
@ -134,13 +151,18 @@ public class InvokeMethodsTest {
TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
StringBuilder pCode = new StringBuilder();
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_VIRTUAL);
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
JavaInvocationType.INVOKE_VIRTUAL);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1", ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
assertEquals("incorrect pcode for static method invocation", expected.toString(), pCode.toString());
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1",
ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
assertEquals("incorrect pcode for static method invocation", expected.toString(),
pCode.toString());
}
@Test
@ -148,13 +170,10 @@ public class InvokeMethodsTest {
StringBuilder pCode = new StringBuilder();
//InvokeMethods.emitPcodeToReverseStack(pCode, new ArrayList<JavaComputationalCategory>(), false);
StringBuilder expected = new StringBuilder();
assertEquals("incorrect pcode reversing stack: no params no this", expected.toString(), pCode.toString());
assertEquals("incorrect pcode reversing stack: no params no this", expected.toString(),
pCode.toString());
}
//test bad category
@Test
@ -169,20 +188,22 @@ public class InvokeMethodsTest {
TestClassFileCreator.appendUtf8(classFile, "(JJII)I"); //4 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = InvokeMethods.getPcodeForInvoke(1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode =
InvokeMethods.getPcodeForInvoke(1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
StringBuilder expected = new StringBuilder();
String descriptor = DescriptorDecoder.getDescriptorForInvoke(1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
List<JavaComputationalCategory> categories = DescriptorDecoder.getParameterCategories(descriptor);
String descriptor = DescriptorDecoder.getDescriptorForInvoke(1, constantPool,
JavaInvocationType.INVOKE_DYNAMIC);
List<JavaComputationalCategory> categories =
DescriptorDecoder.getParameterCategories(descriptor);
InvokeMethods.emitPcodeToMoveParams(expected, categories, false, 24);
InvokeMethods.emitPcodeToResolveMethodReference(expected, 1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
InvokeMethods.emitPcodeToResolveMethodReference(expected, 1, constantPool,
JavaInvocationType.INVOKE_DYNAMIC);
PcodeTextEmitter.emitIndirectCall(expected, InvokeMethods.CALL_TARGET);
PcodeTextEmitter.emitPushCat1Value(expected, InvokeMethods.CAT_1_RETURN);
System.out.println(pCode);
System.out.println(expected);
assertEquals("incorrect pcode for invoke dynamic: (JJII)I", expected.toString(), pCode);

View file

@ -64,10 +64,10 @@ public class PcodeTextEmitterTest {
//two args
pCode = new StringBuilder();
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 4, "PCODEOP", "ARG1", "ARG2");
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 4, "PCODEOP", "ARG1",
"ARG2");
assertTrue(pCode.toString().equals("LHS:4 = PCODEOP(ARG1,ARG2);\n"));
//test no args
pCode = new StringBuilder();
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 8, "PCODEOP");
@ -80,7 +80,8 @@ public class PcodeTextEmitterTest {
//two args
pCode = new StringBuilder();
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 8, "PCODEOP", "ARG1", "ARG2");
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 8, "PCODEOP", "ARG1",
"ARG2");
assertTrue(pCode.toString().equals("LHS:8 = PCODEOP(ARG1,ARG2);\n"));
}
@ -135,13 +136,6 @@ public class PcodeTextEmitterTest {
assertEquals("bad label definition emitted", "<LABEL>\n", pCode.toString());
}
@Test
public void testEmitAddToStackPointer(){
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitAddToStackPointer(pCode, 4);
assertEquals("SP = SP + 4;\n", pCode.toString());
}
@Test
public void testEmitIndirectCall() {
StringBuilder pCode = new StringBuilder();
@ -156,4 +150,32 @@ public class PcodeTextEmitterTest {
assertEquals("*[ram]:4 offset = test;\n", pCode.toString());
}
@Test
public void testEmitSignExtension() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitSignExtension(pCode, "dest", 4, "src");
assertEquals("dest:4 = sext(src);\n", pCode.toString());
}
@Test
public void testEmitZeroExtension() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitZeroExtension(pCode, "dest", 4, "src");
assertEquals("dest:4 = zext(src);\n", pCode.toString());
}
@Test
public void testEmitTruncate() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitTruncate(pCode, "dest", 4, "src");
assertEquals("dest = src:4;\n", pCode.toString());
}
@Test
public void testAssignVarnodeFromDereference() {
StringBuilder pCode = new StringBuilder();
PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, "dest", 4, "src");
assertEquals("dest:4 = *:4 src;\n", pCode.toString());
}
}

View file

@ -15,8 +15,7 @@
*/
package ghidra.app.util.pcodeInject;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.ArrayList;
@ -27,8 +26,6 @@ import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
public class ReferenceMethodsTest {
public ReferenceMethodsTest() {
}
@ -47,15 +44,18 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForGetStatic(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.VALUE, 4, ConstantPoolJava.CPOOL_OP , "0", "1", ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.TEMP_1, 4,
ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromDereference(expected, ReferenceMethods.VALUE, 4,
ReferenceMethods.TEMP_1);
PcodeTextEmitter.emitPushCat1Value(expected, ReferenceMethods.VALUE);
assertTrue(pCode.equals(expected.toString()));
}
@Test
@ -72,12 +72,16 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForGetStatic(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.VALUE, 8, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.TEMP_1, 8,
ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_GETSTATIC);
PcodeTextEmitter.emitAssignVarnodeFromDereference(expected, ReferenceMethods.VALUE, 8,
ReferenceMethods.TEMP_1);
PcodeTextEmitter.emitPushCat2Value(expected, ReferenceMethods.VALUE);
assertEquals(pCode, expected.toString());
@ -97,13 +101,16 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForPutStatic(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 4, ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET,
4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 4,
ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE);
assertEquals(pCode, expected.toString());
}
@ -121,16 +128,18 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForPutStatic(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat2Value(expected, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 8, ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.STATIC_OFFSET,
4, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_PUTSTATIC);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 8,
ReferenceMethods.STATIC_OFFSET, ReferenceMethods.NEW_VALUE);
assertEquals(pCode, expected.toString());
}
@Test
@ -147,12 +156,17 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForGetField(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.VALUE, 4, ConstantPoolJava.CPOOL_OP , ReferenceMethods.OBJECT_REF, "1", ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.TEMP_1, 4,
ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1",
ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromDereference(expected, ReferenceMethods.VALUE, 4,
ReferenceMethods.TEMP_1);
PcodeTextEmitter.emitPushCat1Value(expected, ReferenceMethods.VALUE);
assertEquals(pCode, expected.toString());
@ -172,12 +186,17 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForGetField(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.VALUE, 8, ConstantPoolJava.CPOOL_OP , ReferenceMethods.OBJECT_REF, "1", ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.TEMP_1, 8,
ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1",
ConstantPoolJava.CPOOL_GETFIELD);
PcodeTextEmitter.emitAssignVarnodeFromDereference(expected, ReferenceMethods.VALUE, 8,
ReferenceMethods.TEMP_1);
PcodeTextEmitter.emitPushCat2Value(expected, ReferenceMethods.VALUE);
assertEquals(pCode, expected.toString());
@ -197,14 +216,18 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendUtf8(classFile, "I"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForPutField(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1", ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 4, ReferenceMethods.FIELD_OFFSET, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET,
4, ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1",
ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 4,
ReferenceMethods.FIELD_OFFSET, ReferenceMethods.NEW_VALUE);
assertEquals(pCode, expected.toString());
@ -224,20 +247,21 @@ public class ReferenceMethodsTest {
TestClassFileCreator.appendUtf8(classFile, "J"); //6 (descriptor)
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode = ReferenceMethods.getPcodeForPutField(1, constantPool);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitPopCat2Value(expected, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitPopCat1Value(expected, ReferenceMethods.OBJECT_REF);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1", ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 8, ReferenceMethods.FIELD_OFFSET, ReferenceMethods.NEW_VALUE);
PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(expected, ReferenceMethods.FIELD_OFFSET,
4, ConstantPoolJava.CPOOL_OP, ReferenceMethods.OBJECT_REF, "1",
ConstantPoolJava.CPOOL_PUTFIELD);
PcodeTextEmitter.emitWriteToMemory(expected, PcodeTextEmitter.RAM, 8,
ReferenceMethods.FIELD_OFFSET, ReferenceMethods.NEW_VALUE);
assertEquals(pCode, expected.toString());
}
}

View file

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

View file

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