diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ConstantPool.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ConstantPool.java index bf8c322a65..100c29fde8 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ConstantPool.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ConstantPool.java @@ -26,15 +26,15 @@ import ghidra.util.xml.SpecXmlUtils; * */ public abstract class ConstantPool { - public static final int PRIMITIVE = 0; // Constant -value- of datatype -type- - public static final int STRING_LITERAL = 1; // Constant reference to string in -token- - public static final int CLASS_REFERENCE = 2; // Reference to (system level) class object - public static final int POINTER_METHOD = 3; // Pointer to a method, name in -token-, signature in -type- - public static final int POINTER_FIELD = 4; // Pointer to a field, name in -token-, datatype in -type- - public static final int ARRAY_LENGTH = 5; // Integer length, -token- is language specific indicator, -type- is integral type - public static final int INSTANCE_OF = 6; // boolean value, -token- is language specific indicator, -type- is boolean type - public static final int CHECK_CAST = 7; // Pointer to object, new name in -token-, new datatype in -type- - + public static final int PRIMITIVE = 0; // Constant -value- of datatype -type- + public static final int STRING_LITERAL = 1; // Constant reference to string in -token- + public static final int CLASS_REFERENCE = 2; // Reference to (system level) class object + public static final int POINTER_METHOD = 3; // Pointer to a method, name in -token-, signature in -type- + public static final int POINTER_FIELD = 4; // Pointer to a field, name in -token-, datatype in -type- + public static final int ARRAY_LENGTH = 5; // Integer length, -token- is language specific indicator, -type- is integral type + public static final int INSTANCE_OF = 6; // boolean value, -token- is language specific indicator, -type- is boolean type + public static final int CHECK_CAST = 7; // Pointer to object, new name in -token-, new datatype in -type- + public static class Record { public int tag; // The type of the record public String token; // Name or token associated with object @@ -43,31 +43,41 @@ public abstract class ConstantPool { public DataType type; public boolean hasThisPtr = false; public boolean isConstructor = false; - - public StringBuilder build(long ref,PcodeDataTypeManager dtmanage) { + + public StringBuilder build(long ref, PcodeDataTypeManager dtmanage) { StringBuilder buf = new StringBuilder(); buf.append("\n"); if (tag == PRIMITIVE) { buf.append(""); diff --git a/Ghidra/Processors/JVM/data/languages/JVM.cspec b/Ghidra/Processors/JVM/data/languages/JVM.cspec index 90f5815d79..a1e6dc81f5 100644 --- a/Ghidra/Processors/JVM/data/languages/JVM.cspec +++ b/Ghidra/Processors/JVM/data/languages/JVM.cspec @@ -99,15 +99,7 @@ - - - - - - - - - + diff --git a/Ghidra/Processors/JVM/data/languages/JVM.slaspec b/Ghidra/Processors/JVM/data/languages/JVM.slaspec index f73c04a274..cf5e6395f8 100644 --- a/Ghidra/Processors/JVM/data/languages/JVM.slaspec +++ b/Ghidra/Processors/JVM/data/languages/JVM.slaspec @@ -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); } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/opinion/JavaLoader.java b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/opinion/JavaLoader.java index 8e235f5f18..967d2b6ade 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/opinion/JavaLoader.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/opinion/JavaLoader.java @@ -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 findSupportedLoadSpecs(ByteProvider provider) throws IOException { @@ -61,22 +64,24 @@ public class JavaLoader extends AbstractLibrarySupportLoader { return loadSpecs; } - private boolean checkClass(ByteProvider provider) { + private boolean checkClass(ByteProvider provider) throws IOException { BinaryReader reader = new BinaryReader(provider, false); - ClassFileJava classFile; + int magic = reader.peekNextInt(); + //if it doesn't begin with the 0xCAFEBABE it's not a class file + if (magic != JavaClassConstants.MAGIC) { + return false; + } + //attempt to parse the header, if successful count it as a class file. try { - classFile = new ClassFileJava(reader); + new ClassFileJava(reader); } catch (IOException e) { return false; - } catch (RuntimeException re) { + } + catch (RuntimeException re) { return false; } - int magic = classFile.getMagic(); - if (magic == 0xCAFEBABE) { - return true; - } - return false; + return true; } @Override @@ -117,7 +122,7 @@ public class JavaLoader extends AbstractLibrarySupportLoader { throws LockException, MemoryConflictException, AddressOverflowException, CancelledException, DuplicateNameException, IOException { AddressFactory af = program.getAddressFactory(); - AddressSpace space = af.getAddressSpace("constantPool"); + AddressSpace space = af.getAddressSpace(CONSTANT_POOL); Memory memory = program.getMemory(); alignmentReg = program.getRegister("alignmentPad"); @@ -130,28 +135,27 @@ public class JavaLoader extends AbstractLibrarySupportLoader { memory.createInitializedBlock("_" + provider.getName() + "_", address, provider.getInputStream(0), provider.length(), monitor, false); - createMethodLookupMemoryBlock( program, monitor ); + createMethodLookupMemoryBlock(program, monitor); createMethodMemoryBlocks(program, provider, classFile, monitor); } - - private void createMethodLookupMemoryBlock(Program program, TaskMonitor monitor) { - Address address = toAddr( program, JavaClassUtil.LOOKUP_ADDRESS ); + Address address = toAddr(program, JavaClassUtil.LOOKUP_ADDRESS); MemoryBlock block = null; Memory memory = program.getMemory(); try { - block = memory.createInitializedBlock( "method_lookup", address, JavaClassUtil.METHOD_INDEX_SIZE, (byte) 0xff, monitor, false ); + block = memory.createInitializedBlock("method_lookup", address, + JavaClassUtil.METHOD_INDEX_SIZE, (byte) 0xff, monitor, false); } catch (LockException | DuplicateNameException | MemoryConflictException | AddressOverflowException | CancelledException e) { // TODO Auto-generated catch block e.printStackTrace(); } - block.setRead( true ); - block.setWrite( false ); - block.setExecute( false ); + block.setRead(true); + block.setWrite(false); + block.setExecute(false); } @@ -164,12 +168,11 @@ public class JavaLoader extends AbstractLibrarySupportLoader { monitor.setProgress(0); monitor.setMaximum(methods.length); - long codeOffset = 0x10000; - Address start = toAddr(program, codeOffset); + Address start = toAddr(program, CODE_OFFSET); try { //program.setImageBase(start, true); //for (MethodInfoJava method : methods) { - for (int i = 0, max = methods.length; i < max; ++i){ + for (int i = 0, max = methods.length; i < max; ++i) { MethodInfoJava method = methods[i]; monitor.incrementProgress(1); CodeAttribute code = method.getCodeAttribute(); @@ -180,18 +183,19 @@ public class JavaLoader extends AbstractLibrarySupportLoader { long offset = code.getCodeOffset(); Memory memory = program.getMemory(); - short nameIndex = method.getNameIndex(); - short descriptorIndex = method.getDescriptorIndex(); - ConstantPoolUtf8Info methodNameInfo = (ConstantPoolUtf8Info) constantPool[nameIndex]; + int nameIndex = method.getNameIndex(); + int descriptorIndex = method.getDescriptorIndex(); + ConstantPoolUtf8Info methodNameInfo = + (ConstantPoolUtf8Info) constantPool[nameIndex]; ConstantPoolUtf8Info methodDescriptorInfo = - (ConstantPoolUtf8Info) constantPool[descriptorIndex]; + (ConstantPoolUtf8Info) constantPool[descriptorIndex]; String methodName = methodNameInfo.getString() + methodDescriptorInfo.getString(); - MemoryBlock memoryBlock = - memory.createInitializedBlock(methodName, start, - provider.getInputStream(offset), length, monitor, false); - Address methodIndexAddress = JavaClassUtil.toLookupAddress( program, i ); - program.getMemory( ).setInt( methodIndexAddress, (int) start.getOffset() ); + MemoryBlock memoryBlock = memory.createInitializedBlock(methodName, start, + provider.getInputStream(offset), length, monitor, false); + Address methodIndexAddress = JavaClassUtil.toLookupAddress(program, i); + program.getMemory().setInt(methodIndexAddress, (int) start.getOffset()); + program.getListing().createData(methodIndexAddress, PointerDataType.dataType); setAlignmentInfo(program, new AddressSet(memoryBlock.getStart(), memoryBlock.getEnd())); @@ -200,10 +204,9 @@ public class JavaLoader extends AbstractLibrarySupportLoader { start = start.add(1); } - - } - } catch (Exception e1) { + } + catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } @@ -214,9 +217,8 @@ public class JavaLoader extends AbstractLibrarySupportLoader { int alignmentValue = 3; while (addressIterator.hasNext()) { Address address = addressIterator.next(); - SetRegisterCmd cmd = - new SetRegisterCmd(alignmentReg, address, address, - BigInteger.valueOf(alignmentValue)); + SetRegisterCmd cmd = new SetRegisterCmd(alignmentReg, address, address, + BigInteger.valueOf(alignmentValue)); cmd.applyTo(program); if (alignmentValue == 0) { alignmentValue = 3; diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ConstantPoolJava.java b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ConstantPoolJava.java index 7d41025470..3b03ee7672 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ConstantPoolJava.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ConstantPoolJava.java @@ -32,24 +32,24 @@ public class ConstantPoolJava extends ConstantPool { private DataTypeManager dtManager = null; //the following constants must agree with the definitions in JVM.slaspec - public static final String CPOOL_ANEWARRAY = "0"; - public static final String CPOOL_CHECKCAST = "1"; - public static final String CPOOL_GETFIELD = "2"; - public static final String CPOOL_GETSTATIC = "3"; - public static final String CPOOL_LDC = "4"; //also used for ldc_w - public static final String CPOOL_LDC2_W = "5"; - public static final String CPOOL_INSTANCEOF = "6"; - public static final String CPOOL_INVOKEDYNAMIC = "7"; + public static final String CPOOL_ANEWARRAY = "0"; + public static final String CPOOL_CHECKCAST = "1"; + public static final String CPOOL_GETFIELD = "2"; + public static final String CPOOL_GETSTATIC = "3"; + public static final String CPOOL_LDC = "4"; //also used for ldc_w + public static final String CPOOL_LDC2_W = "5"; + public static final String CPOOL_INSTANCEOF = "6"; + public static final String CPOOL_INVOKEDYNAMIC = "7"; public static final String CPOOL_INVOKEINTERFACE = "8"; - public static final String CPOOL_INVOKESPECIAL = "9"; - public static final String CPOOL_INVOKESTATIC = "10"; - public static final String CPOOL_INVOKEVIRTUAL = "11"; - public static final String CPOOL_MULTIANEWARRAY = "12"; - public static final String CPOOL_NEW = "13"; - public static final String CPOOL_NEWARRAY = "14"; - public static final String CPOOL_PUTSTATIC = "15"; - public static final String CPOOL_PUTFIELD = "16"; - public static final String CPOOL_ARRAYLENGTH = "17"; + public static final String CPOOL_INVOKESPECIAL = "9"; + public static final String CPOOL_INVOKESTATIC = "10"; + public static final String CPOOL_INVOKEVIRTUAL = "11"; + public static final String CPOOL_MULTIANEWARRAY = "12"; + public static final String CPOOL_NEW = "13"; + public static final String CPOOL_NEWARRAY = "14"; + public static final String CPOOL_PUTSTATIC = "15"; + public static final String CPOOL_PUTFIELD = "16"; + public static final String CPOOL_ARRAYLENGTH = "17"; public ConstantPoolJava(Program program) throws IOException { ClassFileAnalysisState analysisState = ClassFileAnalysisState.getState(program); @@ -58,43 +58,68 @@ public class ConstantPoolJava extends ConstantPool { dtManager = program.getDataTypeManager(); } - private void fillinMethod(int name_and_type_index, Record res,JavaInvocationType methodType) { - ConstantPoolNameAndTypeInfo methodNameAndType = (ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index]; + private void fillinMethod(int index, int name_and_type_index, Record res, + JavaInvocationType methodType) { + ConstantPoolNameAndTypeInfo methodNameAndType = + (ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index]; int name_index = methodNameAndType.getNameIndex(); res.tag = ConstantPool.POINTER_METHOD; - res.token = ((ConstantPoolUtf8Info)constantPool[name_index]).getString(); + + if (methodType.equals(JavaInvocationType.INVOKE_STATIC)) { + AbstractConstantPoolReferenceInfo poolRef = + (AbstractConstantPoolReferenceInfo) constantPool[index]; + ConstantPoolClassInfo classInfo = + (ConstantPoolClassInfo) constantPool[poolRef.getClassIndex()]; + int classNameIndex = classInfo.getNameIndex(); + String fullyQualifiedName = + ((ConstantPoolUtf8Info) constantPool[classNameIndex]).getString(); + String className = getClassName(fullyQualifiedName); + res.token = + className + "." + ((ConstantPoolUtf8Info) constantPool[name_index]).getString(); + } + else { + res.token = ((ConstantPoolUtf8Info) constantPool[name_index]).getString(); + } + int descriptor_index = methodNameAndType.getDescriptorIndex(); ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index]; String descriptor = descriptorInfo.getString(); - FunctionDefinitionDataType funcDef = new FunctionDefinitionDataType(res.token); - res.type = new PointerDataType(funcDef); - DataType returnType = DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor, dtManager); + + String uniqueifier = Integer.toHexString(index); + FunctionDefinitionDataType funcDef = + new FunctionDefinitionDataType(uniqueifier + "_" + res.token); + DataType returnType = + DescriptorDecoder.getReturnTypeOfMethodDescriptor(descriptor, dtManager); funcDef.setReturnType(returnType); List params = DescriptorDecoder.getDataTypeList(descriptor, dtManager); ParameterDefinitionImpl[] paramDefs; //invokestatic and invokedynamic don't have a this pointer on the stack - if (methodType.equals(JavaInvocationType.INVOKE_STATIC) || methodType.equals(JavaInvocationType.INVOKE_DYNAMIC)){ + if (methodType.equals(JavaInvocationType.INVOKE_STATIC) || + methodType.equals(JavaInvocationType.INVOKE_DYNAMIC)) { paramDefs = new ParameterDefinitionImpl[params.size()]; - for (int i = 0, max = params.size(); i < max; ++i){ - ParameterDefinitionImpl currentParam = new ParameterDefinitionImpl("", params.get(i), null); - paramDefs[i]= currentParam; + for (int i = 0, max = params.size(); i < max; ++i) { + ParameterDefinitionImpl currentParam = + new ParameterDefinitionImpl("", params.get(i), null); + paramDefs[i] = currentParam; } res.hasThisPtr = false; } //invokeinterface, invokespecial, and invokevirtual do have a this pointer else { paramDefs = new ParameterDefinitionImpl[params.size() + 1]; - ParameterDefinitionImpl thisParam = new ParameterDefinitionImpl("objectRef", new Pointer32DataType(DataType.VOID), null); + ParameterDefinitionImpl thisParam = new ParameterDefinitionImpl("objectRef", + new Pointer32DataType(DataType.VOID), null); paramDefs[0] = thisParam; - for (int i = 1, max = params.size(); i <= max; ++i){ - ParameterDefinitionImpl currentParam = new ParameterDefinitionImpl("", params.get(i-1), null); - paramDefs[i]= currentParam; + for (int i = 1, max = params.size(); i <= max; ++i) { + ParameterDefinitionImpl currentParam = + new ParameterDefinitionImpl("", params.get(i - 1), null); + paramDefs[i] = currentParam; } res.hasThisPtr = true; } - funcDef.setArguments(paramDefs); + res.type = new PointerDataType(funcDef); } //ref array does not include the first element passed to the cpool operator. @@ -109,38 +134,33 @@ public class ConstantPoolJava extends ConstantPool { * type of the elements of the new array. We use the cpool operator to * look up the string token corresponding to the primitive type. */ - if (op.equals(CPOOL_NEWARRAY)){ + if (op.equals(CPOOL_NEWARRAY)) { res.tag = ConstantPool.POINTER_METHOD; - res.token = ArrayMethods.getPrimitiveArrayToken((int)ref[0]); + res.token = ArrayMethods.getPrimitiveArrayToken((int) ref[0]); DataType elementType = ArrayMethods.getArrayBaseType((int) ref[0], dtManager); res.type = dtManager.getPointer(elementType); return res; } /*arraylength instruction does not reference the constant pool */ - if (op.equals(CPOOL_ARRAYLENGTH)){ + if (op.equals(CPOOL_ARRAYLENGTH)) { res.tag = ConstantPool.ARRAY_LENGTH; res.token = "length"; - res.type = new PointerDataType(DWordDataType.dataType); + res.type = IntegerDataType.dataType; return res; } - AbstractConstantPoolInfoJava poolRef = constantPool[(int)ref[0]]; - short name_and_type_index; - ConstantPoolNameAndTypeInfo fieldNameAndType; - short descriptor_index; - ConstantPoolUtf8Info descriptorInfo; - String descriptor; - StringBuilder sb = null; - String[] parts = null; - switch(op){ + AbstractConstantPoolInfoJava poolRef = constantPool[(int) ref[0]]; + int name_and_type_index; + switch (op) { case CPOOL_ANEWARRAY: case CPOOL_NEW: res.tag = ConstantPool.CLASS_REFERENCE; - int name_index = ((ConstantPoolClassInfo)poolRef).getNameIndex(); - String fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[name_index]).getString(); - parts = fullyQualifiedName.split("/"); - res.token = parts[parts.length-1]; - sb = new StringBuilder(); + int name_index = ((ConstantPoolClassInfo) poolRef).getNameIndex(); + String fullyQualifiedName = + ((ConstantPoolUtf8Info) constantPool[name_index]).getString(); + String[] parts = fullyQualifiedName.split("/"); + res.token = parts[parts.length - 1]; + StringBuilder sb = new StringBuilder(); for (String part : parts) { sb.append(CategoryPath.DELIMITER_CHAR); sb.append(part); @@ -148,12 +168,13 @@ public class ConstantPoolJava extends ConstantPool { DataTypePath dataPath = new DataTypePath(sb.toString(), res.token); res.type = new PointerDataType(dtManager.getDataType(dataPath)); break; - //TODO case CPOOL_CHECKCAST: - res.tag = ConstantPool.CHECK_CAST; - res.token = "checkcast"; - setTypeNameInfo(poolRef,res); - break; + setTypeNameInfo(poolRef, res); + res.tag = ConstantPool.CHECK_CAST; + PointerDataType pointerType = (PointerDataType) res.type; + String typeName = pointerType.getDataType().getDisplayName(); + res.token = "checkcast(" + typeName + ")"; + break; case CPOOL_INSTANCEOF: res.tag = ConstantPool.INSTANCE_OF; res.token = "instanceof"; @@ -161,154 +182,159 @@ public class ConstantPoolJava extends ConstantPool { break; case CPOOL_GETFIELD: case CPOOL_PUTFIELD: - name_and_type_index = ((ConstantPoolFieldReferenceInfo)poolRef).getNameAndTypeIndex(); - fieldNameAndType = (ConstantPoolNameAndTypeInfo)constantPool[name_and_type_index]; - name_index = fieldNameAndType.getNameIndex(); - res.tag = ConstantPool.POINTER_FIELD; - res.token = ((ConstantPoolUtf8Info)constantPool[name_index]).getString(); - descriptor_index = fieldNameAndType.getDescriptorIndex(); - descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index]; - descriptor = descriptorInfo.getString(); - DataType type = DescriptorDecoder.getDataTypeOfDescriptor(descriptor, dtManager); - res.type = new PointerDataType(type); - break; - //for references to static fields, we want the class name to be part of the token case CPOOL_GETSTATIC: case CPOOL_PUTSTATIC: - name_and_type_index = ((ConstantPoolFieldReferenceInfo)poolRef).getNameAndTypeIndex(); - int class_index = ((ConstantPoolFieldReferenceInfo)poolRef).getClassIndex(); - fieldNameAndType = (ConstantPoolNameAndTypeInfo)constantPool[name_and_type_index]; - name_index = fieldNameAndType.getNameIndex(); - ConstantPoolClassInfo classInfo = (ConstantPoolClassInfo)constantPool[class_index]; - int classNameIndex = classInfo.getNameIndex(); - fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[classNameIndex]).getString(); - res.tag = ConstantPool.POINTER_FIELD; - String className = getClassName(fullyQualifiedName); - res.token = className + "." + ((ConstantPoolUtf8Info)constantPool[name_index]).getString(); - descriptor_index = fieldNameAndType.getDescriptorIndex(); - descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index]; - descriptor = descriptorInfo.getString(); - type = DescriptorDecoder.getDataTypeOfDescriptor(descriptor, dtManager); - res.type = new PointerDataType(type); - //res.type = type; + handlePutAndGetOps(poolRef, res, op); break; case CPOOL_INVOKEDYNAMIC: - name_and_type_index = ((ConstantPoolInvokeDynamicInfo)poolRef).getNameAndTypeIndex(); - fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_DYNAMIC); + name_and_type_index = + ((ConstantPoolInvokeDynamicInfo) poolRef).getNameAndTypeIndex(); + + fillinMethod((int) ref[0], name_and_type_index, res, + JavaInvocationType.INVOKE_DYNAMIC); break; case CPOOL_INVOKEINTERFACE: - name_and_type_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getNameAndTypeIndex(); - fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_INTERFACE); + name_and_type_index = + ((ConstantPoolInterfaceMethodReferenceInfo) poolRef).getNameAndTypeIndex(); + fillinMethod((int) ref[0], name_and_type_index, res, + JavaInvocationType.INVOKE_INTERFACE); break; case CPOOL_INVOKESPECIAL: - if (poolRef instanceof ConstantPoolMethodReferenceInfo) { - name_and_type_index = ((ConstantPoolMethodReferenceInfo)poolRef).getNameAndTypeIndex(); - } - else{ - name_and_type_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getNameAndTypeIndex(); - } - fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_SPECIAL); - + AbstractConstantPoolReferenceInfo refInfo = + (AbstractConstantPoolReferenceInfo) poolRef; + name_and_type_index = refInfo.getNameAndTypeIndex(); + fillinMethod((int) ref[0], name_and_type_index, res, + JavaInvocationType.INVOKE_SPECIAL); break; case CPOOL_INVOKESTATIC: - if (poolRef instanceof ConstantPoolMethodReferenceInfo) { - name_and_type_index = ((ConstantPoolMethodReferenceInfo)poolRef).getNameAndTypeIndex(); - class_index = ((ConstantPoolMethodReferenceInfo)poolRef).getClassIndex(); - - } - else{ - name_and_type_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getNameAndTypeIndex(); - class_index = ((ConstantPoolInterfaceMethodReferenceInfo)poolRef).getClassIndex(); - } - classInfo = (ConstantPoolClassInfo)constantPool[class_index]; - classNameIndex = classInfo.getNameIndex(); - fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[classNameIndex]).getString(); - className = getClassName(fullyQualifiedName); - fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_STATIC); - res.token = className + "." + res.token; + refInfo = (AbstractConstantPoolReferenceInfo) poolRef; + name_and_type_index = refInfo.getNameAndTypeIndex(); + fillinMethod((int) ref[0], name_and_type_index, res, + JavaInvocationType.INVOKE_STATIC); break; case CPOOL_INVOKEVIRTUAL: - name_and_type_index = ((ConstantPoolMethodReferenceInfo)poolRef).getNameAndTypeIndex(); - fillinMethod(name_and_type_index,res,JavaInvocationType.INVOKE_VIRTUAL); + name_and_type_index = + ((ConstantPoolMethodReferenceInfo) poolRef).getNameAndTypeIndex(); + fillinMethod((int) ref[0], name_and_type_index, res, + JavaInvocationType.INVOKE_VIRTUAL); break; - //in this case, the constant pool entry can be a reference to: - //int, float, string literal, or a symbolic reference to a class, - //method type, or method handle + + //in this case, the constant pool entry can be a reference to: + //int, float, string literal, or a symbolic reference to a class, + //method type, or method handle case CPOOL_LDC: if (poolRef instanceof ConstantPoolIntegerInfo) { res.tag = ConstantPool.PRIMITIVE; res.token = "int"; - res.value = ((ConstantPoolIntegerInfo)poolRef).getValue(); + res.value = ((ConstantPoolIntegerInfo) poolRef).getValue(); res.type = IntegerDataType.dataType; } else if (poolRef instanceof ConstantPoolFloatInfo) { res.tag = ConstantPool.PRIMITIVE; res.token = "float"; - res.value = ((ConstantPoolFloatInfo)poolRef).getRawBytes() & 0xffffffffL; + res.value = ((ConstantPoolFloatInfo) poolRef).getRawBytes() & 0xffffffffL; res.type = FloatDataType.dataType; } else if (poolRef instanceof ConstantPoolStringInfo) { - int string_index = ((ConstantPoolStringInfo)poolRef).getStringIndex(); + int string_index = ((ConstantPoolStringInfo) poolRef).getStringIndex(); res.tag = ConstantPool.STRING_LITERAL; res.byteData = ((ConstantPoolUtf8Info) constantPool[string_index]).getBytes(); - res.type = DescriptorDecoder.getReferenceTypeOfDescriptor("java/lang/String", dtManager, false); + res.type = DescriptorDecoder.getReferenceTypeOfDescriptor("java/lang/String", + dtManager, false); } - else if (poolRef instanceof ConstantPoolClassInfo){ + else if (poolRef instanceof ConstantPoolClassInfo) { res.tag = ConstantPool.CLASS_REFERENCE; - name_index = ((ConstantPoolClassInfo)poolRef).getNameIndex(); - fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[name_index]).getString(); - className = getClassName(fullyQualifiedName); - res.token = className + ".class"; - res.type = DescriptorDecoder.getReferenceTypeOfDescriptor(fullyQualifiedName, dtManager, false); + name_index = ((ConstantPoolClassInfo) poolRef).getNameIndex(); + fullyQualifiedName = + ((ConstantPoolUtf8Info) constantPool[name_index]).getString(); + String className = getClassName(fullyQualifiedName); + res.token = className + ".class"; + res.type = DescriptorDecoder.getReferenceTypeOfDescriptor(fullyQualifiedName, + dtManager, false); } - //standard java compilers don't seem to emit the following two - else if (poolRef instanceof ConstantPoolMethodTypeInfo){ + else if (poolRef instanceof ConstantPoolMethodTypeInfo) { res.tag = ConstantPool.POINTER_METHOD; - name_index = ((ConstantPoolMethodTypeInfo)poolRef).getDescriptorIndex(); - res.token = ((ConstantPoolUtf8Info)constantPool[name_index]).getString(); + name_index = ((ConstantPoolMethodTypeInfo) poolRef).getDescriptorIndex(); + res.token = ((ConstantPoolUtf8Info) constantPool[name_index]).getString(); res.type = dtManager.getPointer(DWordDataType.dataType); } //TODO set the token? - else if (poolRef instanceof ConstantPoolMethodHandleInfo){ + else if (poolRef instanceof ConstantPoolMethodHandleInfo) { res.tag = ConstantPool.POINTER_METHOD; res.type = dtManager.getPointer(DWordDataType.dataType); } break; - //must be a constant of type long or double - //according to JVM spec + //must be a constant of type long or double + //according to JVM spec case CPOOL_LDC2_W: if (poolRef instanceof ConstantPoolLongInfo) { res.tag = ConstantPool.PRIMITIVE; res.token = "long"; - res.value = ((ConstantPoolLongInfo)poolRef).getValue(); + res.value = ((ConstantPoolLongInfo) poolRef).getValue(); res.type = LongDataType.dataType; } else { res.tag = ConstantPool.PRIMITIVE; res.token = "double"; - res.value = ((ConstantPoolDoubleInfo)poolRef).getRawBytes(); + res.value = ((ConstantPoolDoubleInfo) poolRef).getRawBytes(); res.type = DoubleDataType.dataType; } break; case CPOOL_MULTIANEWARRAY: - res.tag = ConstantPool.POINTER_METHOD; + res.tag = ConstantPool.CLASS_REFERENCE; res.type = new PointerDataType(DataType.VOID); int nameIndex = ((ConstantPoolClassInfo) poolRef).getNameIndex(); ConstantPoolUtf8Info utf8Info = (ConstantPoolUtf8Info) constantPool[nameIndex]; String classNameWithSemicolon = utf8Info.getString(); - res.token = DescriptorDecoder.getTypeNameFromDescriptor(classNameWithSemicolon, false, false); + res.token = DescriptorDecoder.getTypeNameFromDescriptor(classNameWithSemicolon, + false, false); default: break; } return res; } + private void handlePutAndGetOps(AbstractConstantPoolInfoJava poolRef, Record res, String op) { + + int name_and_type_index = ((ConstantPoolFieldReferenceInfo) poolRef).getNameAndTypeIndex(); + ConstantPoolNameAndTypeInfo fieldNameAndType = + (ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index]; + int name_index = fieldNameAndType.getNameIndex(); + switch (op) { + case CPOOL_GETFIELD: + case CPOOL_PUTFIELD: + res.token = ((ConstantPoolUtf8Info) constantPool[name_index]).getString(); + break; + case CPOOL_GETSTATIC: + case CPOOL_PUTSTATIC: + int class_index = ((ConstantPoolFieldReferenceInfo) poolRef).getClassIndex(); + ConstantPoolClassInfo classInfo = (ConstantPoolClassInfo) constantPool[class_index]; + int classNameIndex = classInfo.getNameIndex(); + String fullyQualifiedName = + ((ConstantPoolUtf8Info) constantPool[classNameIndex]).getString(); + String className = getClassName(fullyQualifiedName); + res.token = + className + "." + ((ConstantPoolUtf8Info) constantPool[name_index]).getString(); + break; + default: + throw new IllegalArgumentException("Invalid op: " + op); + } + + res.tag = ConstantPool.POINTER_FIELD; + + int descriptor_index = fieldNameAndType.getDescriptorIndex(); + ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index]; + String descriptor = descriptorInfo.getString(); + DataType type = DescriptorDecoder.getDataTypeOfDescriptor(descriptor, dtManager); + res.type = new PointerDataType(type); + } + private void setTypeNameInfo(AbstractConstantPoolInfoJava poolRef, Record res) { - int name_index = ((ConstantPoolClassInfo)poolRef).getNameIndex(); - String fullyQualifiedName = ((ConstantPoolUtf8Info)constantPool[name_index]).getString(); + int name_index = ((ConstantPoolClassInfo) poolRef).getNameIndex(); + String fullyQualifiedName = ((ConstantPoolUtf8Info) constantPool[name_index]).getString(); String[] parts = null; StringBuilder sb = null; - if (fullyQualifiedName.startsWith("[")){ + if (fullyQualifiedName.startsWith("[")) { //TODO: how to get instanceof X to display, where X is an array type? //need to decide how to handle multidimensional arrays //remove the brackets @@ -318,7 +344,7 @@ public class ConstantPoolJava extends ConstantPool { for (String part : parts) { sb.append(CategoryPath.DELIMITER_CHAR); sb.append(part); - } + } } else { parts = fullyQualifiedName.split("/"); @@ -328,17 +354,17 @@ public class ConstantPoolJava extends ConstantPool { sb.append(part); } } - DataTypePath dataPath = new DataTypePath(sb.toString(), parts[parts.length-1]); + DataTypePath dataPath = new DataTypePath(sb.toString(), parts[parts.length - 1]); res.type = new PointerDataType(dtManager.getDataType(dataPath)); - + } - private String getClassName(String fullyQualifiedName){ + private String getClassName(String fullyQualifiedName) { int lastSlash = fullyQualifiedName.lastIndexOf("/"); - return fullyQualifiedName.substring(lastSlash+1, fullyQualifiedName.length()); + return fullyQualifiedName.substring(lastSlash + 1, fullyQualifiedName.length()); } - public AbstractConstantPoolInfoJava[] getConstantPool(){ + public AbstractConstantPoolInfoJava[] getConstantPool() { return constantPool; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InjectInvokeDynamic.java b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InjectInvokeDynamic.java index 93c4981175..784d614f72 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InjectInvokeDynamic.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InjectInvokeDynamic.java @@ -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; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InjectLookupSwitch.java b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InjectLookupSwitch.java deleted file mode 100644 index 65059e2e56..0000000000 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InjectLookupSwitch.java +++ /dev/null @@ -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; - } - -} diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InvokeMethods.java b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InvokeMethods.java index 9df5202848..5adc94b485 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InvokeMethods.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/InvokeMethods.java @@ -38,7 +38,7 @@ public class InvokeMethods { static final String PARAM_SPACE = "parameterSpace"; //private constructor to enforce noninstantiability - private InvokeMethods(){ + private InvokeMethods() { throw new AssertionError(); } @@ -50,24 +50,28 @@ public class InvokeMethods { * @param type - the JavaInvocationType of the invocation * @return - the pcode as a string */ - - public static String getPcodeForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) { + public static String getPcodeForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool, + JavaInvocationType type) { StringBuilder pCode = new StringBuilder(); - String descriptor = DescriptorDecoder.getDescriptorForInvoke(offset, constantPool, type); - List categories = DescriptorDecoder.getParameterCategories(descriptor); - boolean includeThisPointer = type.equals(JavaInvocationType.INVOKE_VIRTUAL) || type.equals(JavaInvocationType.INVOKE_SPECIAL) || type.equals(JavaInvocationType.INVOKE_INTERFACE); - + String descriptor = DescriptorDecoder.getDescriptorForInvoke(offset, constantPool, type); + List categories = + DescriptorDecoder.getParameterCategories(descriptor); + boolean includeThisPointer = type.equals(JavaInvocationType.INVOKE_VIRTUAL) || + type.equals(JavaInvocationType.INVOKE_SPECIAL) || + type.equals(JavaInvocationType.INVOKE_INTERFACE); + int stackPurge = DescriptorDecoder.getStackPurge(descriptor); - if (includeThisPointer){ + if (includeThisPointer) { stackPurge += 4; } emitPcodeToMoveParams(pCode, categories, includeThisPointer, stackPurge); emitPcodeToResolveMethodReference(pCode, offset, constantPool, type); PcodeTextEmitter.emitIndirectCall(pCode, CALL_TARGET); - - JavaComputationalCategory retType = DescriptorDecoder.getReturnCategoryOfMethodDescriptor(descriptor); - switch (retType){ + + JavaComputationalCategory retType = + DescriptorDecoder.getReturnCategoryOfMethodDescriptor(descriptor); + switch (retType) { case CAT_1: PcodeTextEmitter.emitPushCat1Value(pCode, CAT_1_RETURN); break; @@ -80,6 +84,42 @@ public class InvokeMethods { return pCode.toString(); } + /** + * Emits the pcode for an invoke instruction. + * @param offset - the index of the constant pool element containing a symbolic reference + * to a method or a call site specifier. + * @param constantPool - the constant pool + * @return - the pcode as a string + */ + public static String getPcodeForInvokeDynamic(int offset, + AbstractConstantPoolInfoJava[] constantPool) { + StringBuilder pCode = new StringBuilder(); + String invokeDynamicDescriptor = DescriptorDecoder.getDescriptorForInvoke(offset, + constantPool, JavaInvocationType.INVOKE_DYNAMIC); + List categories = + DescriptorDecoder.getParameterCategories(invokeDynamicDescriptor); + + int stackPurge = DescriptorDecoder.getStackPurge(invokeDynamicDescriptor); + + emitPcodeToMoveParams(pCode, categories, false, stackPurge); + emitPcodeToResolveMethodReference(pCode, offset, constantPool, + JavaInvocationType.INVOKE_DYNAMIC); + PcodeTextEmitter.emitIndirectCall(pCode, CALL_TARGET); + + JavaComputationalCategory retType = + DescriptorDecoder.getReturnCategoryOfMethodDescriptor(invokeDynamicDescriptor); + switch (retType) { + case CAT_1: + PcodeTextEmitter.emitPushCat1Value(pCode, CAT_1_RETURN); + break; + case CAT_2: + PcodeTextEmitter.emitPushCat2Value(pCode, CAT_2_RETURN); + break; + default: + break; + } + return pCode.toString(); + } /** * Emits pcode to move the parameters from the stack to the space parameterSpace @@ -89,21 +129,26 @@ public class InvokeMethods { * @param categories - the list of computational categories on the top of the stack * @param includeThisPointer - true if the first element on the stack is an implicit this parameter */ - static void emitPcodeToMoveParams(StringBuilder pCode, List categories, boolean includeThisPointer, int totalSize){ - + static void emitPcodeToMoveParams(StringBuilder pCode, + List categories, boolean includeThisPointer, int totalSize) { + //pop the parameters off of the stack - for (int i = categories.size() - 1; i >= 0; --i){ - switch (categories.get(i)){ + for (int i = categories.size() - 1; i >= 0; --i) { + switch (categories.get(i)) { case CAT_1: PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER + Integer.toString(i)); totalSize -= 4; - PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize) + ":4", PARAMETER + Integer.toString(i)); + PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, + Integer.toString(totalSize) + ":4", PARAMETER + Integer.toString(i)); break; case CAT_2: PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER + Integer.toString(i)); - PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize-8) + ":4", PARAMETER + Integer.toString(i)); + PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, + Integer.toString(totalSize - 8) + ":4", PARAMETER + Integer.toString(i)); PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER_PART2 + Integer.toString(i)); - PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize-4) + ":4", PARAMETER_PART2 + Integer.toString(i)); + PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, + Integer.toString(totalSize - 4) + ":4", + PARAMETER_PART2 + Integer.toString(i)); totalSize -= 8; break; default: @@ -111,15 +156,15 @@ public class InvokeMethods { } } //pop off the this pointer if there is one - if (includeThisPointer){ + if (includeThisPointer) { PcodeTextEmitter.emitPopCat1Value(pCode, THIS); totalSize -= 4; - PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, Integer.toString(totalSize) + ":4", THIS); + PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4, + Integer.toString(totalSize) + ":4", THIS); } } - /** * Emits pcode to assign the result of a cpool op to the call_target register for an invocation. * @param pCode - the pcode buffer @@ -127,25 +172,37 @@ public class InvokeMethods { * @param constantPool - the constant pool * @param type - the type of the invocation */ - static void emitPcodeToResolveMethodReference(StringBuilder pCode, int offset, AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type){ - switch (type){ + static void emitPcodeToResolveMethodReference(StringBuilder pCode, int offset, + AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) { + switch (type) { case INVOKE_DYNAMIC: - PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKEDYNAMIC); + PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, + ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset), + ConstantPoolJava.CPOOL_INVOKEDYNAMIC); break; case INVOKE_INTERFACE: - PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKEINTERFACE); + PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, + ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), + ConstantPoolJava.CPOOL_INVOKEINTERFACE); break; case INVOKE_SPECIAL: - PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKESPECIAL); + PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, + ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), + ConstantPoolJava.CPOOL_INVOKESPECIAL); break; case INVOKE_STATIC: - PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKESTATIC); + PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, + ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset), + ConstantPoolJava.CPOOL_INVOKESTATIC); break; case INVOKE_VIRTUAL: - PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), ConstantPoolJava.CPOOL_INVOKEVIRTUAL); + PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET, + ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset), + ConstantPoolJava.CPOOL_INVOKEVIRTUAL); break; default: - throw new IllegalArgumentException("Unimplemented JavaMethodType: " + type.toString()); + throw new IllegalArgumentException( + "Unimplemented JavaMethodType: " + type.toString()); } } } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/PcodeInjectLibraryJava.java b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/PcodeInjectLibraryJava.java index d68398a12d..90b7945452 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/PcodeInjectLibraryJava.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/PcodeInjectLibraryJava.java @@ -79,18 +79,7 @@ import ghidra.program.model.listing.Program; * (Use/add to PcodeTextEmitter.java to actually emit pcode text) * See ConstantPoolJava.java for examples of the use of the CPOOL pcode op. * - * TODO: - * 1) For the lookupswitch op, the disassembly is correct but the decompilation is not. - * There are several possible ways of modeling the instruction in pcode - either using - * injection (SwitchMethods.java) or pcode (JVM.slaspec). In all cases, there seems to - * be an issue with getting the decompiler to follow pointers to the various switch clauses. - * The file LookupSwitchHex.java in the resource directory contains a class file with - * 4 methods with switch statements. Currently the first method is modeled using a - * pcode loop and the last three are modeled using pcode injection (which is possible because - * there are actually 4 separate lookupswitch instructions, the only difference is the amount - * of padding bytes). - * - * possible improvements: + * possible improvements: * * 2) incorporate exceptions. * 6) decide how to display the information used in an invokedynamic instruction @@ -121,7 +110,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary { public static final String LDC = "ldcCallOther"; public static final String LDC2_W = "ldc2_wCallOther"; public static final String LDC_W = "ldc_wCallOther"; - public static final String LOOKUP_SWITCH = "lookupswitchCallOther"; public static final String MULTIANEWARRAY = "multianewarrayCallOther"; public static final String PUTFIELD = "putFieldCallOther"; @@ -149,7 +137,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary { implementedOps.add(LDC); implementedOps.add(LDC2_W); implementedOps.add(LDC_W); - implementedOps.add(LOOKUP_SWITCH); implementedOps.add(MULTIANEWARRAY); implementedOps.add(PUTFIELD); implementedOps.add(PUTSTATIC); @@ -170,8 +157,9 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary { @Override protected InjectPayloadSleigh allocateInject(String sourceName, String name, int tp) { InjectPayloadJava payload = null; - if (tp != InjectPayload.CALLOTHERFIXUP_TYPE) + if (tp != InjectPayload.CALLOTHERFIXUP_TYPE) { return super.allocateInject(sourceName, name, tp); + } switch (name) { case GETFIELD: payload = new InjectGetField(sourceName, language); @@ -199,9 +187,6 @@ public class PcodeInjectLibraryJava extends PcodeInjectLibrary { case LDC_W: payload = new InjectLdc(sourceName, language); break; - case LOOKUP_SWITCH: - payload = new InjectLookupSwitch(sourceName, language); - break; case MULTIANEWARRAY: payload = new InjectMultiANewArray(sourceName, language); break; diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/PcodeTextEmitter.java b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/PcodeTextEmitter.java index 975b57509a..4412f82f65 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/PcodeTextEmitter.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/PcodeTextEmitter.java @@ -15,7 +15,6 @@ */ package ghidra.app.util.pcodeInject; - /** * * This is a utility class containing methods to emit pcode for decompile callbacks occurring during analysis of @@ -27,22 +26,22 @@ package ghidra.app.util.pcodeInject; */ public class PcodeTextEmitter { - static final String RAM = "ram"; + static final String RAM = "ram"; //private constructor to enforce noninstantiability - private PcodeTextEmitter(){ + private PcodeTextEmitter() { throw new AssertionError(); } - + /** * Emits pcode to push a value of computational category 1 onto the stack. * @param pCode - StringBuilder to hold pcode. * @param valueName - name of varnode to push. */ - public static void emitPushCat1Value(StringBuilder pCode, String valueName){ + public static void emitPushCat1Value(StringBuilder pCode, String valueName) { pCode.append("SP = SP - 4;\n*:4 SP = "); pCode.append(valueName); - pCode.append(";\n"); + pCode.append(";\n"); } /** @@ -50,10 +49,10 @@ public class PcodeTextEmitter { * @param pCode - StringBuilder to hold pcode. * @param valueName - name of varnode to push. */ - public static void emitPushCat2Value(StringBuilder pCode, String valueName){ + public static void emitPushCat2Value(StringBuilder pCode, String valueName) { pCode.append("SP = SP - 8;\n*:8 SP = "); pCode.append(valueName); - pCode.append(";\n"); + pCode.append(";\n"); } /** @@ -61,9 +60,9 @@ public class PcodeTextEmitter { * @param pCode - StringBuilder to hold pcode. * @param destName - name of destination varnode. */ - public static void emitPopCat2Value(StringBuilder pCode, String destName){ + public static void emitPopCat2Value(StringBuilder pCode, String destName) { pCode.append(destName); - pCode.append(":8 = *:8 SP;\nSP = SP + 8;\n"); + pCode.append(":8 = *:8 SP;\nSP = SP + 8;\n"); } /** @@ -71,9 +70,9 @@ public class PcodeTextEmitter { * @param pCode - StringBuilder to hold pcode. * @param destName - name of destination varnode. */ - public static void emitPopCat1Value(StringBuilder pCode, String destName){ + public static void emitPopCat1Value(StringBuilder pCode, String destName) { pCode.append(destName); - pCode.append(":4 = *:4 SP;\nSP = SP + 4;\n"); + pCode.append(":4 = *:4 SP;\nSP = SP + 4;\n"); } /** @@ -83,56 +82,55 @@ public class PcodeTextEmitter { * @param pcodeop - name of pcodeop * @param args - zero or more arguments for the pcodeop */ - public static void emitAssignVarnodeFromPcodeOpCall(StringBuilder pCode, String varnodeName, int size, String pcodeop, String... args){ + public static void emitAssignVarnodeFromPcodeOpCall(StringBuilder pCode, String varnodeName, + int size, String pcodeop, String... args) { pCode.append(varnodeName); - pCode.append(":"); + pCode.append(":"); pCode.append(Integer.toString(size)); - pCode.append(" = "); + pCode.append(" = "); pCode.append(pcodeop); pCode.append("("); - for (int i = 0, numArgs = args.length; i < numArgs; ++i){ + for (int i = 0, numArgs = args.length; i < numArgs; ++i) { pCode.append(args[i]); - if (i < numArgs - 1){ + if (i < numArgs - 1) { pCode.append(","); } } pCode.append(");\n"); } - /** * Emits pcode to call a void black-box pcodeop * @param pCode StringBuilder to hold the pcode * @param pcodeop - name of pcodeop * @param args - zero or more arguments for the pcodeop */ - public static void emitVoidPcodeOpCall(StringBuilder pCode, String pcodeop, String... args){ + public static void emitVoidPcodeOpCall(StringBuilder pCode, String pcodeop, String... args) { pCode.append(pcodeop); pCode.append("("); - for (int i = 0, numArgs = args.length; i < numArgs; ++i){ + for (int i = 0, numArgs = args.length; i < numArgs; ++i) { pCode.append(args[i]); - if (i < numArgs - 1){ + if (i < numArgs - 1) { pCode.append(","); } } pCode.append(");\n"); } - /** * Appends the pcode to assign an integer constant to a register * @param pCode * @param constantPool * @param index */ - public static void emitAssignConstantToRegister(StringBuilder pCode, String register, int constant){ + public static void emitAssignConstantToRegister(StringBuilder pCode, String register, + int constant) { pCode.append(register); pCode.append(" = 0x"); pCode.append(Integer.toHexString(constant)); pCode.append(";\n"); } - - + /** * Appends the pcode to assign a register to the result of a pcode op call with arguments args * @param pCode @@ -140,32 +138,42 @@ public class PcodeTextEmitter { * @param pcodeop * @param args */ - public static void emitAssignRegisterFromPcodeOpCall(StringBuilder pCode, String register, String pcodeop, String... args){ + public static void emitAssignRegisterFromPcodeOpCall(StringBuilder pCode, String register, + String pcodeop, String... args) { pCode.append(register); pCode.append(" = "); pCode.append(pcodeop); pCode.append("("); - for (int i = 0, numArgs = args.length; i < numArgs; ++i){ + for (int i = 0, numArgs = args.length; i < numArgs; ++i) { pCode.append(args[i]); - if (i < numArgs - 1){ + if (i < numArgs - 1) { pCode.append(","); } } pCode.append(");\n"); } - + /** * Appends the pcode to emit a label definition. * @param pCode * @param caseName */ - public static void emitLabelDefinition(StringBuilder pCode, String caseName){ + public static void emitLabelDefinition(StringBuilder pCode, String caseName) { pCode.append("<"); pCode.append(caseName); pCode.append(">\n"); } - - public static void emitWriteToMemory(StringBuilder pCode, String space, int size, String offset, String value){ + + /** + * Appends the pcode to write to a value at an offset of a memory space + * @param pCode buffer to append pcode + * @param space name of space + * @param size size of write + * @param offset offset in space + * @param value value to write + */ + public static void emitWriteToMemory(StringBuilder pCode, String space, int size, String offset, + String value) { pCode.append("*["); pCode.append(space); pCode.append("]:"); @@ -177,19 +185,25 @@ public class PcodeTextEmitter { pCode.append(";\n"); } - public static void emitIndirectCall(StringBuilder pCode, String target){ + /** + * Appends the pcode to emit an indirect call + * @param pCode buffer to append to + * @param target varnode to call indirectly + */ + public static void emitIndirectCall(StringBuilder pCode, String target) { pCode.append("call ["); pCode.append(target); pCode.append("];\n"); } - - public static void emitAddToStackPointer(StringBuilder pCode, int amount){ - pCode.append("SP = SP + "); - pCode.append(Integer.toString(amount)); - pCode.append(";\n"); - } - - public static void emitSignExtension(StringBuilder pCode, String dest, int size, String src){ + + /** + * Appends the pcode to sign-extend the value src into dest + * @param pCode buffer to append to + * @param dest target varnode + * @param size size of target varnode + * @param src size of source varnode + */ + public static void emitSignExtension(StringBuilder pCode, String dest, int size, String src) { pCode.append(dest); pCode.append(":"); pCode.append(Integer.toString(size)); @@ -197,8 +211,15 @@ public class PcodeTextEmitter { pCode.append(src); pCode.append(");\n"); } - - public static void emitZeroExtension(StringBuilder pCode, String dest, int size, String src){ + + /** + * Appends the pcode to zero-extend the value src into dest + * @param pCode buffer to append to + * @param dest target varnode + * @param size size of target varnode + * @param src size of source varnode + */ + public static void emitZeroExtension(StringBuilder pCode, String dest, int size, String src) { pCode.append(dest); pCode.append(":"); pCode.append(Integer.toString(size)); @@ -206,8 +227,15 @@ public class PcodeTextEmitter { pCode.append(src); pCode.append(");\n"); } - - public static void emitTruncate(StringBuilder pCode, String dest, int size, String src){ + + /** + * Appends the pcode truncate src into dest + * @param pCode buffer to append to + * @param dest target varnode + * @param size size of target varnode + * @param src size of source varnode + */ + public static void emitTruncate(StringBuilder pCode, String dest, int size, String src) { pCode.append(dest); pCode.append(" = "); pCode.append(src); @@ -215,6 +243,25 @@ public class PcodeTextEmitter { pCode.append(Integer.toString(size)); pCode.append(";\n"); } - - + + /** + * Appends the pcode to assign a varnode from a dereference of another varnode + * @param pCode buffer to append to + * @param lhs target varnode + * @param size size of pointed-to value + * @param rhs varnode to dereference + */ + public static void emitAssignVarnodeFromDereference(StringBuilder pCode, String lhs, int size, + String rhs) { + pCode.append(lhs); + pCode.append(":"); + pCode.append(Integer.toString(size)); + pCode.append(" = "); + pCode.append("*:"); + pCode.append(Integer.toString(size)); + pCode.append(" "); + pCode.append(rhs); + pCode.append(";\n"); + } + } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ReferenceMethods.java b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ReferenceMethods.java index a4102c8550..963b678cb1 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ReferenceMethods.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/ReferenceMethods.java @@ -16,10 +16,7 @@ package ghidra.app.util.pcodeInject; import ghidra.javaclass.format.DescriptorDecoder; -import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava; -import ghidra.javaclass.format.constantpool.ConstantPoolFieldReferenceInfo; -import ghidra.javaclass.format.constantpool.ConstantPoolNameAndTypeInfo; -import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info; +import ghidra.javaclass.format.constantpool.*; /** * @@ -37,14 +34,15 @@ import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info; public class ReferenceMethods { static final String VALUE = "value"; - static final String TEMP = "temp"; + static final String TEMP_1 = "temp_1"; + static final String TEMP_2 = "temp_2"; static final String NEW_VALUE = "newValue"; static final String OBJECT_REF = "objectRef"; static final String FIELD_OFFSET = "fieldOffset"; static final String STATIC_OFFSET = "staticOffset"; //private constructor to enforce noninstantiability - private ReferenceMethods(){ + private ReferenceMethods() { throw new AssertionError(); } @@ -54,44 +52,63 @@ public class ReferenceMethods { * @param constantPool - the constant pool of the class file * @return - the pcode string */ - public static String getPcodeForGetStatic(int index, AbstractConstantPoolInfoJava[] constantPool) { + public static String getPcodeForGetStatic(int index, + AbstractConstantPoolInfoJava[] constantPool) { StringBuilder pCode = new StringBuilder(); //determine the computational category and push a value of the correct size onto the operand stack String descriptor = getDescriptorForFieldRef(constantPool, index); - - switch (descriptor.charAt(0)){ + + switch (descriptor.charAt(0)) { case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC); - PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP); - PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); - break; + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1, + ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), + ConstantPoolJava.CPOOL_GETSTATIC); + PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1); + PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2); + PcodeTextEmitter.emitPushCat1Value(pCode, VALUE); + break; case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC); - PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP); - PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1, + ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), + ConstantPoolJava.CPOOL_GETSTATIC); + PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1); + PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2); + PcodeTextEmitter.emitPushCat1Value(pCode, VALUE); break; case DescriptorDecoder.BASE_TYPE_CHAR: //char - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC); - PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP); - PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2, + ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), + ConstantPoolJava.CPOOL_GETSTATIC); + PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1); + PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2); + PcodeTextEmitter.emitPushCat1Value(pCode, VALUE); break; case DescriptorDecoder.BASE_TYPE_SHORT: //signed short - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC); - PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP); - PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); - break; + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2, + ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), + ConstantPoolJava.CPOOL_GETSTATIC); + PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1); + PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2); + PcodeTextEmitter.emitPushCat1Value(pCode, VALUE); + break; case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension case DescriptorDecoder.BASE_TYPE_FLOAT: //float case DescriptorDecoder.BASE_TYPE_INT: //int case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC); - PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 4, + ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), + ConstantPoolJava.CPOOL_GETSTATIC); + PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 4, TEMP_1); + PcodeTextEmitter.emitPushCat1Value(pCode, VALUE); break; case DescriptorDecoder.BASE_TYPE_DOUBLE: //double case DescriptorDecoder.BASE_TYPE_LONG: //long - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 8, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_GETSTATIC); - PcodeTextEmitter.emitPushCat2Value(pCode,VALUE); - break; + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 8, + ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), + ConstantPoolJava.CPOOL_GETSTATIC); + PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 8, TEMP_1); + PcodeTextEmitter.emitPushCat2Value(pCode, VALUE); + break; default: throw new IllegalArgumentException("Invalid descriptor: " + descriptor); } @@ -104,49 +121,68 @@ public class ReferenceMethods { * @param constantPool - the constant pool of the class file * @return - the pcode string */ - public static String getPcodeForPutStatic(int index, AbstractConstantPoolInfoJava[] constantPool){ + public static String getPcodeForPutStatic(int index, + AbstractConstantPoolInfoJava[] constantPool) { StringBuilder pCode = new StringBuilder(); String descriptor = getDescriptorForFieldRef(constantPool, index); - - switch (descriptor.charAt(0)){ + + switch (descriptor.charAt(0)) { case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC); - PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE); - PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET, TEMP); - break; + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, + ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), + ConstantPoolJava.CPOOL_PUTSTATIC); + PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE); + PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET, + TEMP_1); + break; case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC); - PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE); - PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET, TEMP); + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, + ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), + ConstantPoolJava.CPOOL_PUTSTATIC); + PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE); + PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, STATIC_OFFSET, + TEMP_1); break; case DescriptorDecoder.BASE_TYPE_CHAR: //char PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC); - PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE); - PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET, TEMP); + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, + ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), + ConstantPoolJava.CPOOL_PUTSTATIC); + PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE); + PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET, + TEMP_1); break; case DescriptorDecoder.BASE_TYPE_SHORT: //signed short PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC); - PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE); - PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET, TEMP); - break; + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, + ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), + ConstantPoolJava.CPOOL_PUTSTATIC); + PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE); + PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, STATIC_OFFSET, + TEMP_1); + break; case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension case DescriptorDecoder.BASE_TYPE_FLOAT: //float case DescriptorDecoder.BASE_TYPE_INT: //int case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC); - PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, STATIC_OFFSET, NEW_VALUE); + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, + ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), + ConstantPoolJava.CPOOL_PUTSTATIC); + PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, STATIC_OFFSET, + NEW_VALUE); break; case DescriptorDecoder.BASE_TYPE_DOUBLE: //double case DescriptorDecoder.BASE_TYPE_LONG: //long PcodeTextEmitter.emitPopCat2Value(pCode, NEW_VALUE); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), ConstantPoolJava.CPOOL_PUTSTATIC); - PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, STATIC_OFFSET, NEW_VALUE); - break; + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, STATIC_OFFSET, 4, + ConstantPoolJava.CPOOL_OP, "0", Integer.toString(index), + ConstantPoolJava.CPOOL_PUTSTATIC); + PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, STATIC_OFFSET, + NEW_VALUE); + break; default: throw new IllegalArgumentException("Invalid descriptor: " + descriptor); } @@ -159,50 +195,69 @@ public class ReferenceMethods { * @param constantPool * @return - the pcode string */ - public static String getPcodeForGetField(int index, AbstractConstantPoolInfoJava[] constantPool) { + public static String getPcodeForGetField(int index, + AbstractConstantPoolInfoJava[] constantPool) { StringBuilder pCode = new StringBuilder(); String descriptor = getDescriptorForFieldRef(constantPool, index); - - switch (descriptor.charAt(0)){ + + switch (descriptor.charAt(0)) { case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD); - PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP); - PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); - break; + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1, + ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), + ConstantPoolJava.CPOOL_GETFIELD); + PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1); + PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2); + PcodeTextEmitter.emitPushCat1Value(pCode, VALUE); + break; case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 1, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD); - PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP); - PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 1, + ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), + ConstantPoolJava.CPOOL_GETFIELD); + PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 1, TEMP_1); + PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2); + PcodeTextEmitter.emitPushCat1Value(pCode, VALUE); break; case DescriptorDecoder.BASE_TYPE_CHAR: //char PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD); - PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP); - PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2, + ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), + ConstantPoolJava.CPOOL_GETFIELD); + PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1); + PcodeTextEmitter.emitZeroExtension(pCode, VALUE, 4, TEMP_2); + PcodeTextEmitter.emitPushCat1Value(pCode, VALUE); break; case DescriptorDecoder.BASE_TYPE_SHORT: //signed short PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP, 2, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD); - PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP); - PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 2, + ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), + ConstantPoolJava.CPOOL_GETFIELD); + PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, TEMP_2, 2, TEMP_1); + PcodeTextEmitter.emitSignExtension(pCode, VALUE, 4, TEMP_2); + PcodeTextEmitter.emitPushCat1Value(pCode, VALUE); break; case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension case DescriptorDecoder.BASE_TYPE_FLOAT: //float case DescriptorDecoder.BASE_TYPE_INT: //int case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD); - PcodeTextEmitter.emitPushCat1Value(pCode,VALUE); + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 4, + ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), + ConstantPoolJava.CPOOL_GETFIELD); + PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 4, TEMP_1); + PcodeTextEmitter.emitPushCat1Value(pCode, VALUE); break; case DescriptorDecoder.BASE_TYPE_DOUBLE: //double case DescriptorDecoder.BASE_TYPE_LONG: //long PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, VALUE, 8, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_GETFIELD); - PcodeTextEmitter.emitPushCat2Value(pCode,VALUE); - break; + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, TEMP_1, 8, + ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), + ConstantPoolJava.CPOOL_GETFIELD); + PcodeTextEmitter.emitAssignVarnodeFromDereference(pCode, VALUE, 8, TEMP_1); + PcodeTextEmitter.emitPushCat2Value(pCode, VALUE); + break; default: throw new IllegalArgumentException("Invalid descriptor: " + descriptor); } @@ -215,64 +270,81 @@ public class ReferenceMethods { * @param constantPool - the constant pool * @return - the pcode */ - public static String getPcodeForPutField(int index, AbstractConstantPoolInfoJava[] constantPool) { + public static String getPcodeForPutField(int index, + AbstractConstantPoolInfoJava[] constantPool) { StringBuilder pCode = new StringBuilder(); //determine the computational category and push a value of the correct size onto the operand stack String descriptor = getDescriptorForFieldRef(constantPool, index); - - - switch (descriptor.charAt(0)){ + + switch (descriptor.charAt(0)) { case DescriptorDecoder.BASE_TYPE_BYTE: //signed byte PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD); - PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE); - PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET, TEMP); - break; + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, + ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), + ConstantPoolJava.CPOOL_PUTFIELD); + PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE); + PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET, + TEMP_1); + break; case DescriptorDecoder.BASE_TYPE_BOOLEAN: //boolean PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD); - PcodeTextEmitter.emitTruncate(pCode, TEMP, 1, NEW_VALUE); - PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET, TEMP); + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, + ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), + ConstantPoolJava.CPOOL_PUTFIELD); + PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 1, NEW_VALUE); + PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 1, FIELD_OFFSET, + TEMP_1); break; case DescriptorDecoder.BASE_TYPE_CHAR: //char PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD); - PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE); - PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET, TEMP); + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, + ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), + ConstantPoolJava.CPOOL_PUTFIELD); + PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE); + PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET, + TEMP_1); break; case DescriptorDecoder.BASE_TYPE_SHORT: //signed short PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD); - PcodeTextEmitter.emitTruncate(pCode, TEMP, 2, NEW_VALUE); - PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET, TEMP); - break; + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, + ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), + ConstantPoolJava.CPOOL_PUTFIELD); + PcodeTextEmitter.emitTruncate(pCode, TEMP_1, 2, NEW_VALUE); + PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 2, FIELD_OFFSET, + TEMP_1); + break; case DescriptorDecoder.BASE_TYPE_ARRAY: //array dimension case DescriptorDecoder.BASE_TYPE_FLOAT: //float case DescriptorDecoder.BASE_TYPE_INT: //int case DescriptorDecoder.BASE_TYPE_REFERENCE: //object reference PcodeTextEmitter.emitPopCat1Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD); - PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, FIELD_OFFSET, NEW_VALUE); + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, + ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), + ConstantPoolJava.CPOOL_PUTFIELD); + PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 4, FIELD_OFFSET, + NEW_VALUE); break; case DescriptorDecoder.BASE_TYPE_DOUBLE: //double case DescriptorDecoder.BASE_TYPE_LONG: //long PcodeTextEmitter.emitPopCat2Value(pCode, NEW_VALUE); PcodeTextEmitter.emitPopCat1Value(pCode, OBJECT_REF); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), ConstantPoolJava.CPOOL_PUTFIELD); - PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, FIELD_OFFSET, NEW_VALUE); - break; + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, FIELD_OFFSET, 4, + ConstantPoolJava.CPOOL_OP, OBJECT_REF, Integer.toString(index), + ConstantPoolJava.CPOOL_PUTFIELD); + PcodeTextEmitter.emitWriteToMemory(pCode, PcodeTextEmitter.RAM, 8, FIELD_OFFSET, + NEW_VALUE); + break; default: throw new IllegalArgumentException("Invalid descriptor: " + descriptor); } return pCode.toString(); - - + /*JavaComputationalCategory category = DescriptorDecoder.getComputationalCategoryOfDescriptor(descriptor); switch (category){ case CAT_1: @@ -295,21 +367,21 @@ public class ReferenceMethods { return pCode.toString();*/ } - /** * Returns the descriptor of a field reference in the constant pool * @param constantPool * @param index * @return */ - static String getDescriptorForFieldRef(AbstractConstantPoolInfoJava[] constantPool, int index){ - ConstantPoolFieldReferenceInfo fieldRef = (ConstantPoolFieldReferenceInfo) constantPool[index]; + static String getDescriptorForFieldRef(AbstractConstantPoolInfoJava[] constantPool, int index) { + ConstantPoolFieldReferenceInfo fieldRef = + (ConstantPoolFieldReferenceInfo) constantPool[index]; int nameAndTypeIndex = fieldRef.getNameAndTypeIndex(); - ConstantPoolNameAndTypeInfo nameAndTypeInfo = (ConstantPoolNameAndTypeInfo) constantPool[nameAndTypeIndex]; - ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()]; - return descriptorInfo.getString(); + ConstantPoolNameAndTypeInfo nameAndTypeInfo = + (ConstantPoolNameAndTypeInfo) constantPool[nameAndTypeIndex]; + ConstantPoolUtf8Info descriptorInfo = + (ConstantPoolUtf8Info) constantPool[nameAndTypeInfo.getDescriptorIndex()]; + return descriptorInfo.getString(); } - - } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/SwitchMethods.java b/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/SwitchMethods.java deleted file mode 100644 index 0e489db6f1..0000000000 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/app/util/pcodeInject/SwitchMethods.java +++ /dev/null @@ -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 ;\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(); - } -} - diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/analyzers/JavaAnalyzer.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/analyzers/JavaAnalyzer.java index 9a46abfc58..52e6a1c05e 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/analyzers/JavaAnalyzer.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/analyzers/JavaAnalyzer.java @@ -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 indexMap) { AbstractAttributeInfo[] attributes = classFile.getAttributes(); for (AbstractAttributeInfo attribute : attributes) { - short nameIndex = attribute.getAttributeNameIndex(); + int nameIndex = attribute.getAttributeNameIndex(); AbstractConstantPoolInfoJava poolEntry = classFile.getConstantPool()[nameIndex]; if (poolEntry instanceof ConstantPoolUtf8Info) { String name = ((ConstantPoolUtf8Info) poolEntry).getString(); @@ -388,24 +406,179 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker return indexMap; } - private void labelOperands(Program program, ClassFileJava classFile) { - InstructionIterator instructionIt = - program.getListing().getInstructions(toAddr(program, 0x10000), true); - while (instructionIt.hasNext()) { - Instruction instruction = instructionIt.next(); + private void processInstructions(Program program, Data constantPoolData, + ClassFileJava classFile, TaskMonitor monitor) throws CancelledException { - Scalar opValue = instruction.getScalar(0); - if (opValue == null) { + InstructionIterator instructionIt = + program.getListing().getInstructions(toAddr(program, JavaLoader.CODE_OFFSET), true); + AbstractConstantPoolInfoJava[] constantPool = classFile.getConstantPool(); + Map 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 indexMap, + BootstrapMethods[] bootstrapMethods, Instruction instruction) { + StringBuffer sb = new StringBuffer("Bootstrap Method: \n"); + + Address addr = instruction.getAddress(); + int index = (int) (instruction.getScalar(0).getValue() & 0xFFFFFFFF); + ConstantPoolInvokeDynamicInfo dynamicInfo = + (ConstantPoolInvokeDynamicInfo) constantPool[index]; + int bootstrapIndex = dynamicInfo.getBootstrapMethodAttrIndex(); + appendMethodHandleInfo(sb, constantPool, + bootstrapMethods[bootstrapIndex].getBootstrapMethodsReference()); + + sb.append("\n"); + + int argNum = 0; + for (int i = 0; i < bootstrapMethods[bootstrapIndex].getNumberOfBootstrapArguments(); i++) { + sb.append(" static arg " + argNum++ + ": "); + appendLoadableInfo(sb, constantPool, + bootstrapMethods[bootstrapIndex].getBootstrapArgumentsEntry(i)); + if (argNum < bootstrapMethods[bootstrapIndex].getNumberOfBootstrapArguments()) { + sb.append("\n"); + } + } + program.getListing().setComment(addr, CodeUnit.PLATE_COMMENT, sb.toString()); + } + + private void appendMethodHandleInfo(StringBuffer sb, + AbstractConstantPoolInfoJava[] constantPool, int argIndex) { + ConstantPoolMethodHandleInfo methodHandle = + (ConstantPoolMethodHandleInfo) constantPool[argIndex]; + AbstractConstantPoolInfoJava handleRef = constantPool[methodHandle.getReferenceIndex()]; + + if (handleRef instanceof ConstantPoolFieldReferenceInfo) { + ConstantPoolFieldReferenceInfo fieldRef = (ConstantPoolFieldReferenceInfo) handleRef; + ConstantPoolClassInfo classInfo = + (ConstantPoolClassInfo) constantPool[fieldRef.getClassIndex()]; + ConstantPoolUtf8Info utf8 = + (ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()]; + sb.append(utf8.getString()); + sb.append("."); + ConstantPoolNameAndTypeInfo ntInfo = + (ConstantPoolNameAndTypeInfo) constantPool[fieldRef.getNameAndTypeIndex()]; + utf8 = (ConstantPoolUtf8Info) constantPool[ntInfo.getNameIndex()]; + sb.append(utf8.getString()); + } + if (handleRef instanceof ConstantPoolMethodReferenceInfo) { + ConstantPoolMethodReferenceInfo methodRef = (ConstantPoolMethodReferenceInfo) handleRef; + ConstantPoolClassInfo classRef = + (ConstantPoolClassInfo) constantPool[methodRef.getClassIndex()]; + ConstantPoolUtf8Info utf8 = + (ConstantPoolUtf8Info) constantPool[classRef.getNameIndex()]; + sb.append(utf8.getString() + "."); + ConstantPoolNameAndTypeInfo nameAndType = + (ConstantPoolNameAndTypeInfo) constantPool[methodRef.getNameAndTypeIndex()]; + utf8 = (ConstantPoolUtf8Info) constantPool[nameAndType.getNameIndex()]; + sb.append(utf8.getString()); + } + if (handleRef instanceof ConstantPoolInterfaceMethodReferenceInfo) { + ConstantPoolInterfaceMethodReferenceInfo mrInfo = + (ConstantPoolInterfaceMethodReferenceInfo) handleRef; + ConstantPoolClassInfo classRef = + (ConstantPoolClassInfo) constantPool[mrInfo.getClassIndex()]; + ConstantPoolUtf8Info utf8 = + (ConstantPoolUtf8Info) constantPool[classRef.getNameIndex()]; + sb.append(utf8.getString() + "."); + ConstantPoolNameAndTypeInfo nameAndType = + (ConstantPoolNameAndTypeInfo) constantPool[mrInfo.getNameAndTypeIndex()]; + utf8 = (ConstantPoolUtf8Info) constantPool[nameAndType.getNameIndex()]; + sb.append(utf8.getString()); + } + } + + private void appendLoadableInfo(StringBuffer sb, AbstractConstantPoolInfoJava[] constantPool, + int argIndex) { + AbstractConstantPoolInfoJava cpoolInfo = constantPool[argIndex]; + if (cpoolInfo instanceof ConstantPoolIntegerInfo) { + ConstantPoolIntegerInfo intInfo = (ConstantPoolIntegerInfo) cpoolInfo; + sb.append(intInfo.getValue()); + return; + } + if (cpoolInfo instanceof ConstantPoolFloatInfo) { + ConstantPoolFloatInfo floatInfo = (ConstantPoolFloatInfo) cpoolInfo; + sb.append(floatInfo.getValue()); + return; + } + if (cpoolInfo instanceof ConstantPoolLongInfo) { + ConstantPoolLongInfo longInfo = (ConstantPoolLongInfo) cpoolInfo; + sb.append(longInfo.getValue()); + return; + } + if (cpoolInfo instanceof ConstantPoolDoubleInfo) { + ConstantPoolDoubleInfo doubleInfo = (ConstantPoolDoubleInfo) cpoolInfo; + sb.append(doubleInfo.getValue()); + return; + } + if (cpoolInfo instanceof ConstantPoolClassInfo) { + ConstantPoolClassInfo classInfo = (ConstantPoolClassInfo) cpoolInfo; + ConstantPoolUtf8Info className = + (ConstantPoolUtf8Info) constantPool[classInfo.getNameIndex()]; + sb.append(className.getString()); + return; + } + if (cpoolInfo instanceof ConstantPoolStringInfo) { + ConstantPoolStringInfo stringInfo = (ConstantPoolStringInfo) cpoolInfo; + ConstantPoolUtf8Info utf8 = + (ConstantPoolUtf8Info) constantPool[stringInfo.getStringIndex()]; + sb.append("\""); + sb.append(utf8.getString()); + sb.append("\""); + return; + } + if (cpoolInfo instanceof ConstantPoolMethodHandleInfo) { + appendMethodHandleInfo(sb, constantPool, argIndex); + return; + } + if (cpoolInfo instanceof ConstantPoolMethodTypeInfo) { + ConstantPoolMethodTypeInfo mtInfo = (ConstantPoolMethodTypeInfo) cpoolInfo; + ConstantPoolUtf8Info descriptor = + (ConstantPoolUtf8Info) constantPool[mtInfo.getDescriptorIndex()]; + sb.append(descriptor.getString()); + return; + } + if (cpoolInfo instanceof ConstantPoolDynamicInfo) { + ConstantPoolDynamicInfo dynamicInfo = (ConstantPoolDynamicInfo) cpoolInfo; + ConstantPoolNameAndTypeInfo ntInfo = + (ConstantPoolNameAndTypeInfo) constantPool[dynamicInfo.getNameAndTypeIndex()]; + ConstantPoolUtf8Info name = (ConstantPoolUtf8Info) constantPool[ntInfo.getNameIndex()]; + sb.append(name.getString()); + return; + } + Msg.showWarn(this, null, "Unsupported Constant Pool Type", cpoolInfo.getClass().getName()); + return; + } + private void markupFields(Program program, ClassFileJava classFile, TaskMonitor monitor) { AbstractConstantPoolInfoJava[] constantPool = classFile.getConstantPool(); @@ -479,290 +652,6 @@ public class JavaAnalyzer extends AbstractJavaAnalyzer implements AnalysisWorker } } - private String getOperandMarkup(Program program, AbstractConstantPoolInfoJava[] constantPool, - int index) { - if (index >= constantPool.length || index < 0) { - // TODO: < 0 can happen with if 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("")) { - 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 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; + } + } + } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/flags/ClassFileFlags.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/flags/ClassFileFlags.java index 322c324286..60935173f9 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/flags/ClassFileFlags.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/flags/ClassFileFlags.java @@ -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; + } } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/flags/FieldInfoAccessFlags.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/flags/FieldInfoAccessFlags.java index c1348a16c6..c08c1972f3 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/flags/FieldInfoAccessFlags.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/flags/FieldInfoAccessFlags.java @@ -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; + } } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/flags/MethodsInfoAccessFlags.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/flags/MethodsInfoAccessFlags.java index a1943847cf..6dea043cae 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/flags/MethodsInfoAccessFlags.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/flags/MethodsInfoAccessFlags.java @@ -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: + *
+ *
"public static final",
+ *
"package private", or
+ *
"protected transient".
+ *
+ * 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(); + } } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/AccessFlagsJava.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/AccessFlagsJava.java deleted file mode 100644 index ac8ec46437..0000000000 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/AccessFlagsJava.java +++ /dev/null @@ -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 - * invokespecial 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: - *
- *
"public static final",
- *
"package private", or
- *
"protected transient".
- *
- * 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 ); - } - -} diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/ClassFileJava.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/ClassFileJava.java index 98c998d260..896e13afad 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/ClassFileJava.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/ClassFileJava.java @@ -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 *

@@ -85,9 +79,9 @@ public class ClassFileJava implements StructConverter { minorVersion = reader.readNextShort(); majorVersion = reader.readNextShort(); constantPoolCount = reader.readNextShort(); - constantPool = new AbstractConstantPoolInfoJava[constantPoolCount]; + constantPool = new AbstractConstantPoolInfoJava[getConstantPoolCount()]; //NOTE: start at index 1 per JVM specification!!! - for (int i = 1; i < constantPoolCount; i++) { + for (int i = 1; i < getConstantPoolCount(); i++) { constantPool[i] = ConstantPoolFactory.get(reader); //From section 4.4.5 of JVM specification: @@ -97,7 +91,7 @@ public class ClassFileJava implements StructConverter { ///located at index n+2. The constant_pool index n+1 must be valid but is considered //unusable. if (constantPool[i] instanceof ConstantPoolLongInfo || - constantPool[i] instanceof ConstantPoolDoubleInfo) { + constantPool[i] instanceof ConstantPoolDoubleInfo) { ++i; } } @@ -105,20 +99,20 @@ public class ClassFileJava implements StructConverter { thisClass = reader.readNextShort(); superClass = reader.readNextShort(); interfacesCount = reader.readNextShort(); - interfaces = reader.readNextShortArray(interfacesCount); + interfaces = reader.readNextShortArray(getInterfacesCount()); fieldsCount = reader.readNextShort(); - fields = new FieldInfoJava[fieldsCount]; - for (int i = 0; i < fieldsCount; i++) { + fields = new FieldInfoJava[getFieldsCount()]; + for (int i = 0; i < getFieldsCount(); i++) { fields[i] = new FieldInfoJava(reader, this); } methodsCount = reader.readNextShort(); - methods = new MethodInfoJava[methodsCount]; - for (int i = 0; i < methodsCount; i++) { + methods = new MethodInfoJava[getMethodsCount()]; + for (int i = 0; i < getMethodsCount(); i++) { methods[i] = new MethodInfoJava(reader, this); } attributesCount = reader.readNextShort(); - attributes = new AbstractAttributeInfo[attributesCount]; - for (int i = 0; i < attributesCount; i++) { + attributes = new AbstractAttributeInfo[getAttributesCount()]; + for (int i = 0; i < getAttributesCount(); i++) { attributes[i] = AttributeFactory.get(reader, getConstantPool()); } } @@ -173,8 +167,8 @@ public class ClassFileJava implements StructConverter { * exception for constants of type long and double noted in ?4.4.5. * @return the number of entries in the constant_pool table plus one */ - public short getConstantPoolCount() { - return constantPoolCount; + public int getConstantPoolCount() { + return constantPoolCount & 0xffff; } /** @@ -207,8 +201,8 @@ public class ClassFileJava implements StructConverter { * defined by this class file. * @return a valid index into the constant_pool table to a CONSTANT_Class_info */ - public short getThisClass() { - return thisClass; + public int getThisClass() { + return thisClass & 0xffff; } /** @@ -228,8 +222,8 @@ public class ClassFileJava implements StructConverter { * must be a CONSTANT_Class_info structure representing the class Object. * @return a valid index into the constant_pool table to a CONSTANT_Class_info */ - public short getSuperClass() { - return superClass; + public int getSuperClass() { + return superClass & 0xffff; } /** @@ -237,8 +231,8 @@ public class ClassFileJava implements StructConverter { * superinterfaces of this class or interface type. * @return the number of direct superinterfaces of this class */ - public short getInterfacesCount() { - return interfacesCount; + public int getInterfacesCount() { + return interfacesCount & 0xffff; } /** @@ -248,10 +242,11 @@ public class ClassFileJava implements StructConverter { * CONSTANT_Class_info (?4.4.1) structure representing an interface that is a * direct superinterface of this class or interface type, in the left-to-right order * given in the source for the type. - * @return an array of interfaces + * @param i entry + * @return interface index */ - public short[] getInterfaces() { - return interfaces; + public int getInterfacesEntry(int i) { + return interfaces[i] & 0xffff; } /** @@ -261,8 +256,8 @@ public class ClassFileJava implements StructConverter { * interface type. * @return the number of field_info structures in the fields table */ - public short getFieldsCount() { - return fieldsCount; + public int getFieldsCount() { + return fieldsCount & 0xffff; } /** @@ -282,8 +277,8 @@ public class ClassFileJava implements StructConverter { * structures in the methods table. * @return the number of method_info structures in the methods table */ - public short getMethodsCount() { - return methodsCount; + public int getMethodsCount() { + return methodsCount & 0xffff; } /** @@ -309,8 +304,8 @@ public class ClassFileJava implements StructConverter { * in the attributes table of this class. * @return the number of attributes in the attributes table */ - public short getAttributesCount() { - return attributesCount; + public int getAttributesCount() { + return attributesCount & 0xffff; } /** @@ -370,14 +365,14 @@ public class ClassFileJava implements StructConverter { structure.add(WORD, "super_class", null); structure.add(WORD, "interfaces_count", null); - if (interfacesCount > 0) { - DataType array = new ArrayDataType(WORD, interfacesCount, WORD.getLength()); + if (getInterfacesCount() > 0) { + DataType array = new ArrayDataType(WORD, getInterfacesCount(), WORD.getLength()); structure.add(array, "interfaces", null); } structure.add(WORD, "field_count", null); - if (fieldsCount > 0) { + if (getFieldsCount() > 0) { Structure fieldStruct = new StructureDataType("fields", 0); for (int i = 0; i < fields.length; ++i) { fieldStruct.add(fields[i].toDataType(), "field_" + i, null); @@ -387,7 +382,7 @@ public class ClassFileJava implements StructConverter { structure.add(WORD, "method_count", null); - if (methodsCount > 0) { + if (getMethodsCount() > 0) { Structure methodsStruct = new StructureDataType("methods", 0); for (int i = 0; i < methods.length; ++i) { methodsStruct.add(methods[i].toDataType(), "methods_" + i, null); @@ -396,7 +391,7 @@ public class ClassFileJava implements StructConverter { } structure.add(WORD, "attributes_count", null); - if (attributesCount > 0){ + if (getAttributesCount() > 0) { Structure attributesStruct = new StructureDataType("attributes", 0); for (int i = 0; i < attributes.length; ++i) { attributesStruct.add(attributes[i].toDataType(), "attributes_" + i, null); diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/DescriptorDecoder.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/DescriptorDecoder.java index 1ac9b8e944..0683eafd27 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/DescriptorDecoder.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/DescriptorDecoder.java @@ -19,12 +19,7 @@ import java.util.ArrayList; import java.util.List; import ghidra.app.util.pcodeInject.*; -import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava; -import ghidra.javaclass.format.constantpool.ConstantPoolInterfaceMethodReferenceInfo; -import ghidra.javaclass.format.constantpool.ConstantPoolInvokeDynamicInfo; -import ghidra.javaclass.format.constantpool.ConstantPoolMethodReferenceInfo; -import ghidra.javaclass.format.constantpool.ConstantPoolNameAndTypeInfo; -import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info; +import ghidra.javaclass.format.constantpool.*; import ghidra.program.model.data.*; /** @@ -34,7 +29,6 @@ import ghidra.program.model.data.*; * */ - public class DescriptorDecoder { public final static byte BASE_TYPE_BYTE = 'B'; @@ -53,9 +47,8 @@ public class DescriptorDecoder { public final static byte BASE_TYPE_ENUM = 'e'; public final static byte BASE_TYPE_ANNOTATION = '@'; - //private constructor to enforce noninstantiability - private DescriptorDecoder(){ + private DescriptorDecoder() { throw new AssertionError(); } @@ -65,11 +58,11 @@ public class DescriptorDecoder { * @param methodDescriptor * @return */ - public static int getStackPurge(String methodDescriptor){ + public static int getStackPurge(String methodDescriptor) { int stackPurge = 0; List categories = getParameterCategories(methodDescriptor); - for (JavaComputationalCategory cat : categories){ - switch (cat){ + for (JavaComputationalCategory cat : categories) { + switch (cat) { case CAT_1: stackPurge += PcodeInjectLibraryJava.REFERENCE_SIZE; break; @@ -83,31 +76,41 @@ public class DescriptorDecoder { return stackPurge; } - /** * Returns the computational category of the return type of a method descriptor. * @param methodDescriptor * @return */ - public static JavaComputationalCategory getReturnCategoryOfMethodDescriptor(String methodDescriptor){ + public static JavaComputationalCategory getReturnCategoryOfMethodDescriptor( + String methodDescriptor) { int closeParenIndex = methodDescriptor.indexOf(")"); - if (closeParenIndex == -1){ + if (closeParenIndex == -1) { throw new IllegalArgumentException("Invalid method descriptor: " + methodDescriptor); } - String returnDescriptor = methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length()); + String returnDescriptor = + methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length()); return DescriptorDecoder.getComputationalCategoryOfDescriptor(returnDescriptor); } - public static DataType getReturnTypeOfMethodDescriptor(String methodDescriptor, DataTypeManager dtManager){ + /** + * Given a method descriptor, returns the data type of the return value of the corresponding + * method + * @param methodDescriptor descriptor of method + * @param dtManager data type manger for containing program + * @return data type of return value of method + */ + public static DataType getReturnTypeOfMethodDescriptor(String methodDescriptor, + DataTypeManager dtManager) { int closeParenIndex = methodDescriptor.indexOf(")"); - if (closeParenIndex == -1){ + if (closeParenIndex == -1) { throw new IllegalArgumentException("Invalid method descriptor: " + methodDescriptor); } - String returnDescriptor = methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length()); - if (returnDescriptor.startsWith("[")){ + String returnDescriptor = + methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length()); + if (returnDescriptor.startsWith("[")) { return getPointerType(returnDescriptor, dtManager); } - return DescriptorDecoder.getDataTypeOfDescriptor(returnDescriptor, dtManager); + return DescriptorDecoder.getDataTypeOfDescriptor(returnDescriptor, dtManager); } /** @@ -115,11 +118,12 @@ public class DescriptorDecoder { * @param descriptor * @return */ - public static JavaComputationalCategory getComputationalCategoryOfDescriptor(String descriptor){ + public static JavaComputationalCategory getComputationalCategoryOfDescriptor( + String descriptor) { //all references to objects start with "L" //all references to arrays start with "[" //all other descriptors are just one letter. - switch (descriptor.charAt(0)){ + switch (descriptor.charAt(0)) { case BASE_TYPE_BYTE: //signed byte case BASE_TYPE_CHAR: //char case BASE_TYPE_FLOAT: //float @@ -144,7 +148,8 @@ public class DescriptorDecoder { * @param methodDescriptor * @return */ - public static List getTypeNameList(String methodDescriptor, boolean fullyQualifiedName, boolean replaceSlash) { + public static List getTypeNameList(String methodDescriptor, boolean fullyQualifiedName, + boolean replaceSlash) { ArrayList typeNames = new ArrayList<>(); int closeParenIndex = methodDescriptor.indexOf(")"); String argString = methodDescriptor.substring(1, closeParenIndex); @@ -152,79 +157,85 @@ public class DescriptorDecoder { int currentPosition = 0; int len = argString.length(); - while (currentPosition < len){ + while (currentPosition < len) { String currentParam = argString.substring(currentPosition, currentPosition + 1); - if (currentParam.equals("[")){ + if (currentParam.equals("[")) { int initialBracket = currentPosition; - while (argString.charAt(currentPosition) == '['){ + while (argString.charAt(currentPosition) == '[') { currentPosition++; } //advance past the base type of the array - if (argString.charAt(currentPosition) == 'L'){ + if (argString.charAt(currentPosition) == 'L') { int semiColonIndex = argString.indexOf(";", currentPosition); currentPosition = semiColonIndex + 1; } - else{ + else { currentPosition++; } - currentParamTypeName = getTypeNameFromDescriptor(argString.substring(initialBracket,currentPosition), fullyQualifiedName, replaceSlash); + currentParamTypeName = + getTypeNameFromDescriptor(argString.substring(initialBracket, currentPosition), + fullyQualifiedName, replaceSlash); typeNames.add(currentParamTypeName); continue; - } + } //advance to next type in argString //if it's a reference, it starts with L and ends with a ; //otherwise you only need to advance one character - switch(currentParam){ + switch (currentParam) { case "L": int semiColonIndex = argString.indexOf(";", currentPosition); - currentParamTypeName = getTypeNameFromDescriptor(argString.substring(currentPosition,semiColonIndex+1), fullyQualifiedName, replaceSlash); + currentParamTypeName = getTypeNameFromDescriptor( + argString.substring(currentPosition, semiColonIndex + 1), + fullyQualifiedName, replaceSlash); currentPosition = semiColonIndex + 1; //advance past ; break; default: - currentParamTypeName = getTypeNameFromDescriptor(currentParam, fullyQualifiedName, replaceSlash); - currentPosition++; + currentParamTypeName = + getTypeNameFromDescriptor(currentParam, fullyQualifiedName, replaceSlash); + currentPosition++; } typeNames.add(currentParamTypeName); } //now add the the name of the return type - String returnType = methodDescriptor.substring(closeParenIndex+1, methodDescriptor.length()); + String returnType = + methodDescriptor.substring(closeParenIndex + 1, methodDescriptor.length()); typeNames.add(getTypeNameFromDescriptor(returnType, fullyQualifiedName, replaceSlash)); return typeNames; } - - /** * Returns the type name for a parameter descriptor * @param descriptor * @return */ - public static String getTypeNameFromDescriptor(String descriptor, boolean fullyQualifiedName, boolean replaceSlash){ - if (descriptor.startsWith("L")){ + public static String getTypeNameFromDescriptor(String descriptor, boolean fullyQualifiedName, + boolean replaceSlash) { + if (descriptor.startsWith("L")) { //leave off the initial L and the final ; - String name = descriptor.substring(1, descriptor.length()-1); - if (fullyQualifiedName){ - if (replaceSlash){ - return name.replace("/", "."); + String name = descriptor.substring(1, descriptor.length() - 1); + if (fullyQualifiedName) { + if (replaceSlash) { + return name.replace("/", "."); } return name; } int lastSlash = name.lastIndexOf("/"); //lastSlash+1 so the slash is not included in the name - return name.substring(lastSlash+1, name.length()); + return name.substring(lastSlash + 1, name.length()); } - if (descriptor.startsWith("[")){ + if (descriptor.startsWith("[")) { int dimension = descriptor.lastIndexOf("[") + 1; - String baseType = getTypeNameFromDescriptor(descriptor.replace("[", ""), fullyQualifiedName, replaceSlash); + String baseType = getTypeNameFromDescriptor(descriptor.replace("[", ""), + fullyQualifiedName, replaceSlash); StringBuilder sb = new StringBuilder(baseType); - for (int i = 0; i < dimension; ++i){ + for (int i = 0; i < dimension; ++i) { sb.append("[]"); } return sb.toString(); } - switch (descriptor.charAt(0)){ + switch (descriptor.charAt(0)) { case BASE_TYPE_BYTE: //signed byte return "byte"; case BASE_TYPE_CHAR: //char @@ -248,17 +259,18 @@ public class DescriptorDecoder { } } - public static DataType getReferenceTypeOfDescriptor(String descriptor, DataTypeManager dtManager, boolean includesLandSemi){ - if (includesLandSemi){ - descriptor = descriptor.substring(1, descriptor.length()-1); + public static DataType getReferenceTypeOfDescriptor(String descriptor, + DataTypeManager dtManager, boolean includesLandSemi) { + if (includesLandSemi) { + descriptor = descriptor.substring(1, descriptor.length() - 1); } String[] parts = descriptor.split("/"); StringBuilder sb = new StringBuilder(); - for (int i = 0; i < parts.length; i++){ + for (String part : parts) { sb.append(CategoryPath.DELIMITER_CHAR); - sb.append(parts[i]); + sb.append(part); } - DataTypePath dataPath = new DataTypePath(sb.toString(), parts[parts.length-1]); + DataTypePath dataPath = new DataTypePath(sb.toString(), parts[parts.length - 1]); DataType referencedType = dtManager.getDataType(dataPath); return new PointerDataType(referencedType); } @@ -268,44 +280,50 @@ public class DescriptorDecoder { * @param descriptor * @return */ - public static DataType getDataTypeOfDescriptor(String descriptor, DataTypeManager dtManager){ + public static DataType getDataTypeOfDescriptor(String descriptor, DataTypeManager dtManager) { //all references to objects start with "L" //all references to arrays start with "[" //all other descriptors are just one letter. - if (descriptor.startsWith("[")){ + if (descriptor.startsWith("[")) { return getPointerType(descriptor, dtManager); } - switch (descriptor.charAt(0)){ - case BASE_TYPE_BYTE: + switch (descriptor.charAt(0)) { + case BASE_TYPE_BYTE: return SignedByteDataType.dataType; - case BASE_TYPE_CHAR: + case BASE_TYPE_CHAR: return CharDataType.dataType; - case BASE_TYPE_INT: + case BASE_TYPE_INT: return IntegerDataType.dataType; case BASE_TYPE_SHORT: return ShortDataType.dataType; - case BASE_TYPE_BOOLEAN: + case BASE_TYPE_BOOLEAN: return BooleanDataType.dataType; - case BASE_TYPE_FLOAT: + case BASE_TYPE_FLOAT: return FloatDataType.dataType; case BASE_TYPE_REFERENCE: //object reference return getReferenceTypeOfDescriptor(descriptor, dtManager, true); - case BASE_TYPE_DOUBLE: + case BASE_TYPE_DOUBLE: return DoubleDataType.dataType; - case BASE_TYPE_LONG: + case BASE_TYPE_LONG: return LongDataType.dataType; case BASE_TYPE_VOID: //void (only for return types) return DataType.VOID; default: - throw new IllegalArgumentException("Invalid computational category: " + descriptor); + throw new IllegalArgumentException("Invalid type descriptor: " + descriptor); } } - public static DataType getPointerType(String descriptor, DataTypeManager dtManager){ + /** + * Returns the data type of a pointer to the type represented by descriptor + * @param descriptor description of base type + * @param dtManager data type manager of program + * @return pointer data type + */ + public static DataType getPointerType(String descriptor, DataTypeManager dtManager) { int lastBracket = descriptor.lastIndexOf("["); - String baseTypeOfArray = descriptor.substring(lastBracket+1, lastBracket+2); + String baseTypeOfArray = descriptor.substring(lastBracket + 1, lastBracket + 2); DataType baseType = null; - switch (baseTypeOfArray.charAt(0)){ + switch (baseTypeOfArray.charAt(0)) { case BASE_TYPE_BYTE: baseType = ArrayMethods.getArrayBaseType(JavaClassConstants.T_BYTE, dtManager); break; @@ -334,7 +352,8 @@ public class DescriptorDecoder { return dtManager.getPointer(DWordDataType.dataType); default: - throw new IllegalArgumentException("Invalid array base type category: " + baseTypeOfArray); + throw new IllegalArgumentException( + "Invalid array base type category: " + baseTypeOfArray); } return dtManager.getPointer(baseType); } @@ -345,17 +364,18 @@ public class DescriptorDecoder { * @param methodDescriptor * @return */ - public static List getParameterCategories(String methodDescriptor){ + public static List getParameterCategories(String methodDescriptor) { ArrayList categories = new ArrayList<>(); int closeParenIndex = methodDescriptor.indexOf(")"); String argString = methodDescriptor.substring(1, closeParenIndex); int currentPosition = 0; int len = argString.length(); - while (currentPosition < len){ + while (currentPosition < len) { String currentParam = argString.substring(currentPosition, currentPosition + 1); - JavaComputationalCategory category = DescriptorDecoder.getComputationalCategoryOfDescriptor(currentParam); + JavaComputationalCategory category = + DescriptorDecoder.getComputationalCategoryOfDescriptor(currentParam); - switch (category){ + switch (category) { case CAT_1: categories.add(JavaComputationalCategory.CAT_1); break; @@ -370,22 +390,22 @@ public class DescriptorDecoder { //if it's a reference, it starts with L and ends with a ; //if it's an array, it has one "[" for each dimension, then the type (which might be a reference) //otherwise you only need to advance one character - switch(currentParam){ + switch (currentParam) { case "L": int semiColonIndex = argString.indexOf(";", currentPosition); currentPosition = semiColonIndex + 1; //advance past ; break; case "[": //advance past all the ['s - while (argString.charAt(currentPosition) == '['){ + while (argString.charAt(currentPosition) == '[') { currentPosition++; } //advance past the base type of the array - if (argString.charAt(currentPosition) == 'L'){ + if (argString.charAt(currentPosition) == 'L') { semiColonIndex = argString.indexOf(";", currentPosition); currentPosition = semiColonIndex + 1; } - else{ + else { currentPosition++; } break; @@ -402,7 +422,8 @@ public class DescriptorDecoder { * @param methodDescriptor * @return */ - public static List getDataTypeList(String methodDescriptor, DataTypeManager dtManager) { + public static List getDataTypeList(String methodDescriptor, + DataTypeManager dtManager) { ArrayList paramDataTypes = new ArrayList<>(); int closeParenIndex = methodDescriptor.indexOf(")"); String argString = methodDescriptor.substring(1, closeParenIndex); @@ -411,14 +432,14 @@ public class DescriptorDecoder { int currentPosition = 0; int len = argString.length(); String currentParam = null; - while (currentPosition < len){ + while (currentPosition < len) { int arrayDimensions = 0; //if it's an array, decode the number of dimensions - while (argString.charAt(currentPosition) == '['){ + while (argString.charAt(currentPosition) == '[') { arrayDimensions++; currentPosition++; } - switch (argString.charAt(currentPosition)){ + switch (argString.charAt(currentPosition)) { case BASE_TYPE_BYTE: case BASE_TYPE_CHAR: case BASE_TYPE_SHORT: @@ -427,17 +448,17 @@ public class DescriptorDecoder { case BASE_TYPE_FLOAT: case BASE_TYPE_DOUBLE: case BASE_TYPE_BOOLEAN: - currentParam = argString.substring(currentPosition, currentPosition+1); + currentParam = argString.substring(currentPosition, currentPosition + 1); currentPosition++; break; case BASE_TYPE_REFERENCE: int semiColonIndex = argString.indexOf(";", currentPosition); - currentParam = argString.substring(currentPosition, semiColonIndex+1); + currentParam = argString.substring(currentPosition, semiColonIndex + 1); currentPosition = semiColonIndex + 1; break; } currentParamType = getDataTypeOfDescriptor(currentParam, dtManager); - if (arrayDimensions > 0){ + if (arrayDimensions > 0) { paramDataTypes.add(dtManager.getPointer(currentParamType)); } else { @@ -455,47 +476,91 @@ public class DescriptorDecoder { * @param type * @return */ - public static String getDescriptorForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type){ + public static String getDescriptorForInvoke(int offset, + AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) { String descriptor = null; int name_and_type_index = 0; - switch (type){ + switch (type) { case INVOKE_DYNAMIC: - ConstantPoolInvokeDynamicInfo dynamicInfo = (ConstantPoolInvokeDynamicInfo) constantPool[offset]; + ConstantPoolInvokeDynamicInfo dynamicInfo = + (ConstantPoolInvokeDynamicInfo) constantPool[offset]; name_and_type_index = dynamicInfo.getNameAndTypeIndex(); break; case INVOKE_INTERFACE: - ConstantPoolInterfaceMethodReferenceInfo interfaceInfo = (ConstantPoolInterfaceMethodReferenceInfo) constantPool[offset]; + ConstantPoolInterfaceMethodReferenceInfo interfaceInfo = + (ConstantPoolInterfaceMethodReferenceInfo) constantPool[offset]; name_and_type_index = interfaceInfo.getNameAndTypeIndex(); break; - case INVOKE_SPECIAL: case INVOKE_STATIC: + AbstractConstantPoolInfoJava poolElem = constantPool[offset]; + if (poolElem instanceof ConstantPoolInterfaceMethodReferenceInfo) { + interfaceInfo = (ConstantPoolInterfaceMethodReferenceInfo) constantPool[offset]; + name_and_type_index = interfaceInfo.getNameAndTypeIndex(); + break; + } + if (poolElem instanceof ConstantPoolMethodReferenceInfo) { + ConstantPoolMethodReferenceInfo methodReferenceInfo = + (ConstantPoolMethodReferenceInfo) constantPool[offset]; + name_and_type_index = methodReferenceInfo.getNameAndTypeIndex(); + break; + } + throw new IllegalArgumentException( + "Unsupported type for invokestatic at constant pool element " + offset); + case INVOKE_SPECIAL: case INVOKE_VIRTUAL: - ConstantPoolMethodReferenceInfo methodReferenceInfo = (ConstantPoolMethodReferenceInfo) constantPool[offset]; + ConstantPoolMethodReferenceInfo methodReferenceInfo = + (ConstantPoolMethodReferenceInfo) constantPool[offset]; name_and_type_index = methodReferenceInfo.getNameAndTypeIndex(); break; default: throw new IllegalArgumentException("unimplemented method type: " + type.name()); } - ConstantPoolNameAndTypeInfo methodNameAndType = (ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index]; + ConstantPoolNameAndTypeInfo methodNameAndType = + (ConstantPoolNameAndTypeInfo) constantPool[name_and_type_index]; int descriptor_index = methodNameAndType.getDescriptorIndex(); ConstantPoolUtf8Info descriptorInfo = (ConstantPoolUtf8Info) constantPool[descriptor_index]; descriptor = descriptorInfo.getString(); return descriptor; } - public final static String decodeType(ConstantPoolUtf8Info utf, - boolean useFullyQualifiedClassName) { - return DescriptorDecoder.getTypeNameFromDescriptor(utf.getString(), useFullyQualifiedClassName, true); - } - - //no L, no ; - public static DataType resolveClassForString(String fullyQualifiedName, DataTypeManager dtm, DataType baseType){ + /** + * Resolves the datatype represented by {@code fullyQualifiedName} with a base type of + * {@code baseType} into dtm + * @param fullyQualifiedName String representation of type + * @param dtm data type manager + * @param baseType base type + * @return data type represented by input string + */ + public static DataType resolveClassForString(String fullyQualifiedName, DataTypeManager dtm, + DataType baseType) { fullyQualifiedName = CategoryPath.DELIMITER_CHAR + fullyQualifiedName; CategoryPath catPath = new CategoryPath(fullyQualifiedName); String[] parts = catPath.getPathElements(); - DataType dataType = new TypedefDataType(catPath,parts[parts.length-1],baseType); + DataType dataType = new TypedefDataType(catPath, parts[parts.length - 1], baseType); dtm.resolve(dataType, DataTypeConflictHandler.KEEP_HANDLER); return dataType; } + /** + * Returns a String representing the types of the parameters of a method, e.g. + * (java.lang.String, java.lang.Integer) for a method with signature + * public static void test(String x, Integer y); + * @param descriptor method descriptor + * @return string representation of types of method parameters + */ + public static String getParameterString(String descriptor) { + List 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(); + } + } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/FieldInfoJava.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/FieldInfoJava.java index 79146e4099..0b2271ee1e 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/FieldInfoJava.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/FieldInfoJava.java @@ -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 *

@@ -48,18 +48,18 @@ public class FieldInfoJava implements StructConverter { private short nameIndex; private short descriptorIndex; private short attributesCount; - private AbstractAttributeInfo [] attributes; + private AbstractAttributeInfo[] attributes; - public FieldInfoJava( BinaryReader reader, ClassFileJava classFile ) throws IOException { + public FieldInfoJava(BinaryReader reader, ClassFileJava classFile) throws IOException { _offset = reader.getPointerIndex(); - accessFlags = reader.readNextShort(); - nameIndex = reader.readNextShort(); - descriptorIndex = reader.readNextShort(); - attributesCount = reader.readNextShort(); - attributes = new AbstractAttributeInfo[ attributesCount ]; - for ( int i = 0 ; i < attributesCount ; i++ ) { - attributes[ i ] = AttributeFactory.get( reader, classFile.getConstantPool() ); + accessFlags = reader.readNextShort(); + nameIndex = reader.readNextShort(); + descriptorIndex = reader.readNextShort(); + attributesCount = reader.readNextShort(); + attributes = new AbstractAttributeInfo[getAttributesCount()]; + for (int i = 0; i < getAttributesCount(); i++) { + attributes[i] = AttributeFactory.get(reader, classFile.getConstantPool()); } } @@ -84,8 +84,8 @@ public class FieldInfoJava implements StructConverter { * unqualified name denoting a field. * @return a valid index into the constant_pool table */ - public short getNameIndex() { - return nameIndex; + public int getNameIndex() { + return nameIndex & 0xffff; } /** @@ -95,8 +95,8 @@ public class FieldInfoJava implements StructConverter { * descriptor. * @return a valid index into the constant_pool table */ - public short getDescriptorIndex() { - return descriptorIndex; + public int getDescriptorIndex() { + return descriptorIndex & 0xffff; } /** @@ -104,8 +104,8 @@ public class FieldInfoJava implements StructConverter { * attributes of this field. * @return the number of additional attributes */ - public short getAttributesCount() { - return attributesCount; + public int getAttributesCount() { + return attributesCount & 0xffff; } /** @@ -137,13 +137,13 @@ public class FieldInfoJava implements StructConverter { * information. * @return */ - public AbstractAttributeInfo [] getAttributes() { + public AbstractAttributeInfo[] getAttributes() { return attributes; } public ConstantValueAttribute getConstantValueAttribute() { - for ( AbstractAttributeInfo attributeInfo : attributes ) { - if ( attributeInfo instanceof ConstantValueAttribute ) { + for (AbstractAttributeInfo attributeInfo : attributes) { + if (attributeInfo instanceof ConstantValueAttribute) { return (ConstantValueAttribute) attributeInfo; } } @@ -152,17 +152,17 @@ public class FieldInfoJava implements StructConverter { @Override public DataType toDataType() throws DuplicateNameException, IOException { - String name = "field_info" + "|" + attributesCount + "|"; + String name = "field_info" + "|" + attributesCount + "|"; - Structure structure = new StructureDataType( name, 0 ); + Structure structure = new StructureDataType(name, 0); - structure.add( WORD, "access_flags", null ); - structure.add( WORD, "name_index", null ); - structure.add( WORD, "descriptor_index", null ); - structure.add( WORD, "attributes_count", null ); + structure.add(WORD, "access_flags", null); + structure.add(WORD, "name_index", null); + structure.add(WORD, "descriptor_index", null); + structure.add(WORD, "attributes_count", null); - for ( int i = 0 ; i < attributes.length ; ++i ) { - structure.add( attributes[ i ].toDataType(), "attributes_" + i, null ); + for (int i = 0; i < attributes.length; ++i) { + structure.add(attributes[i].toDataType(), "attributes_" + i, null); } return structure; diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/JavaClassUtil.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/JavaClassUtil.java index 403021ec54..fc7070d398 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/JavaClassUtil.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/JavaClassUtil.java @@ -15,42 +15,38 @@ */ package ghidra.javaclass.format; -import ghidra.framework.options.Options; +import java.util.Arrays; + +import ghidra.app.util.opinion.JavaLoader; import ghidra.program.model.address.*; import ghidra.program.model.listing.Program; import ghidra.util.Msg; -import java.util.Arrays; - public class JavaClassUtil { - + public final static long LOOKUP_ADDRESS = 0xE0000000L; //65536 is the maximum size of the methods_count item in a class file public static final long METHOD_INDEX_SIZE = 65536 * 4; public final static boolean isClassFile(Program program) { - Options options = program.getOptions(Program.PROGRAM_INFO); - String firmwarePath = options.getString("Firmware Path", ""); - if (program.getExecutablePath().toLowerCase().endsWith(".class") || - firmwarePath.toLowerCase().endsWith(".class")) { - byte[] bytes = new byte[4]; - try { - Address address = program.getAddressFactory().getAddressSpace("constantPool").getMinAddress(); - program.getMemory().getBytes(address, bytes); - } - catch (Exception e) { - Msg.info(JavaClassUtil.class, e.getLocalizedMessage()); - } - return Arrays.equals(bytes, JavaClassConstants.MAGIC_BYTES); + byte[] bytes = new byte[4]; + try { + Address address = program.getAddressFactory().getAddressSpace( + JavaLoader.CONSTANT_POOL).getMinAddress(); + program.getMemory().getBytes(address, bytes); } - return false; + catch (Exception e) { + Msg.info(JavaClassUtil.class, e.getLocalizedMessage()); + return false; + } + return Arrays.equals(bytes, JavaClassConstants.MAGIC_BYTES); } - - public static Address toLookupAddress( Program program, int methodIndex ) { - AddressFactory addressFactory = program.getAddressFactory( ); - AddressSpace defaultAddressSpace = addressFactory.getDefaultAddressSpace( ); - return defaultAddressSpace.getAddress( JavaClassUtil.LOOKUP_ADDRESS + ( methodIndex * 4 ) ); + + public static Address toLookupAddress(Program program, int methodIndex) { + AddressFactory addressFactory = program.getAddressFactory(); + AddressSpace defaultAddressSpace = addressFactory.getDefaultAddressSpace(); + return defaultAddressSpace.getAddress(JavaClassUtil.LOOKUP_ADDRESS + (methodIndex * 4)); } } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/MethodInfoJava.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/MethodInfoJava.java index 1045913b0d..4e1d9cc81b 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/MethodInfoJava.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/MethodInfoJava.java @@ -15,15 +15,16 @@ */ package ghidra.javaclass.format; +import java.io.IOException; + import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.StructConverter; +import ghidra.javaclass.flags.MethodsInfoAccessFlags; import ghidra.javaclass.format.attributes.*; import ghidra.javaclass.format.constantpool.*; import ghidra.program.model.data.*; import ghidra.util.exception.DuplicateNameException; -import java.io.IOException; - /** * Each method, including each instance initialization method (2.9) and the class or * interface initialization method (2.9), is described by a method_info structure. No @@ -58,8 +59,8 @@ public class MethodInfoJava implements StructConverter { nameIndex = reader.readNextShort(); descriptorIndex = reader.readNextShort(); attributesCount = reader.readNextShort(); - attributes = new AbstractAttributeInfo[attributesCount]; - for (int i = 0; i < attributesCount; i++) { + attributes = new AbstractAttributeInfo[getAttributesCount()]; + for (int i = 0; i < getAttributesCount(); i++) { attributes[i] = AttributeFactory.get(reader, classFile.getConstantPool()); } } @@ -81,13 +82,14 @@ public class MethodInfoJava implements StructConverter { public short getAccessFlags() { return accessFlags; } - + /** * * @return boolean encoding whether the method is static */ - public boolean isStatic(){ - return AccessFlagsJava.isStatic(accessFlags); + public boolean isStatic() { + return (MethodsInfoAccessFlags.ACC_STATIC.getValue() & + accessFlags) == MethodsInfoAccessFlags.ACC_STATIC.getValue(); } /** @@ -98,8 +100,8 @@ public class MethodInfoJava implements StructConverter { * denoting a method. * @return a valid index into the constant_pool table */ - public short getNameIndex() { - return nameIndex; + public int getNameIndex() { + return nameIndex & 0xffff; } /** @@ -108,8 +110,8 @@ public class MethodInfoJava implements StructConverter { * CONSTANT_Utf8_info structure representing a valid method descriptor. * @return a valid index into the constant_pool table */ - public short getDescriptorIndex() { - return descriptorIndex; + public int getDescriptorIndex() { + return descriptorIndex & 0xffff; } /** @@ -117,8 +119,8 @@ public class MethodInfoJava implements StructConverter { * attributes of this method. * @return the number of additional attributes of this method */ - public short getAttributesCount() { - return attributesCount; + public int getAttributesCount() { + return attributesCount & 0xffff; } /** @@ -178,11 +180,13 @@ public class MethodInfoJava implements StructConverter { ConstantPoolUtf8Info methodDescriptor = (ConstantPoolUtf8Info) constantPool[descriptorIndex]; StringBuffer stringBuffer = new StringBuffer(); - stringBuffer.append(AccessFlagsJava.toString(accessFlags, false).trim()); + stringBuffer.append(MethodsInfoAccessFlags.toString(accessFlags)); - if (!methodName.getString().equals("")) { + if (methodName.getString().equals("")) { + stringBuffer.append(" (class initializer)"); + } + else { stringBuffer.append(' '); - if (methodName.getString().equals("")) {//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); diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AbstractAttributeInfo.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AbstractAttributeInfo.java index a589205df3..3850010557 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AbstractAttributeInfo.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AbstractAttributeInfo.java @@ -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 *

@@ -94,11 +93,11 @@ public abstract class AbstractAttributeInfo implements StructConverter { private short attributeNameIndex; private int attributeLength; - protected AbstractAttributeInfo( BinaryReader reader ) throws IOException { + protected AbstractAttributeInfo(BinaryReader reader) throws IOException { _offset = reader.getPointerIndex(); attributeNameIndex = reader.readNextShort(); - attributeLength = reader.readNextInt(); + attributeLength = reader.readNextInt(); } public long getOffset() { @@ -112,8 +111,8 @@ public abstract class AbstractAttributeInfo implements StructConverter { * @see AttributesConstants * @return the attribute_name_index */ - public short getAttributeNameIndex() { - return attributeNameIndex; + public int getAttributeNameIndex() { + return attributeNameIndex & 0xffff; } /** @@ -127,10 +126,10 @@ public abstract class AbstractAttributeInfo implements StructConverter { return attributeLength; } - protected StructureDataType getBaseStructure( String name ) { - StructureDataType structure = new StructureDataType( name + "|" + attributeLength + "|", 0 ); - structure.add( WORD, "attribute_name_index", null ); - structure.add( DWORD, "attribute_length" , null ); + protected StructureDataType getBaseStructure(String name) { + StructureDataType structure = new StructureDataType(name + "|" + attributeLength + "|", 0); + structure.add(WORD, "attribute_name_index", null); + structure.add(DWORD, "attribute_length", null); return structure; } } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AnnotationElementValue.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AnnotationElementValue.java index 94b7f35576..0e0d81fc3d 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AnnotationElementValue.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AnnotationElementValue.java @@ -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 *

@@ -69,38 +69,35 @@ public class AnnotationElementValue implements StructConverter { private AnnotationJava annotation; private short numberOfValues; - private AnnotationElementValue [] values; + private AnnotationElementValue[] values; - public AnnotationElementValue( BinaryReader reader ) throws IOException { + public AnnotationElementValue(BinaryReader reader) throws IOException { tag = reader.readNextByte(); - if ( tag == DescriptorDecoder.BASE_TYPE_BYTE || - tag == DescriptorDecoder.BASE_TYPE_CHAR || - tag == DescriptorDecoder.BASE_TYPE_INT || - tag == DescriptorDecoder.BASE_TYPE_SHORT || - tag == DescriptorDecoder.BASE_TYPE_LONG || - tag == DescriptorDecoder.BASE_TYPE_FLOAT || - tag == DescriptorDecoder.BASE_TYPE_DOUBLE || - tag == DescriptorDecoder.BASE_TYPE_BOOLEAN || - tag == DescriptorDecoder.BASE_TYPE_STRING ) { + if (tag == DescriptorDecoder.BASE_TYPE_BYTE || tag == DescriptorDecoder.BASE_TYPE_CHAR || + tag == DescriptorDecoder.BASE_TYPE_INT || tag == DescriptorDecoder.BASE_TYPE_SHORT || + tag == DescriptorDecoder.BASE_TYPE_LONG || tag == DescriptorDecoder.BASE_TYPE_FLOAT || + tag == DescriptorDecoder.BASE_TYPE_DOUBLE || + tag == DescriptorDecoder.BASE_TYPE_BOOLEAN || + tag == DescriptorDecoder.BASE_TYPE_STRING) { constantValueIndex = reader.readNextShort(); } - else if ( tag == DescriptorDecoder.BASE_TYPE_ENUM ) { + else if (tag == DescriptorDecoder.BASE_TYPE_ENUM) { typeNameIndex = reader.readNextShort(); constantNameIndex = reader.readNextShort(); } - else if ( tag == DescriptorDecoder.BASE_TYPE_CLASS ) { + else if (tag == DescriptorDecoder.BASE_TYPE_CLASS) { classInfoIndex = reader.readNextShort(); } - else if ( tag == DescriptorDecoder.BASE_TYPE_ANNOTATION ) { - annotation = new AnnotationJava( reader ); + else if (tag == DescriptorDecoder.BASE_TYPE_ANNOTATION) { + annotation = new AnnotationJava(reader); } - else if ( tag == DescriptorDecoder.BASE_TYPE_ARRAY ) { + else if (tag == DescriptorDecoder.BASE_TYPE_ARRAY) { numberOfValues = reader.readNextShort(); - values = new AnnotationElementValue[ numberOfValues ]; - for ( int i = 0 ; i < numberOfValues ; ++i ) { - values[ i ] = new AnnotationElementValue( reader ); + values = new AnnotationElementValue[numberOfValues & 0xffff]; + for (int i = 0; i < (numberOfValues & 0xffff); ++i) { + values[i] = new AnnotationElementValue(reader); } } } @@ -138,8 +135,8 @@ public class AnnotationElementValue implements StructConverter { * for the field type designated by the tag item, as specified in Table 4.24. * @return a valid index into the constant_pool table */ - public short getConstantValueIndex() { - return constantValueIndex; + public int getConstantValueIndex() { + return constantValueIndex & 0xffff; } /** @@ -151,11 +148,11 @@ public class AnnotationElementValue implements StructConverter { * element_value structure. * @return a valid index into the constant_pool table */ - public short getTypeNameIndex() { - if ( tag != DescriptorDecoder.BASE_TYPE_ENUM ) { + public int getTypeNameIndex() { + if (tag != DescriptorDecoder.BASE_TYPE_ENUM) { throw new IllegalArgumentException(); } - return typeNameIndex; + return typeNameIndex & 0xffff; } /** @@ -166,11 +163,11 @@ public class AnnotationElementValue implements StructConverter { * structure. * @return a valid index into the constant_pool table */ - public short getConstantNameIndex() { - if ( tag != DescriptorDecoder.BASE_TYPE_ENUM ) { + public int getConstantNameIndex() { + if (tag != DescriptorDecoder.BASE_TYPE_ENUM) { throw new IllegalArgumentException(); } - return constantNameIndex; + return constantNameIndex & 0xffff; } /** @@ -183,8 +180,8 @@ public class AnnotationElementValue implements StructConverter { * For example, 'V' for Void.class, 'Ljava/lang/Object;' for Object, etc. * @return a valid index into the constant_pool table */ - public short getClassInfoIndex() { - return classInfoIndex; + public int getClassInfoIndex() { + return classInfoIndex & 0xffff; } /** @@ -206,32 +203,29 @@ public class AnnotationElementValue implements StructConverter { * array-typed value represented by this element_value structure. * @return nested element value table */ - public AnnotationElementValue [] getValues() { + public AnnotationElementValue[] getValues() { return values; } @Override public DataType toDataType() throws DuplicateNameException, IOException { - String name = "element_value" +"|" + tag + "|"; - StructureDataType structure = new StructureDataType( name, 0 ); + String name = "element_value" + "|" + tag + "|"; + StructureDataType structure = new StructureDataType(name, 0); - if ( tag == DescriptorDecoder.BASE_TYPE_BYTE || - tag == DescriptorDecoder.BASE_TYPE_CHAR || - tag == DescriptorDecoder.BASE_TYPE_INT || - tag == DescriptorDecoder.BASE_TYPE_SHORT || - tag == DescriptorDecoder.BASE_TYPE_LONG || - tag == DescriptorDecoder.BASE_TYPE_FLOAT || - tag == DescriptorDecoder.BASE_TYPE_DOUBLE || - tag == DescriptorDecoder.BASE_TYPE_BOOLEAN || - tag == DescriptorDecoder.BASE_TYPE_STRING ) { + if (tag == DescriptorDecoder.BASE_TYPE_BYTE || tag == DescriptorDecoder.BASE_TYPE_CHAR || + tag == DescriptorDecoder.BASE_TYPE_INT || tag == DescriptorDecoder.BASE_TYPE_SHORT || + tag == DescriptorDecoder.BASE_TYPE_LONG || tag == DescriptorDecoder.BASE_TYPE_FLOAT || + tag == DescriptorDecoder.BASE_TYPE_DOUBLE || + tag == DescriptorDecoder.BASE_TYPE_BOOLEAN || + tag == DescriptorDecoder.BASE_TYPE_STRING) { } - else if ( tag == DescriptorDecoder.BASE_TYPE_ENUM ) { + else if (tag == DescriptorDecoder.BASE_TYPE_ENUM) { } - else if ( tag == DescriptorDecoder.BASE_TYPE_CLASS ) { + else if (tag == DescriptorDecoder.BASE_TYPE_CLASS) { } - else if ( tag == DescriptorDecoder.BASE_TYPE_ANNOTATION ) { + else if (tag == DescriptorDecoder.BASE_TYPE_ANNOTATION) { } - else if ( tag == DescriptorDecoder.BASE_TYPE_ARRAY ) { + else if (tag == DescriptorDecoder.BASE_TYPE_ARRAY) { } return structure; diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AnnotationElementValuePair.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AnnotationElementValuePair.java index 31b72f549e..b8fd91a5ff 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AnnotationElementValuePair.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AnnotationElementValuePair.java @@ -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 *

@@ -43,9 +42,9 @@ public class AnnotationElementValuePair implements StructConverter { private short elementNameIndex; private AnnotationElementValue value; - public AnnotationElementValuePair( BinaryReader reader ) throws IOException { + public AnnotationElementValuePair(BinaryReader reader) throws IOException { elementNameIndex = reader.readNextShort(); - value = new AnnotationElementValue( reader ); + value = new AnnotationElementValue(reader); } /** @@ -56,8 +55,8 @@ public class AnnotationElementValuePair implements StructConverter { * element represented by this element_value_pairs entry. * @return a valid index into the constant_pool table */ - public short getElementNameIndex() { - return elementNameIndex; + public int getElementNameIndex() { + return elementNameIndex & 0xffff; } /** @@ -71,9 +70,9 @@ public class AnnotationElementValuePair implements StructConverter { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType structure = new StructureDataType( "element_value_pair", 0 ); - structure.add( WORD, "element_name_index", null ); - structure.add( value.toDataType(), "element_value_pair", null ); + StructureDataType structure = new StructureDataType("element_value_pair", 0); + structure.add(WORD, "element_name_index", null); + structure.add(value.toDataType(), "element_value_pair", null); return structure; } } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AnnotationJava.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AnnotationJava.java index 507bcfa5d8..d8d6c0ded7 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AnnotationJava.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AnnotationJava.java @@ -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 *

@@ -45,14 +45,14 @@ public class AnnotationJava implements StructConverter { private short typeIndex; private short numberOfElementValuePairs; - private AnnotationElementValuePair [] elementValuePairs; + private AnnotationElementValuePair[] elementValuePairs; - public AnnotationJava( BinaryReader reader ) throws IOException { + public AnnotationJava(BinaryReader reader) throws IOException { typeIndex = reader.readNextShort(); numberOfElementValuePairs = reader.readNextShort(); - elementValuePairs = new AnnotationElementValuePair[ numberOfElementValuePairs ]; - for ( int i = 0 ; i < numberOfElementValuePairs ; ++i ) { - elementValuePairs[ i ] = new AnnotationElementValuePair( reader ); + elementValuePairs = new AnnotationElementValuePair[getNumberOfElementValuePairs()]; + for (int i = 0; i < getNumberOfElementValuePairs(); ++i) { + elementValuePairs[i] = new AnnotationElementValuePair(reader); } } @@ -64,8 +64,8 @@ public class AnnotationJava implements StructConverter { * represented by this annotation structure. * @return valid index into the constant_pool table */ - public short getTypeIndex() { - return typeIndex; + public int getTypeIndex() { + return typeIndex & 0xffff; } /** @@ -77,26 +77,26 @@ public class AnnotationJava implements StructConverter { * annotation. * @return the number of element-value pairs of the annotation */ - public short getNumberOfElementValuePairs() { - return numberOfElementValuePairs; + public int getNumberOfElementValuePairs() { + return numberOfElementValuePairs & 0xffff; } /** * Returns the element value pair table for this annotation. * @return the element value pair table */ - public AnnotationElementValuePair [] getElementValuePairs() { + public AnnotationElementValuePair[] getElementValuePairs() { return elementValuePairs; } @Override public DataType toDataType() throws DuplicateNameException, IOException { - String name = "annotation" +"|" + numberOfElementValuePairs + "|"; - StructureDataType structure = new StructureDataType( name, 0 ); - structure.add( WORD, "type_index", null ); - structure.add( WORD, "num_element_value_pairs", null ); - for ( int i = 0 ; i < elementValuePairs.length ; ++i ) { - structure.add( elementValuePairs[ i ].toDataType(), "element_value_pair_" + i, null ); + String name = "annotation" + "|" + numberOfElementValuePairs + "|"; + StructureDataType structure = new StructureDataType(name, 0); + structure.add(WORD, "type_index", null); + structure.add(WORD, "num_element_value_pairs", null); + for (int i = 0; i < elementValuePairs.length; ++i) { + structure.add(elementValuePairs[i].toDataType(), "element_value_pair_" + i, null); } return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AttributeFactory.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AttributeFactory.java index 16269bdf3e..48b56b0a31 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AttributeFactory.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AttributeFactory.java @@ -15,90 +15,82 @@ */ package ghidra.javaclass.format.attributes; +import java.io.IOException; + import ghidra.app.util.bin.BinaryReader; import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava; import ghidra.javaclass.format.constantpool.ConstantPoolUtf8Info; -import java.io.IOException; - public class AttributeFactory { - public static AbstractAttributeInfo get( BinaryReader reader, AbstractConstantPoolInfoJava [] constantPool ) throws IOException { - - int attributeNameIndex = reader.readShort( reader.getPointerIndex() ); + public static AbstractAttributeInfo get(BinaryReader reader, + AbstractConstantPoolInfoJava[] constantPool) throws IOException { - if ( attributeNameIndex < 1 || attributeNameIndex >= constantPool.length ) { - throw new RuntimeException( "invalid index"); + int attributeNameIndex = reader.readShort(reader.getPointerIndex()); + + if (attributeNameIndex < 1 || attributeNameIndex >= constantPool.length) { + throw new RuntimeException("invalid index"); } - if ( !( constantPool[ attributeNameIndex ] instanceof ConstantPoolUtf8Info ) ) { + if (!(constantPool[attributeNameIndex] instanceof ConstantPoolUtf8Info)) { throw new RuntimeException(); } - ConstantPoolUtf8Info utf8 = (ConstantPoolUtf8Info) constantPool[ attributeNameIndex ]; + ConstantPoolUtf8Info utf8 = (ConstantPoolUtf8Info) constantPool[attributeNameIndex]; - if ( utf8.getString().equals( AttributesConstants.ConstantValue ) ) { - return new ConstantValueAttribute( reader ); + switch (utf8.getString()) { + case AttributesConstants.AnnotationDefault: + return new AnnotationDefaultAttribute(reader); + case AttributesConstants.BootstrapMethods: + return new BootstrapMethodsAttribute(reader); + case AttributesConstants.Code: + return new CodeAttribute(reader, constantPool); + case AttributesConstants.ConstantValue: + return new ConstantValueAttribute(reader); + case AttributesConstants.Deprecated: + return new DeprecatedAttribute(reader); + case AttributesConstants.EnclosingMethod: + return new EnclosingMethodAttribute(reader); + case AttributesConstants.Exceptions: + return new ExceptionsAttribute(reader); + case AttributesConstants.InnerClasses: + return new InnerClassesAttribute(reader); + case AttributesConstants.LineNumberTable: + return new LineNumberTableAttribute(reader); + case AttributesConstants.LocalVariableTable: + return new LocalVariableTableAttribute(reader, constantPool); + case AttributesConstants.LocalVariableTypeTable: + return new LocalVariableTypeTableAttribute(reader); + case AttributesConstants.ModuleMainClass: + return new ModuleMainClassAttribute(reader); + case AttributesConstants.ModulePackages: + return new ModulePackagesAttribute(reader); + case AttributesConstants.NestHost: + return new NestHostAttribute(reader); + case AttributesConstants.NestMembers: + return new NestMembersAttribute(reader); + case AttributesConstants.RuntimeInvisibleAnnotations: + return new RuntimeInvisibleAnnotationsAttribute(reader); + case AttributesConstants.RuntimeInvisibleParameterAnnotations: + return new RuntimeParameterAnnotationsAttribute(reader, false /*invisible*/ ); + case AttributesConstants.RuntimeVisibleAnnotations: + return new RuntimeVisibleAnnotationsAttribute(reader); + case AttributesConstants.RuntimeVisibleParameterAnnotations: + return new RuntimeParameterAnnotationsAttribute(reader, true /*visible*/ ); + case AttributesConstants.Signature: + return new SignatureAttribute(reader); + case AttributesConstants.SourceDebugExtension: + return new SourceDebugExtensionAttribute(reader); + case AttributesConstants.SourceFile: + return new SourceFileAttribute(reader); + case AttributesConstants.StackMapTable: + return new StackMapTableAttribute(reader); + case AttributesConstants.Synthetic: + return new SyntheticAttribute(reader); + case AttributesConstants.Module: + return new ModuleAttribute(reader); + default: + throw new RuntimeException("Unknown attribute type: " + utf8.getString()); } - else if ( utf8.getString().equals( AttributesConstants.Code ) ) { - return new CodeAttribute( reader, constantPool ); - } - else if ( utf8.getString().equals( AttributesConstants.StackMapTable ) ) { - return new StackMapTableAttribute( reader ); - } - else if ( utf8.getString().equals( AttributesConstants.Exceptions ) ) { - return new ExceptionsAttribute( reader ); - } - else if ( utf8.getString().equals( AttributesConstants.InnerClasses ) ) { - return new InnerClassesAttribute( reader ); - } - else if ( utf8.getString().equals( AttributesConstants.EnclosingMethod ) ) { - return new EnclosingMethodAttribute( reader ); - } - else if ( utf8.getString().equals( AttributesConstants.Synthetic ) ) { - return new SyntheticAttribute( reader ); - } - else if ( utf8.getString().equals( AttributesConstants.Signature ) ) { - return new SignatureAttribute( reader ); - } - else if ( utf8.getString().equals( AttributesConstants.SourceFile ) ) { - return new SourceFileAttribute( reader ); - } - else if ( utf8.getString().equals( AttributesConstants.SourceDebugExtension ) ) { - return new SourceDebugExtensionAttribute( reader ); - } - else if ( utf8.getString().equals( AttributesConstants.LineNumberTable ) ) { - return new LineNumberTableAttribute( reader ); - } - else if ( utf8.getString().equals( AttributesConstants.LocalVariableTable ) ) { - return new LocalVariableTableAttribute( reader, constantPool ); - } - else if ( utf8.getString().equals( AttributesConstants.LocalVariableTypeTable ) ) { - return new LocalVariableTypeTableAttribute( reader ); - } - else if ( utf8.getString().equals( AttributesConstants.Deprecated ) ) { - return new DeprecatedAttribute( reader ); - } - else if ( utf8.getString().equals( AttributesConstants.RuntimeVisibleAnnotations ) ) { - return new RuntimeVisibleAnnotationsAttribute( reader ); - } - else if ( utf8.getString().equals( AttributesConstants.RuntimeInvisibleAnnotations ) ) { - return new RuntimeInvisibleAnnotationsAttribute( reader ); - } - else if ( utf8.getString().equals( AttributesConstants.RuntimeVisibleParameterAnnotations ) ) { - return new RuntimeParameterAnnotationsAttribute( reader, true /*visible*/ ); - } - else if ( utf8.getString().equals( AttributesConstants.RuntimeInvisibleParameterAnnotations ) ) { - return new RuntimeParameterAnnotationsAttribute( reader, false /*invisible*/ ); - } - else if ( utf8.getString().equals( AttributesConstants.AnnotationDefault ) ) { - return new AnnotationDefaultAttribute( reader ); - } - else if ( utf8.getString().equals( AttributesConstants.BootstrapMethods ) ) { - return new BootstrapMethodsAttribute( reader ); - } - - throw new RuntimeException( "Unknown attribute type: " + utf8.getString() ); } - } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AttributesConstants.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AttributesConstants.java index 4c3a741e02..3d748dc820 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AttributesConstants.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/AttributesConstants.java @@ -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"; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/BootstrapMethods.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/BootstrapMethods.java index 266a4dab07..5cd3f1fefc 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/BootstrapMethods.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/BootstrapMethods.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,9 +19,7 @@ import java.io.IOException; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.StructConverter; -import ghidra.program.model.data.ArrayDataType; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.StructureDataType; +import ghidra.program.model.data.*; import ghidra.util.exception.DuplicateNameException; /** @@ -34,12 +31,12 @@ public class BootstrapMethods implements StructConverter { private short bootstrapMethodsReference; private short numberOfBootstrapArguments; - private short [] bootstrapArguments; + private short[] bootstrapArguments; - public BootstrapMethods( BinaryReader reader ) throws IOException { + public BootstrapMethods(BinaryReader reader) throws IOException { bootstrapMethodsReference = reader.readNextShort(); numberOfBootstrapArguments = reader.readNextShort(); - bootstrapArguments = reader.readNextShortArray( numberOfBootstrapArguments & 0xffff ); + bootstrapArguments = reader.readNextShortArray(getNumberOfBootstrapArguments()); } /** @@ -55,8 +52,8 @@ public class BootstrapMethods implements StructConverter { * * @return a valid index into the constant_pool table */ - public short getBootstrapMethodsReference() { - return bootstrapMethodsReference; + public int getBootstrapMethodsReference() { + return bootstrapMethodsReference & 0xffff; } /** @@ -64,8 +61,8 @@ public class BootstrapMethods implements StructConverter { * items in the bootstrap_arguments array. * @return the number of items in the bootstrap_arguments array */ - public short getNumberOfBootstrapArguments() { - return numberOfBootstrapArguments; + public int getNumberOfBootstrapArguments() { + return numberOfBootstrapArguments & 0xffff; } /** @@ -80,20 +77,21 @@ public class BootstrapMethods implements StructConverter { * CONSTANT_Double_info, * CONSTANT_MethodHandle_info, or * CONSTANT_MethodType_info structure. - * @return + * @param i entry + * @return index */ - public short [] getBootstrapArguments() { - return bootstrapArguments; + public int getBootstrapArgumentsEntry(int i) { + return bootstrapArguments[i] & 0xffff; } @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType structure = new StructureDataType( "bootstrap_methods", 0 ); - structure.add( WORD, "bootstrap_method_ref", null ); - structure.add( WORD, "num_bootstrap_arguments", null ); - if ( numberOfBootstrapArguments > 0 ) { - DataType array = new ArrayDataType( WORD, numberOfBootstrapArguments, WORD.getLength() ); - structure.add( array, "bootstrapArguments", null ); + StructureDataType structure = new StructureDataType("bootstrap_methods", 0); + structure.add(WORD, "bootstrap_method_ref", null); + structure.add(WORD, "num_bootstrap_arguments", null); + if (numberOfBootstrapArguments > 0) { + DataType array = new ArrayDataType(WORD, numberOfBootstrapArguments, WORD.getLength()); + structure.add(array, "bootstrapArguments", null); } return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/BootstrapMethodsAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/BootstrapMethodsAttribute.java index 4a673cb5b3..6a903d3cd9 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/BootstrapMethodsAttribute.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/BootstrapMethodsAttribute.java @@ -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 *

@@ -55,33 +55,33 @@ import java.io.IOException; public class BootstrapMethodsAttribute extends AbstractAttributeInfo { private short numberOfBootstrapMethods; - private BootstrapMethods [] bootstrapMethods; + private BootstrapMethods[] bootstrapMethods; - public BootstrapMethodsAttribute( BinaryReader reader ) throws IOException { + public BootstrapMethodsAttribute(BinaryReader reader) throws IOException { super(reader); numberOfBootstrapMethods = reader.readNextShort(); - bootstrapMethods = new BootstrapMethods[ numberOfBootstrapMethods ]; - for ( int i = 0 ; i < numberOfBootstrapMethods ; ++i ) { - bootstrapMethods[ i ] = new BootstrapMethods( reader ); + bootstrapMethods = new BootstrapMethods[getNumberOfBootstrapMethods()]; + for (int i = 0; i < getNumberOfBootstrapMethods(); ++i) { + bootstrapMethods[i] = new BootstrapMethods(reader); } } - public short getNumberOfBootstrapMethods() { - return numberOfBootstrapMethods; + public int getNumberOfBootstrapMethods() { + return numberOfBootstrapMethods & 0xffff; } - - public BootstrapMethods[] getBootstrapMethods(){ + + public BootstrapMethods[] getBootstrapMethods() { return bootstrapMethods; } @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType structure = getBaseStructure( "BootstrapMethods_attribute" ); - structure.add( WORD, "num_bootstrap_methods", null ); - for ( int i = 0 ; i < bootstrapMethods.length ; ++i ) { - structure.add( bootstrapMethods[ i ].toDataType(), "bootstrap_methods" + i, null ); + StructureDataType structure = getBaseStructure("BootstrapMethods_attribute"); + structure.add(WORD, "num_bootstrap_methods", null); + for (int i = 0; i < bootstrapMethods.length; ++i) { + structure.add(bootstrapMethods[i].toDataType(), "bootstrap_methods" + i, null); } return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/CodeAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/CodeAttribute.java index 5fb3e87956..ed1f2c7b08 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/CodeAttribute.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/CodeAttribute.java @@ -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 *

@@ -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; } /** diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ConstantValueAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ConstantValueAttribute.java index b748154a77..ec7df773a4 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ConstantValueAttribute.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ConstantValueAttribute.java @@ -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 *

@@ -56,8 +55,8 @@ public class ConstantValueAttribute extends AbstractAttributeInfo { private short constantValueIndex; - public ConstantValueAttribute( BinaryReader reader ) throws IOException { - super( reader ); + public ConstantValueAttribute(BinaryReader reader) throws IOException { + super(reader); constantValueIndex = reader.readNextShort(); } @@ -80,15 +79,15 @@ public class ConstantValueAttribute extends AbstractAttributeInfo { * * @return a valid index into the constant_pool table */ - public short getConstantValueIndex() { - return constantValueIndex; + public int getConstantValueIndex() { + return constantValueIndex & 0xffff; } @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType structure = getBaseStructure( "ConstantValue_attribute" ); - structure.add( WORD, "constantvalue_index", null ); + StructureDataType structure = getBaseStructure("ConstantValue_attribute"); + structure.add(WORD, "constantvalue_index", null); return structure; } - + } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/EnclosingMethodAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/EnclosingMethodAttribute.java index 5efc5d250e..d7fd93d50f 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/EnclosingMethodAttribute.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/EnclosingMethodAttribute.java @@ -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 *

@@ -46,8 +45,8 @@ public class EnclosingMethodAttribute extends AbstractAttributeInfo { private short classIndex; private short methodIndex; - public EnclosingMethodAttribute( BinaryReader reader ) throws IOException { - super( reader ); + public EnclosingMethodAttribute(BinaryReader reader) throws IOException { + super(reader); classIndex = reader.readNextShort(); methodIndex = reader.readNextShort(); @@ -60,8 +59,8 @@ public class EnclosingMethodAttribute extends AbstractAttributeInfo { * encloses the declaration of the current class. * @return a valid index into the constant_pool table */ - public short getClassIndex() { - return classIndex; + public int getClassIndex() { + return classIndex & 0xffff; } /** @@ -74,15 +73,15 @@ public class EnclosingMethodAttribute extends AbstractAttributeInfo { * type of a method in the class referenced by the class_index attribute above. * @return a valid index into the constant_pool table, or zero */ - public short getMethodIndex() { - return methodIndex; + public int getMethodIndex() { + return methodIndex & 0xffff; } @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType structure = getBaseStructure( "EnclosingMethod_attribute" ); - structure.add( WORD, "class_index", null ); - structure.add( WORD, "method_index", null ); + StructureDataType structure = getBaseStructure("EnclosingMethod_attribute"); + structure.add(WORD, "class_index", null); + structure.add(WORD, "method_index", null); return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ExceptionHandlerJava.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ExceptionHandlerJava.java index 5112e610f3..ec2fc1f2f7 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ExceptionHandlerJava.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ExceptionHandlerJava.java @@ -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 *

@@ -32,10 +32,10 @@ public class ExceptionHandlerJava implements StructConverter { private short endPC; private short handlerPC; private short catchType; - - public ExceptionHandlerJava( BinaryReader reader ) throws IOException { - startPC = reader.readNextShort(); - endPC = reader.readNextShort(); + + public ExceptionHandlerJava(BinaryReader reader) throws IOException { + startPC = reader.readNextShort(); + endPC = reader.readNextShort(); handlerPC = reader.readNextShort(); catchType = reader.readNextShort(); } @@ -54,9 +54,10 @@ public class ExceptionHandlerJava implements StructConverter { * [start_pc, end_pc]. * @return a valid index into the code array */ - public short getStartPC() { - return startPC; + public int getStartPC() { + return startPC & 0xffff; } + /** * The values of the two items start_pc and end_pc indicate the ranges in the * code array at which the exception handler is active. @@ -72,18 +73,20 @@ public class ExceptionHandlerJava implements StructConverter { * [start_pc, end_pc]. * @return a valid index into the code array */ - public short getEndPC() { - return endPC; + public int getEndPC() { + return endPC & 0xffff; } + /** * The value of the handler_pc item indicates the start of the exception * handler. The value of the item must be a valid index into the code array * and must be the index of the opcode of an instruction. * @return the start of the exception handler */ - public short getHandlerPC() { - return handlerPC; + public int getHandlerPC() { + return handlerPC & 0xffff; } + /** * If the value of the catch_type item is nonzero, it must be a valid index * into the constant_pool table. The constant_pool entry at that index @@ -96,17 +99,17 @@ public class ExceptionHandlerJava implements StructConverter { * for all exceptions. This is used to implement finally (?3.13). * @return the value of the catch_type item */ - public short getCatchType() { - return catchType; + public int getCatchType() { + return catchType & 0xffff; } @Override public DataType toDataType() throws DuplicateNameException, IOException { - Structure structure = new StructureDataType( "exception_handler", 0 ); - structure.add( WORD, "start_pc", null ); - structure.add( WORD, "end_pc", null ); - structure.add( WORD, "handler_pc", null ); - structure.add( WORD, "catch_type", null ); + Structure structure = new StructureDataType("exception_handler", 0); + structure.add(WORD, "start_pc", null); + structure.add(WORD, "end_pc", null); + structure.add(WORD, "handler_pc", null); + structure.add(WORD, "catch_type", null); return structure; } } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ExceptionsAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ExceptionsAttribute.java index 0040f8073f..4f3cb6dd60 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ExceptionsAttribute.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ExceptionsAttribute.java @@ -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 *

@@ -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 diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/InnerClass.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/InnerClass.java index fa731e3999..611ce2b5f3 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/InnerClass.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/InnerClass.java @@ -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 *

@@ -44,7 +43,7 @@ public class InnerClass implements StructConverter { private short innerNameIndex; private short innerClassAccessFlags; - public InnerClass( BinaryReader reader ) throws IOException { + public InnerClass(BinaryReader reader) throws IOException { innerClassInfoIndex = reader.readNextShort(); outerClassInfoIndex = reader.readNextShort(); innerNameIndex = reader.readNextShort(); @@ -58,8 +57,8 @@ public class InnerClass implements StructConverter { * items in the classes array entry give information about C. * @return a valid index into the constant_pool table */ - public short getInnerClassInfoIndex() { - return innerClassInfoIndex; + public int getInnerClassInfoIndex() { + return innerClassInfoIndex & 0xffff; } /** @@ -74,8 +73,8 @@ public class InnerClass implements StructConverter { * interface of which C is a member. * @return a valid index into the constant_pool table, or zero */ - public short getOuterClassInfoIndex() { - return outerClassInfoIndex; + public int getOuterClassInfoIndex() { + return outerClassInfoIndex & 0xffff; } /** @@ -88,8 +87,8 @@ public class InnerClass implements StructConverter { * compiled. * @return a valid index into the constant_pool table, or zero */ - public short getInnerNameIndex() { - return innerNameIndex; + public int getInnerNameIndex() { + return innerNameIndex & 0xffff; } /** @@ -107,11 +106,11 @@ public class InnerClass implements StructConverter { @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType structure = new StructureDataType( "inner_class", 0 ); - structure.add( WORD, "inner_class_info_index", null ); - structure.add( WORD, "outer_class_info_index", null ); - structure.add( WORD, "inner_name_index", null ); - structure.add( WORD, "inner_class_access_flags", null ); + StructureDataType structure = new StructureDataType("inner_class", 0); + structure.add(WORD, "inner_class_info_index", null); + structure.add(WORD, "outer_class_info_index", null); + structure.add(WORD, "inner_name_index", null); + structure.add(WORD, "inner_class_access_flags", null); return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/InnerClassesAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/InnerClassesAttribute.java index 9aa74c5d0b..0a5b0886e1 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/InnerClassesAttribute.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/InnerClassesAttribute.java @@ -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 *

@@ -50,15 +49,15 @@ import java.io.IOException; public class InnerClassesAttribute extends AbstractAttributeInfo { private short numberOfInnerClasses; - private InnerClass [] innerClasses; + private InnerClass[] innerClasses; - public InnerClassesAttribute( BinaryReader reader ) throws IOException { - super( reader ); + public InnerClassesAttribute(BinaryReader reader) throws IOException { + super(reader); numberOfInnerClasses = reader.readNextShort(); - innerClasses = new InnerClass[ numberOfInnerClasses ]; - for ( int i = 0 ; i < numberOfInnerClasses ; i++ ) { - innerClasses[ i ] = new InnerClass( reader ); + innerClasses = new InnerClass[getNumberOfInnerClasses()]; + for (int i = 0; i < getNumberOfInnerClasses(); i++) { + innerClasses[i] = new InnerClass(reader); } } @@ -66,25 +65,26 @@ public class InnerClassesAttribute extends AbstractAttributeInfo { * The value of the number_of_classes item indicates the number of entries in * the classes array. * @return the number of entries in the classes array - */ - public short getNumberOfInnerClasses() { - return numberOfInnerClasses; + */ + public int getNumberOfInnerClasses() { + return numberOfInnerClasses & 0xffff; } /** * Returns array of inner classes. * @return array of inner classes. */ - public InnerClass [] getInnerClasses() { + public InnerClass[] getInnerClasses() { return innerClasses; } @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType structure = getBaseStructure( "InnerClasses_attribute" + "|" + numberOfInnerClasses + "|" ); - structure.add( WORD, "number_of_classes", null ); - for ( int i = 0 ; i < innerClasses.length ; ++i ) { - structure.add( innerClasses[ i ].toDataType(), "inner_class_" + i, null ); + StructureDataType structure = + getBaseStructure("InnerClasses_attribute" + "|" + numberOfInnerClasses + "|"); + structure.add(WORD, "number_of_classes", null); + for (int i = 0; i < innerClasses.length; ++i) { + structure.add(innerClasses[i].toDataType(), "inner_class_" + i, null); } return structure; diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LineNumber.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LineNumber.java index c17f42107a..1494784ddb 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LineNumber.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LineNumber.java @@ -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 *

@@ -40,7 +39,7 @@ public class LineNumber implements StructConverter { private short startPC; private short lineNumber; - public LineNumber( BinaryReader reader ) throws IOException { + public LineNumber(BinaryReader reader) throws IOException { startPC = reader.readNextShort(); lineNumber = reader.readNextShort(); } @@ -53,23 +52,23 @@ public class LineNumber implements StructConverter { * item of the Code attribute of which this LineNumberTable is an attribute. * @return index into the code array at which the code for a new line in the original source file begins */ - public short getStartPC() { - return startPC; + public int getStartPC() { + return startPC & 0xffff; } /** * The value of the line_number item must give the corresponding line number in the original source file. * @return the corresponding line number in the original source file */ - public short getLineNumber() { - return lineNumber; + public int getLineNumber() { + return lineNumber & 0xffff; } @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType structure = new StructureDataType( "line_number", 0 ); - structure.add( WORD, "start_pc", null ); - structure.add( WORD, "line_number", null ); + StructureDataType structure = new StructureDataType("line_number", 0); + structure.add(WORD, "start_pc", null); + structure.add(WORD, "line_number", null); return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LineNumberTableAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LineNumberTableAttribute.java index c070c3aac2..4ad41753e3 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LineNumberTableAttribute.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LineNumberTableAttribute.java @@ -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 *

@@ -52,25 +51,25 @@ import java.io.IOException; public class LineNumberTableAttribute extends AbstractAttributeInfo { private short lineNumberTableLength; - private LineNumber [] lineNumberTable; + private LineNumber[] lineNumberTable; - public LineNumberTableAttribute( BinaryReader reader ) throws IOException { - super( reader ); + public LineNumberTableAttribute(BinaryReader reader) throws IOException { + super(reader); lineNumberTableLength = reader.readNextShort(); - lineNumberTable = new LineNumber[ lineNumberTableLength ]; - for ( int i = 0 ; i < lineNumberTableLength ; i++ ) { - lineNumberTable[ i ] = new LineNumber( reader ); + lineNumberTable = new LineNumber[lineNumberTableLength & 0xffff]; + for (int i = 0; i < (lineNumberTableLength & 0xffff); i++) { + lineNumberTable[i] = new LineNumber(reader); } } @Override public DataType toDataType() throws DuplicateNameException, IOException { String name = "LineNumberTable_attribute" + "|" + lineNumberTableLength + "|"; - StructureDataType structure = getBaseStructure( name ); - structure.add( WORD, "line_number_table_length", null ); - for ( int i = 0 ; i < lineNumberTable.length ; ++i ) { - structure.add( lineNumberTable[ i ].toDataType(), "line_number_" + i, null ); + StructureDataType structure = getBaseStructure(name); + structure.add(WORD, "line_number_table_length", null); + for (int i = 0; i < lineNumberTable.length; ++i) { + structure.add(lineNumberTable[i].toDataType(), "line_number_" + i, null); } return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LocalVariableJava.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LocalVariableJava.java index 723c9178da..21b2b92ad1 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LocalVariableJava.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LocalVariableJava.java @@ -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 *

@@ -90,12 +90,12 @@ public class LocalVariableJava implements StructConverter { private short descriptorIndex; private short index; - public LocalVariableJava( BinaryReader reader ) throws IOException { - startPC = reader.readNextShort(); - length = reader.readNextShort(); - nameIndex = reader.readNextShort(); + public LocalVariableJava(BinaryReader reader) throws IOException { + startPC = reader.readNextShort(); + length = reader.readNextShort(); + nameIndex = reader.readNextShort(); descriptorIndex = reader.readNextShort(); - index = reader.readNextShort(); + index = reader.readNextShort(); } /** @@ -111,16 +111,16 @@ public class LocalVariableJava implements StructConverter { * or it must be the first index beyond the end of that code array. * @return the start PC */ - public short getStartPC() { - return startPC; + public int getStartPC() { + return startPC & 0xffff; } /** * Returns the length of this local variable in bytes. * @return the length of this local variable in bytes */ - public short getLength() { - return length; + public int getLength() { + return length & 0xffff; } /** @@ -130,8 +130,8 @@ public class LocalVariableJava implements StructConverter { * name denoting a local variable. * @return a valid index into the constant_pool table */ - public short getNameIndex() { - return nameIndex; + public int getNameIndex() { + return nameIndex & 0xffff; } /** @@ -141,8 +141,8 @@ public class LocalVariableJava implements StructConverter { * encoding the type of a local variable in the source program. * @return a valid index into the constant_pool table */ - public short getDescriptorIndex() { - return descriptorIndex; + public int getDescriptorIndex() { + return descriptorIndex & 0xffff; } /** @@ -153,18 +153,18 @@ public class LocalVariableJava implements StructConverter { * index and index + 1. * @return index in the local variable array */ - public short getIndex() { - return index; + public int getIndex() { + return index & 0xffff; } @Override public DataType toDataType() throws DuplicateNameException, IOException { - Structure structure = new StructureDataType( "local_variable", 0 ); - structure.add( WORD, "start_pc", null ); - structure.add( WORD, "length", null ); - structure.add( WORD, "name_index", null ); - structure.add( WORD, "descriptor_index", null ); - structure.add( WORD, "index", null ); + Structure structure = new StructureDataType("local_variable", 0); + structure.add(WORD, "start_pc", null); + structure.add(WORD, "length", null); + structure.add(WORD, "name_index", null); + structure.add(WORD, "descriptor_index", null); + structure.add(WORD, "index", null); return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LocalVariableTableAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LocalVariableTableAttribute.java index b02420152d..431876183b 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LocalVariableTableAttribute.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/LocalVariableTableAttribute.java @@ -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 *

@@ -53,28 +53,29 @@ import java.io.IOException; public class LocalVariableTableAttribute extends AbstractAttributeInfo { private short localVariableTableLength; - private LocalVariableJava [] localVariableTable; + private LocalVariableJava[] localVariableTable; - public LocalVariableTableAttribute( BinaryReader reader, AbstractConstantPoolInfoJava [] constantPool ) throws IOException { - super( reader ); + public LocalVariableTableAttribute(BinaryReader reader, + AbstractConstantPoolInfoJava[] constantPool) throws IOException { + super(reader); localVariableTableLength = reader.readNextShort(); - localVariableTable = new LocalVariableJava[ localVariableTableLength ]; - for ( int i = 0 ; i < localVariableTableLength ; i++ ) { - localVariableTable[ i ] = new LocalVariableJava( reader ); + localVariableTable = new LocalVariableJava[localVariableTableLength & 0xffff]; + for (int i = 0; i < (localVariableTableLength & 0xffff); i++) { + localVariableTable[i] = new LocalVariableJava(reader); } } - public LocalVariableJava [] getLocalVariables() { + public LocalVariableJava[] getLocalVariables() { return localVariableTable; } @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType structure = getBaseStructure( "LocalVariableTable_attribute" ); - structure.add( WORD, "local_variable_table_length", null ); - for ( int i = 0 ; i < localVariableTable.length ; ++i ) { - structure.add( localVariableTable[ i ].toDataType(), "local_variable_" + i, null ); + StructureDataType structure = getBaseStructure("LocalVariableTable_attribute"); + structure.add(WORD, "local_variable_table_length", null); + for (int i = 0; i < localVariableTable.length; ++i) { + structure.add(localVariableTable[i].toDataType(), "local_variable_" + i, null); } return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ModuleAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ModuleAttribute.java new file mode 100644 index 0000000000..e74c868324 --- /dev/null +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ModuleAttribute.java @@ -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 + *

+ * The {@code Module} attribute indicates: + *

    + *
  • the modules required by a module
  • + *
  • the packages exported and opened by a module
  • + *
  • the services used and provided by a module
  • + *
+ */ +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: + *
    + *
  • 0x0020 (ACC_OPEN): indicates that this module is open
  • + *
  • 0x10000 (ACC_SYNTHETIC): Indicates that this module was not explicitly or implicitly + * declared
  • + *
  • 0x8000 (ACC_MANDATED) indicates that this module was implicitly declared
  • + *
+ * @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: + *
    + *
  • 0x0020 ACC_TRANSITIVE
  • + *
  • 0x0040 ACC_STATIC_PHASE
  • + *
  • 0x1000 ACC_SYNTHETIC
  • + *
  • 0x8000 ACC_MANDATED
  • + *
+ * @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: + *
    + *
  • 0x1000 (ACC_SYNTHETIC)
  • + *
  • 0x8000 (ACC_MANDATED)
  • + *
+ * @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: + *
    + *
  • 0x1000 (ACC_SYNTHETIC)
  • + *
  • 0x8000 (ACC_MANDATED)
  • + *
+ * @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; + } + + } + +} diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ModuleMainClassAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ModuleMainClassAttribute.java new file mode 100644 index 0000000000..ccc71ee2fa --- /dev/null +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ModuleMainClassAttribute.java @@ -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 + *

+ * 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; + } + +} diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ModulePackagesAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ModulePackagesAttribute.java new file mode 100644 index 0000000000..b0985c927c --- /dev/null +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/ModulePackagesAttribute.java @@ -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 + *

+ * 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; + } + +} diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/NestHostAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/NestHostAttribute.java new file mode 100644 index 0000000000..43a00f603f --- /dev/null +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/NestHostAttribute.java @@ -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 + *

+ * 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; + } + +} diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/NestMembersAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/NestMembersAttribute.java new file mode 100644 index 0000000000..79ba41430d --- /dev/null +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/NestMembersAttribute.java @@ -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 + *

+ * 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; + } + +} diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/RuntimeInvisibleAnnotationsAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/RuntimeInvisibleAnnotationsAttribute.java index 312fab4d4c..6c5acd0976 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/RuntimeInvisibleAnnotationsAttribute.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/RuntimeInvisibleAnnotationsAttribute.java @@ -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 *

@@ -52,17 +52,17 @@ import java.io.IOException; public class RuntimeInvisibleAnnotationsAttribute extends AbstractAttributeInfo { private short numberOfAnnotations; - private AnnotationJava [] annotations; + private AnnotationJava[] annotations; - public RuntimeInvisibleAnnotationsAttribute( BinaryReader reader ) throws IOException { - super( reader ); + public RuntimeInvisibleAnnotationsAttribute(BinaryReader reader) throws IOException { + super(reader); numberOfAnnotations = reader.readNextShort(); - annotations = new AnnotationJava[ numberOfAnnotations ]; + annotations = new AnnotationJava[getNumberOfAnnotations()]; - for ( int i = 0 ; i < numberOfAnnotations ; ++i ) { - annotations[ i ] = new AnnotationJava( reader ); + for (int i = 0; i < getNumberOfAnnotations(); ++i) { + annotations[i] = new AnnotationJava(reader); } } @@ -74,8 +74,8 @@ public class RuntimeInvisibleAnnotationsAttribute extends AbstractAttributeInfo * may be directly attached to a program element. * @return the number of runtime-visible annotations */ - public short getNumberOfAnnotations() { - return numberOfAnnotations; + public int getNumberOfAnnotations() { + return numberOfAnnotations & 0xffff; } /** @@ -83,17 +83,17 @@ public class RuntimeInvisibleAnnotationsAttribute extends AbstractAttributeInfo * annotation on a program element. * @return the annotations table */ - public AnnotationJava [] getAnnotations() { + public AnnotationJava[] getAnnotations() { return annotations; } @Override public DataType toDataType() throws DuplicateNameException, IOException { - String name = "RuntimeInvisibleAnnotations_attribute" +"|" + numberOfAnnotations + "|"; - StructureDataType structure = getBaseStructure( name ); - structure.add( WORD, "num_annotations", null ); - for ( int i = 0 ; i < annotations.length ; ++i ) { - structure.add( annotations[ i ].toDataType(), "annotation_" + i, null ); + String name = "RuntimeInvisibleAnnotations_attribute" + "|" + numberOfAnnotations + "|"; + StructureDataType structure = getBaseStructure(name); + structure.add(WORD, "num_annotations", null); + for (int i = 0; i < annotations.length; ++i) { + structure.add(annotations[i].toDataType(), "annotation_" + i, null); } return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/RuntimeParameterAnnotationsAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/RuntimeParameterAnnotationsAttribute.java index 1c20fa5442..bafa1028ef 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/RuntimeParameterAnnotationsAttribute.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/RuntimeParameterAnnotationsAttribute.java @@ -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 *

@@ -65,22 +65,24 @@ public class RuntimeParameterAnnotationsAttribute extends AbstractAttributeInfo private boolean _isVisible; private byte numberOfParameters; - private Map parameterAnnotations = new HashMap(); + private Map parameterAnnotations = + new HashMap(); - public RuntimeParameterAnnotationsAttribute( BinaryReader reader, boolean isVisible ) throws IOException { - super( reader ); + public RuntimeParameterAnnotationsAttribute(BinaryReader reader, boolean isVisible) + throws IOException { + super(reader); _isVisible = isVisible; numberOfParameters = reader.readNextByte(); - for ( int i = 0 ; i < numberOfParameters ; ++i ) { + for (int i = 0; i < getNumberOfParameters(); ++i) { short numberOfAnnotations = reader.readNextShort(); - AnnotationJava [] annotations = new AnnotationJava[ numberOfAnnotations ]; - for ( int a = 0 ; a < numberOfAnnotations ; ++a ) { - annotations[ a ] = new AnnotationJava( reader ); + AnnotationJava[] annotations = new AnnotationJava[(numberOfAnnotations & 0xffff)]; + for (int a = 0; a < (numberOfAnnotations & 0xffff); ++a) { + annotations[a] = new AnnotationJava(reader); } - parameterAnnotations.put( i, annotations ); + parameterAnnotations.put(i, annotations); } } @@ -100,8 +102,8 @@ public class RuntimeParameterAnnotationsAttribute extends AbstractAttributeInfo * (This duplicates information that could be extracted from the method descriptor.) * @return the number of parameters for this method */ - public byte getNumberOfParameters() { - return numberOfParameters; + public int getNumberOfParameters() { + return numberOfParameters & 0xff; } /** @@ -120,23 +122,23 @@ public class RuntimeParameterAnnotationsAttribute extends AbstractAttributeInfo * @param parameter the parameter index * @return the annotations for the given parameter */ - public AnnotationJava [] getParameterAnnotations( int parameter ) { - return parameterAnnotations.get( parameter ); + public AnnotationJava[] getParameterAnnotations(int parameter) { + return parameterAnnotations.get(parameter); } @Override public DataType toDataType() throws DuplicateNameException, IOException { - String name = _isVisible ? - "RuntimeVisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|" : - "RuntimeInvisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|"; + String name = _isVisible + ? "RuntimeVisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|" + : "RuntimeInvisibleParameterAnnotations_attribute" + "|" + numberOfParameters + "|"; - StructureDataType structure = getBaseStructure( name ); - structure.add( BYTE, "num_parameters", null ); - for ( int i = 0 ; i < numberOfParameters ; ++i ) { - structure.add( WORD, "num_annotations_" + i, null ); - AnnotationJava [] annotations = parameterAnnotations.get( i ); - for ( int a = 0 ; a < annotations.length ; ++a ) { - structure.add( annotations[ a ].toDataType(), "annotations_" + i + "_" + a, null ); + StructureDataType structure = getBaseStructure(name); + structure.add(BYTE, "num_parameters", null); + for (int i = 0; i < numberOfParameters; ++i) { + structure.add(WORD, "num_annotations_" + i, null); + AnnotationJava[] annotations = parameterAnnotations.get(i); + for (int a = 0; a < annotations.length; ++a) { + structure.add(annotations[a].toDataType(), "annotations_" + i + "_" + a, null); } } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/SignatureAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/SignatureAttribute.java index 5366133dd3..13ed847316 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/SignatureAttribute.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/SignatureAttribute.java @@ -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 *

@@ -45,8 +44,8 @@ public class SignatureAttribute extends AbstractAttributeInfo { private short signatureIndex; - public SignatureAttribute( BinaryReader reader ) throws IOException { - super( reader ); + public SignatureAttribute(BinaryReader reader) throws IOException { + super(reader); signatureIndex = reader.readNextShort(); } @@ -60,14 +59,14 @@ public class SignatureAttribute extends AbstractAttributeInfo { * type signature otherwise. * @return a valid index into the constant_pool table */ - public short getSignatureIndex() { - return signatureIndex; + public int getSignatureIndex() { + return signatureIndex & 0xffff; } @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType structure = getBaseStructure( "Signature_attribute" ); - structure.add( WORD, "signature_index", null ); + StructureDataType structure = getBaseStructure("Signature_attribute"); + structure.add(WORD, "signature_index", null); return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/SourceFileAttribute.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/SourceFileAttribute.java index 88b6caae72..9d41c649f2 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/SourceFileAttribute.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/attributes/SourceFileAttribute.java @@ -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 *

@@ -43,8 +42,8 @@ public class SourceFileAttribute extends AbstractAttributeInfo { private short sourceFileIndex; - public SourceFileAttribute( BinaryReader reader ) throws IOException { - super( reader ); + public SourceFileAttribute(BinaryReader reader) throws IOException { + super(reader); sourceFileIndex = reader.readNextShort(); } @@ -62,14 +61,14 @@ public class SourceFileAttribute extends AbstractAttributeInfo { * at the time the file name is actually used. * @return a valid index into the constant_pool table */ - public short getSourceFileIndex() { - return sourceFileIndex; + public int getSourceFileIndex() { + return sourceFileIndex & 0xffff; } @Override public DataType toDataType() throws DuplicateNameException, IOException { - StructureDataType structure = getBaseStructure( "SourceFile_attribute" ); - structure.add( WORD, "sourcefile_index", null ); + StructureDataType structure = getBaseStructure("SourceFile_attribute"); + structure.add(WORD, "sourcefile_index", null); return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/AbstractConstantPoolInfoJava.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/AbstractConstantPoolInfoJava.java index 89a1cd0df9..eec12e0e64 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/AbstractConstantPoolInfoJava.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/AbstractConstantPoolInfoJava.java @@ -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 *

@@ -46,7 +46,7 @@ public abstract class AbstractConstantPoolInfoJava implements StructConverter { private long _offset; private byte tag; - protected AbstractConstantPoolInfoJava( BinaryReader reader ) throws IOException { + protected AbstractConstantPoolInfoJava(BinaryReader reader) throws IOException { _offset = reader.getPointerIndex(); tag = reader.readNextByte(); diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/AbstractConstantPoolReferenceInfo.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/AbstractConstantPoolReferenceInfo.java index 4d124e5480..e031fc7aba 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/AbstractConstantPoolReferenceInfo.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/AbstractConstantPoolReferenceInfo.java @@ -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 *

@@ -56,8 +54,8 @@ public abstract class AbstractConstantPoolReferenceInfo extends AbstractConstant *

* @return a valid index into the constant_pool table */ - public short getClassIndex() { - return classIndex; + public int getClassIndex() { + return classIndex & 0xffff; } /** @@ -77,17 +75,17 @@ public abstract class AbstractConstantPoolReferenceInfo extends AbstractConstant *

* @return a valid index into the constant_pool table */ - public short getNameAndTypeIndex() { - return nameAndTypeIndex; + public int getNameAndTypeIndex() { + return nameAndTypeIndex & 0xffff; } @Override public DataType toDataType() throws DuplicateNameException, IOException { String name = "unnamed"; - Structure structure = new StructureDataType( name, 0 ); - structure.add( BYTE, "tag", null ); - structure.add( WORD, "class_index", null ); - structure.add( WORD, "name_and_type_index", null ); + Structure structure = new StructureDataType(name, 0); + structure.add(BYTE, "tag", null); + structure.add(WORD, "class_index", null); + structure.add(WORD, "name_and_type_index", null); return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolClassInfo.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolClassInfo.java index 1ecbdfcae3..cf62e84d74 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolClassInfo.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolClassInfo.java @@ -18,9 +18,7 @@ package ghidra.javaclass.format.constantpool; import java.io.IOException; import ghidra.app.util.bin.BinaryReader; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.Structure; -import ghidra.program.model.data.StructureDataType; +import ghidra.program.model.data.*; import ghidra.util.exception.DuplicateNameException; /** @@ -47,8 +45,8 @@ public class ConstantPoolClassInfo extends AbstractConstantPoolInfoJava { private short nameIndex; - public ConstantPoolClassInfo( BinaryReader reader ) throws IOException { - super( reader ); + public ConstantPoolClassInfo(BinaryReader reader) throws IOException { + super(reader); nameIndex = reader.readNextShort(); } @@ -60,16 +58,16 @@ public class ConstantPoolClassInfo extends AbstractConstantPoolInfoJava { * interface name encoded in internal form (?4.2.1). * @return a valid index into the constant_pool table */ - public short getNameIndex() { - return nameIndex; + public int getNameIndex() { + return nameIndex & 0xffff; } @Override public DataType toDataType() throws DuplicateNameException, IOException { String name = "CONSTANT_Class_info"; - Structure structure = new StructureDataType( name, 0 ); - structure.add( BYTE, "tag", null ); - structure.add( WORD, "name_index", null ); + Structure structure = new StructureDataType(name, 0); + structure.add(BYTE, "tag", null); + structure.add(WORD, "name_index", null); return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolDynamicInfo.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolDynamicInfo.java new file mode 100644 index 0000000000..26f07bc579 --- /dev/null +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolDynamicInfo.java @@ -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 + *

+ * + * The CONSTANT_Dynamic_info structure is defined as follows: + *

+ *   CONSTANT_Dynamic_info {
+ *     u1 tag;
+ *     u2 bootstrap_method_attr_index;
+ *     u2 name_and_type_index;
+ *   }
+ *   
+*/ +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; + + } + +} diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolFactory.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolFactory.java index 6941c34bcb..cc7b27a882 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolFactory.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolFactory.java @@ -15,62 +15,74 @@ */ package ghidra.javaclass.format.constantpool; -import ghidra.app.util.bin.BinaryReader; - import java.io.IOException; +import ghidra.app.util.bin.BinaryReader; + public class ConstantPoolFactory { - public static AbstractConstantPoolInfoJava get( BinaryReader reader ) throws IOException { + public static AbstractConstantPoolInfoJava get(BinaryReader reader) throws IOException { - switch ( reader.peekNextByte() ) { + switch (reader.peekNextByte()) { case ConstantPoolTagsJava.CONSTANT_Class: - return new ConstantPoolClassInfo( reader ); + return new ConstantPoolClassInfo(reader); case ConstantPoolTagsJava.CONSTANT_Double: - return new ConstantPoolDoubleInfo( reader ); + return new ConstantPoolDoubleInfo(reader); case ConstantPoolTagsJava.CONSTANT_Fieldref: - return new ConstantPoolFieldReferenceInfo( reader ); + return new ConstantPoolFieldReferenceInfo(reader); case ConstantPoolTagsJava.CONSTANT_Float: - return new ConstantPoolFloatInfo( reader ); + return new ConstantPoolFloatInfo(reader); case ConstantPoolTagsJava.CONSTANT_Integer: - return new ConstantPoolIntegerInfo( reader ); + return new ConstantPoolIntegerInfo(reader); case ConstantPoolTagsJava.CONSTANT_InterfaceMethodref: - return new ConstantPoolInterfaceMethodReferenceInfo( reader ); + return new ConstantPoolInterfaceMethodReferenceInfo(reader); case ConstantPoolTagsJava.CONSTANT_InvokeDynamic: - return new ConstantPoolInvokeDynamicInfo( reader ); + return new ConstantPoolInvokeDynamicInfo(reader); case ConstantPoolTagsJava.CONSTANT_Long: - return new ConstantPoolLongInfo( reader ); + return new ConstantPoolLongInfo(reader); case ConstantPoolTagsJava.CONSTANT_MethodHandle: - return new ConstantPoolMethodHandleInfo( reader ); + return new ConstantPoolMethodHandleInfo(reader); case ConstantPoolTagsJava.CONSTANT_Methodref: - return new ConstantPoolMethodReferenceInfo( reader ); + return new ConstantPoolMethodReferenceInfo(reader); case ConstantPoolTagsJava.CONSTANT_MethodType: - return new ConstantPoolMethodTypeInfo( reader ); + return new ConstantPoolMethodTypeInfo(reader); case ConstantPoolTagsJava.CONSTANT_NameAndType: - return new ConstantPoolNameAndTypeInfo( reader ); + return new ConstantPoolNameAndTypeInfo(reader); case ConstantPoolTagsJava.CONSTANT_String: - return new ConstantPoolStringInfo( reader ); + return new ConstantPoolStringInfo(reader); case ConstantPoolTagsJava.CONSTANT_Utf8: - return new ConstantPoolUtf8Info( reader ); + return new ConstantPoolUtf8Info(reader); + + case ConstantPoolTagsJava.CONSTANT_Dynamic: + return new ConstantPoolDynamicInfo(reader); + + case ConstantPoolTagsJava.CONSTANT_Module: + return new ConstantPoolModuleInfo(reader); + + case ConstantPoolTagsJava.CONSTANT_Package: + return new ConstantPoolPackageInfo(reader); case 0: return null; + + default: + throw new IllegalArgumentException( + "Unsupport Constant Pool Entry Type: " + reader.peekNextByte()); } - throw new RuntimeException(); } } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolInvokeDynamicInfo.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolInvokeDynamicInfo.java index 53958ac556..d77c64a731 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolInvokeDynamicInfo.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolInvokeDynamicInfo.java @@ -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 *

* 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. *

@@ -43,8 +41,8 @@ public class ConstantPoolInvokeDynamicInfo extends AbstractConstantPoolInfoJava
 	private short bootstrapMethodAttrIndex;
 	private short nameAndTypeIndex;
 
-	public ConstantPoolInvokeDynamicInfo( BinaryReader reader ) throws IOException {
-		super( reader );
+	public ConstantPoolInvokeDynamicInfo(BinaryReader reader) throws IOException {
+		super(reader);
 		bootstrapMethodAttrIndex = reader.readNextShort();
 		nameAndTypeIndex = reader.readNextShort();
 	}
@@ -55,8 +53,8 @@ public class ConstantPoolInvokeDynamicInfo extends AbstractConstantPoolInfoJava
 	 * this class file.
 	 * @return a valid index into the bootstrap_methods array
 	 */
-	public short getBootstrapMethodAttrIndex() {
-		return bootstrapMethodAttrIndex;
+	public int getBootstrapMethodAttrIndex() {
+		return bootstrapMethodAttrIndex & 0xffff;
 	}
 
 	/**
@@ -66,17 +64,17 @@ public class ConstantPoolInvokeDynamicInfo extends AbstractConstantPoolInfoJava
 	 * and method descriptor.
 	 * @return a valid index into the constant_pool table
 	 */
-	public short getNameAndTypeIndex() {
-		return nameAndTypeIndex;
+	public int getNameAndTypeIndex() {
+		return nameAndTypeIndex & 0xffff;
 	}
 
 	@Override
 	public DataType toDataType() throws DuplicateNameException, IOException {
 		String name = "CONSTANT_InvokeDynamic_info";
-		Structure structure = new StructureDataType( name, 0 );
-		structure.add( BYTE, "tag", null );
-		structure.add( WORD, "bootstrap_method_attr_index", null );
-		structure.add( WORD, "name_and_type_index", null );
+		Structure structure = new StructureDataType(name, 0);
+		structure.add(BYTE, "tag", null);
+		structure.add(WORD, "bootstrap_method_attr_index", null);
+		structure.add(WORD, "name_and_type_index", null);
 		return structure;
 	}
 
diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolMethodHandleInfo.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolMethodHandleInfo.java
index f787c93b6c..57c492a2f1 100644
--- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolMethodHandleInfo.java
+++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolMethodHandleInfo.java
@@ -15,14 +15,11 @@
  */
 package ghidra.javaclass.format.constantpool;
 
-import ghidra.app.util.bin.BinaryReader;
-import ghidra.program.model.data.DataType;
-import ghidra.program.model.data.Structure;
-import ghidra.program.model.data.StructureDataType;
-import ghidra.util.exception.DuplicateNameException;
-
 import java.io.IOException;
 
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.program.model.data.*;
+import ghidra.util.exception.DuplicateNameException;
 
 /**
  * NOTE: THE FOLLOWING TEXT EXTRACTED FROM JVMS7.PDF
@@ -37,12 +34,12 @@ import java.io.IOException;
  * 
*/ public class ConstantPoolMethodHandleInfo extends AbstractConstantPoolInfoJava { - - private byte referenceKind; - private int referenceIndex; - public ConstantPoolMethodHandleInfo( BinaryReader reader ) throws IOException { - super( reader ); + private byte referenceKind; + private short referenceIndex; + + public ConstantPoolMethodHandleInfo(BinaryReader reader) throws IOException { + super(reader); referenceKind = reader.readNextByte(); referenceIndex = reader.readNextShort(); } @@ -101,16 +98,16 @@ public class ConstantPoolMethodHandleInfo extends AbstractConstantPoolInfoJava { * @return a valid index into the constant_pool table */ public int getReferenceIndex() { - return referenceIndex; + return referenceIndex & 0xffff; } @Override public DataType toDataType() throws DuplicateNameException, IOException { String name = "CONSTANT_MethodHandle_info"; - Structure structure = new StructureDataType( name, 0 ); - structure.add( BYTE, "tag", null ); - structure.add( BYTE, "reference_kind", null ); - structure.add( WORD, "reference_index", null ); + Structure structure = new StructureDataType(name, 0); + structure.add(BYTE, "tag", null); + structure.add(BYTE, "reference_kind", null); + structure.add(WORD, "reference_index", null); return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolMethodTypeInfo.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolMethodTypeInfo.java index 8f77f658e4..ae9a5670ae 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolMethodTypeInfo.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolMethodTypeInfo.java @@ -18,9 +18,7 @@ package ghidra.javaclass.format.constantpool; import java.io.IOException; import ghidra.app.util.bin.BinaryReader; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.Structure; -import ghidra.program.model.data.StructureDataType; +import ghidra.program.model.data.*; import ghidra.util.exception.DuplicateNameException; /** @@ -38,8 +36,8 @@ public class ConstantPoolMethodTypeInfo extends AbstractConstantPoolInfoJava { private short descriptorIndex; - public ConstantPoolMethodTypeInfo( BinaryReader reader ) throws IOException { - super( reader ); + public ConstantPoolMethodTypeInfo(BinaryReader reader) throws IOException { + super(reader); descriptorIndex = reader.readNextShort(); } @@ -49,16 +47,16 @@ public class ConstantPoolMethodTypeInfo extends AbstractConstantPoolInfoJava { * CONSTANT_Utf8_info structure representing a method descriptor. * @return a valid index into the constant_pool table */ - public short getDescriptorIndex() { - return descriptorIndex; + public int getDescriptorIndex() { + return descriptorIndex & 0xffff; } @Override public DataType toDataType() throws DuplicateNameException, IOException { String name = "CONSTANT_MethodType_info"; - Structure structure = new StructureDataType( name, 0 ); - structure.add( BYTE, "tag", null ); - structure.add( WORD, "descriptor_index", null ); + Structure structure = new StructureDataType(name, 0); + structure.add(BYTE, "tag", null); + structure.add(WORD, "descriptor_index", null); return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolModuleInfo.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolModuleInfo.java new file mode 100644 index 0000000000..922b20332b --- /dev/null +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolModuleInfo.java @@ -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 + *

+ * 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; + } + +} diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolNameAndTypeInfo.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolNameAndTypeInfo.java index 0b0e76bf58..6e57b1f0e0 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolNameAndTypeInfo.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolNameAndTypeInfo.java @@ -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 *

@@ -41,8 +39,8 @@ public class ConstantPoolNameAndTypeInfo extends AbstractConstantPoolInfoJava { private short nameIndex; private short descriptorIndex; - public ConstantPoolNameAndTypeInfo( BinaryReader reader ) throws IOException { - super( reader ); + public ConstantPoolNameAndTypeInfo(BinaryReader reader) throws IOException { + super(reader); nameIndex = reader.readNextShort(); descriptorIndex = reader.readNextShort(); } @@ -55,8 +53,8 @@ public class ConstantPoolNameAndTypeInfo extends AbstractConstantPoolInfoJava { * method. * @return a valid index into the constant_pool table to the name */ - public short getNameIndex() { - return nameIndex; + public int getNameIndex() { + return nameIndex & 0xffff; } /** @@ -66,17 +64,17 @@ public class ConstantPoolNameAndTypeInfo extends AbstractConstantPoolInfoJava { * or method descriptor. * @return a valid index into the constant_pool table to the descriptor */ - public short getDescriptorIndex() { - return descriptorIndex; + public int getDescriptorIndex() { + return descriptorIndex & 0xffff; } @Override public DataType toDataType() throws DuplicateNameException, IOException { String name = "CONSTANT_NameAndType_info"; - Structure structure = new StructureDataType( name, 0 ); - structure.add( BYTE, "tag", null ); - structure.add( WORD, "name_index", null ); - structure.add( WORD, "descriptor_index", null ); + Structure structure = new StructureDataType(name, 0); + structure.add(BYTE, "tag", null); + structure.add(WORD, "name_index", null); + structure.add(WORD, "descriptor_index", null); return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolPackageInfo.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolPackageInfo.java new file mode 100644 index 0000000000..4294afe9d6 --- /dev/null +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolPackageInfo.java @@ -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 + *

+ * 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; + } + +} diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolStringInfo.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolStringInfo.java index 77483c932c..6a03945178 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolStringInfo.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolStringInfo.java @@ -18,9 +18,7 @@ package ghidra.javaclass.format.constantpool; import java.io.IOException; import ghidra.app.util.bin.BinaryReader; -import ghidra.program.model.data.DataType; -import ghidra.program.model.data.Structure; -import ghidra.program.model.data.StructureDataType; +import ghidra.program.model.data.*; import ghidra.util.exception.DuplicateNameException; /** @@ -39,7 +37,7 @@ public class ConstantPoolStringInfo extends AbstractConstantPoolInfoJava { private short stringIndex; - public ConstantPoolStringInfo( BinaryReader reader ) throws IOException { + public ConstantPoolStringInfo(BinaryReader reader) throws IOException { super(reader); stringIndex = reader.readNextShort(); } @@ -51,16 +49,16 @@ public class ConstantPoolStringInfo extends AbstractConstantPoolInfoJava { * code points to which the String object is to be initialized. * @return a valid index into the constant_pool table */ - public short getStringIndex() { - return stringIndex; + public int getStringIndex() { + return stringIndex & 0xffff; } @Override public DataType toDataType() throws DuplicateNameException, IOException { String name = "CONSTANT_String_info"; - Structure structure = new StructureDataType( name, 0 ); - structure.add( BYTE, "tag", null ); - structure.add( WORD, "string_index", null ); + Structure structure = new StructureDataType(name, 0); + structure.add(BYTE, "tag", null); + structure.add(WORD, "string_index", null); return structure; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolTagsJava.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolTagsJava.java index 97424b62c5..d6be48edfe 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolTagsJava.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolTagsJava.java @@ -17,19 +17,22 @@ package ghidra.javaclass.format.constantpool; public final class ConstantPoolTagsJava { - public final static byte CONSTANT_Class = 7; - public final static byte CONSTANT_Fieldref = 9; - public final static byte CONSTANT_Methodref = 10; - public final static byte CONSTANT_InterfaceMethodref = 11; - public final static byte CONSTANT_String = 8; - public final static byte CONSTANT_Integer = 3; - public final static byte CONSTANT_Float = 4; - public final static byte CONSTANT_Long = 5; - public final static byte CONSTANT_Double = 6; - public final static byte CONSTANT_NameAndType = 12; - public final static byte CONSTANT_Utf8 = 1; - public final static byte CONSTANT_MethodHandle = 15; - public final static byte CONSTANT_MethodType = 16; - public final static byte CONSTANT_InvokeDynamic = 18; + public final static byte CONSTANT_Class = 7; + public final static byte CONSTANT_Fieldref = 9; + public final static byte CONSTANT_Methodref = 10; + public final static byte CONSTANT_InterfaceMethodref = 11; + public final static byte CONSTANT_String = 8; + public final static byte CONSTANT_Integer = 3; + public final static byte CONSTANT_Float = 4; + public final static byte CONSTANT_Long = 5; + public final static byte CONSTANT_Double = 6; + public final static byte CONSTANT_NameAndType = 12; + public final static byte CONSTANT_Utf8 = 1; + public final static byte CONSTANT_MethodHandle = 15; + public final static byte CONSTANT_MethodType = 16; + public final static byte CONSTANT_Dynamic = 17; + public final static byte CONSTANT_InvokeDynamic = 18; + public final static byte CONSTANT_Module = 19; + public final static byte CONSTANT_Package = 20; } diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolUtf8Info.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolUtf8Info.java index ac6b728be3..0e0c425027 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolUtf8Info.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/format/constantpool/ConstantPoolUtf8Info.java @@ -41,12 +41,12 @@ import ghidra.util.exception.DuplicateNameException; public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava { private short length; - private byte [] bytes; + private byte[] bytes; - public ConstantPoolUtf8Info( BinaryReader reader ) throws IOException { - super( reader ); + public ConstantPoolUtf8Info(BinaryReader reader) throws IOException { + super(reader); length = reader.readNextShort(); - bytes = reader.readNextByteArray( length ); + bytes = reader.readNextByteArray(getLength()); } /** @@ -55,8 +55,8 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava { * structure are not null-terminated. * @return the number of bytes in the bytes array */ - public short getLength() { - return length; + public int getLength() { + return length & 0xffff; } /** @@ -65,7 +65,7 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava { * range (byte)0xf0 - (byte)0xff. * @return the bytes of the string */ - public byte [] getBytes() { + public byte[] getBytes() { return bytes; } @@ -75,7 +75,7 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava { * @return the byte array translated into a string */ public String getString() { - return new String( bytes ); + return new String(bytes); } @Override @@ -86,10 +86,10 @@ public class ConstantPoolUtf8Info extends AbstractConstantPoolInfoJava { @Override public DataType toDataType() throws DuplicateNameException, IOException { String name = "CONSTANT_Utf8_info" + "|" + length + "|"; - Structure structure = new StructureDataType( name, 0 ); - structure.add( BYTE, "tag", null ); - structure.add( WORD, "length", null ); - if ( length > 0 ) { + Structure structure = new StructureDataType(name, 0); + structure.add(BYTE, "tag", null); + structure.add(WORD, "length", null); + if (length > 0) { structure.add(UTF8, length, "data", null); } return structure; diff --git a/Ghidra/Processors/JVM/src/test/java/ghidra/app/util/pcodeInject/InvokeMethodsTest.java b/Ghidra/Processors/JVM/src/test/java/ghidra/app/util/pcodeInject/InvokeMethodsTest.java index 397ede693a..59f282d342 100644 --- a/Ghidra/Processors/JVM/src/test/java/ghidra/app/util/pcodeInject/InvokeMethodsTest.java +++ b/Ghidra/Processors/JVM/src/test/java/ghidra/app/util/pcodeInject/InvokeMethodsTest.java @@ -28,9 +28,8 @@ import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava; public class InvokeMethodsTest { - @Test - public void testEmitPcodeToResolveMethodReferenceInvokeDynamic() throws IOException{ + public void testEmitPcodeToResolveMethodReferenceInvokeDynamic() throws IOException { short bootstrap = 0; ArrayList classFile = new ArrayList<>(); TestClassFileCreator.appendMagic(classFile); @@ -39,151 +38,173 @@ public class InvokeMethodsTest { TestClassFileCreator.appendInvokeDynamicInfo(classFile, bootstrap, (short) 2); //1 TestClassFileCreator.appendNameAndType(classFile, (short) 3, (short) 4); //2 TestClassFileCreator.appendUtf8(classFile, "dynamicMethodName"); //3 - TestClassFileCreator.appendUtf8(classFile,"(I)I"); //4 (descriptor) + TestClassFileCreator.appendUtf8(classFile, "(I)I"); //4 (descriptor) byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile); - AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); + AbstractConstantPoolInfoJava[] constantPool = + TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); StringBuilder pCode = new StringBuilder(); - InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_DYNAMIC); - + InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, + JavaInvocationType.INVOKE_DYNAMIC); + StringBuilder expected = new StringBuilder(); - PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKEDYNAMIC); - assertEquals("incorrect pcode for dynamic invocation", expected.toString(), pCode.toString()); + PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, + ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKEDYNAMIC); + assertEquals("incorrect pcode for dynamic invocation", expected.toString(), + pCode.toString()); } - + @Test - public void testEmitPcodeToResolveMethodReferenceInvokeInterface() throws IOException{ + public void testEmitPcodeToResolveMethodReferenceInvokeInterface() throws IOException { ArrayList classFile = new ArrayList<>(); TestClassFileCreator.appendMagic(classFile); TestClassFileCreator.appendVersions(classFile); TestClassFileCreator.appendCount(classFile, (short) 7); - TestClassFileCreator.appendInterfaceMethodRef(classFile, (short) 2, (short)3); //1 + TestClassFileCreator.appendInterfaceMethodRef(classFile, (short) 2, (short) 3); //1 TestClassFileCreator.appendClass(classFile, (short) 4); //2 TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3 TestClassFileCreator.appendUtf8(classFile, "className"); //4 TestClassFileCreator.appendUtf8(classFile, "interfaceMethodName"); //5 - TestClassFileCreator.appendUtf8(classFile,"(I)I"); //6 (descriptor) + TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor) byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile); - AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); + AbstractConstantPoolInfoJava[] constantPool = + TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); StringBuilder pCode = new StringBuilder(); - InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_INTERFACE); - + InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, + JavaInvocationType.INVOKE_INTERFACE); + StringBuilder expected = new StringBuilder(); - PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1", ConstantPoolJava.CPOOL_INVOKEINTERFACE); - assertEquals("incorrect pcode for interface method invocation", expected.toString(), pCode.toString()); + PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, + ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1", + ConstantPoolJava.CPOOL_INVOKEINTERFACE); + assertEquals("incorrect pcode for interface method invocation", expected.toString(), + pCode.toString()); } - + @Test - public void testEmitPcodeToResolveMethodReferenceInvokeSpecial() throws IOException{ + public void testEmitPcodeToResolveMethodReferenceInvokeSpecial() throws IOException { ArrayList classFile = new ArrayList<>(); TestClassFileCreator.appendMagic(classFile); TestClassFileCreator.appendVersions(classFile); TestClassFileCreator.appendCount(classFile, (short) 7); - TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short)3); //1 + TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short) 3); //1 TestClassFileCreator.appendClass(classFile, (short) 4); //2 TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3 TestClassFileCreator.appendUtf8(classFile, "className"); //4 TestClassFileCreator.appendUtf8(classFile, "methodName"); //5 - TestClassFileCreator.appendUtf8(classFile,"(I)I"); //6 (descriptor) + TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor) byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile); - AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); + AbstractConstantPoolInfoJava[] constantPool = + TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); StringBuilder pCode = new StringBuilder(); - InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_SPECIAL); - - StringBuilder expected = new StringBuilder(); - PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1", ConstantPoolJava.CPOOL_INVOKESPECIAL); - assertEquals("incorrect pcode for special method invocation", expected.toString(), pCode.toString()); + InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, + JavaInvocationType.INVOKE_SPECIAL); + + StringBuilder expected = new StringBuilder(); + PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, + ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1", + ConstantPoolJava.CPOOL_INVOKESPECIAL); + assertEquals("incorrect pcode for special method invocation", expected.toString(), + pCode.toString()); } - + @Test - public void testEmitPcodeToResolveMethodReferenceInvokeStatic() throws IOException{ + public void testEmitPcodeToResolveMethodReferenceInvokeStatic() throws IOException { ArrayList classFile = new ArrayList<>(); TestClassFileCreator.appendMagic(classFile); TestClassFileCreator.appendVersions(classFile); TestClassFileCreator.appendCount(classFile, (short) 7); - TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short)3); //1 + TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short) 3); //1 TestClassFileCreator.appendClass(classFile, (short) 4); //2 TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3 TestClassFileCreator.appendUtf8(classFile, "className"); //4 TestClassFileCreator.appendUtf8(classFile, "methodName"); //5 - TestClassFileCreator.appendUtf8(classFile,"(I)I"); //6 (descriptor) + TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor) byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile); - AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); + AbstractConstantPoolInfoJava[] constantPool = + TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); StringBuilder pCode = new StringBuilder(); - InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_STATIC); - - StringBuilder expected = new StringBuilder(); - PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKESTATIC); - assertEquals("incorrect pcode for static method invocation", expected.toString(), pCode.toString()); + InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, + JavaInvocationType.INVOKE_STATIC); + + StringBuilder expected = new StringBuilder(); + PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, + ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKESTATIC); + assertEquals("incorrect pcode for static method invocation", expected.toString(), + pCode.toString()); } - + @Test - public void testEmitPcodeToResolveMethodReferenceInvokeVirtual() throws IOException{ + public void testEmitPcodeToResolveMethodReferenceInvokeVirtual() throws IOException { ArrayList classFile = new ArrayList<>(); TestClassFileCreator.appendMagic(classFile); TestClassFileCreator.appendVersions(classFile); TestClassFileCreator.appendCount(classFile, (short) 7); - TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short)3); //1 + TestClassFileCreator.appendMethodRef(classFile, (short) 2, (short) 3); //1 TestClassFileCreator.appendClass(classFile, (short) 4); //2 TestClassFileCreator.appendNameAndType(classFile, (short) 5, (short) 6); //3 TestClassFileCreator.appendUtf8(classFile, "className"); //4 TestClassFileCreator.appendUtf8(classFile, "methodName"); //5 - TestClassFileCreator.appendUtf8(classFile,"(I)I"); //6 (descriptor) + TestClassFileCreator.appendUtf8(classFile, "(I)I"); //6 (descriptor) byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile); - AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); + AbstractConstantPoolInfoJava[] constantPool = + TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); StringBuilder pCode = new StringBuilder(); - InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, JavaInvocationType.INVOKE_VIRTUAL); - - StringBuilder expected = new StringBuilder(); - PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1", ConstantPoolJava.CPOOL_INVOKEVIRTUAL); - assertEquals("incorrect pcode for static method invocation", expected.toString(), pCode.toString()); + InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool, + JavaInvocationType.INVOKE_VIRTUAL); + + StringBuilder expected = new StringBuilder(); + PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET, + ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1", + ConstantPoolJava.CPOOL_INVOKEVIRTUAL); + assertEquals("incorrect pcode for static method invocation", expected.toString(), + pCode.toString()); } - + @Test - public void testEmitPcodeToReverseStackNoParamsNoThis(){ + public void testEmitPcodeToReverseStackNoParamsNoThis() { StringBuilder pCode = new StringBuilder(); //InvokeMethods.emitPcodeToReverseStack(pCode, new ArrayList(), false); StringBuilder expected = new StringBuilder(); - assertEquals("incorrect pcode reversing stack: no params no this", expected.toString(), pCode.toString()); + assertEquals("incorrect pcode reversing stack: no params no this", expected.toString(), + pCode.toString()); } - - - - - + //test bad category - + @Test - public void testGetPcodeForInvoke() throws IOException{ + public void testGetPcodeForInvoke() throws IOException { ArrayList classFile = new ArrayList<>(); TestClassFileCreator.appendMagic(classFile); TestClassFileCreator.appendVersions(classFile); TestClassFileCreator.appendCount(classFile, (short) 5); - TestClassFileCreator.appendInvokeDynamicInfo(classFile, (short) 0, (short)2); //1 + TestClassFileCreator.appendInvokeDynamicInfo(classFile, (short) 0, (short) 2); //1 TestClassFileCreator.appendNameAndType(classFile, (short) 3, (short) 4); //2 TestClassFileCreator.appendUtf8(classFile, "dynamicMethodName"); //3 - TestClassFileCreator.appendUtf8(classFile,"(JJII)I"); //4 (descriptor) + TestClassFileCreator.appendUtf8(classFile, "(JJII)I"); //4 (descriptor) byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile); - AbstractConstantPoolInfoJava[] constantPool = TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); - String pCode = InvokeMethods.getPcodeForInvoke(1, constantPool, JavaInvocationType.INVOKE_DYNAMIC); - + AbstractConstantPoolInfoJava[] constantPool = + TestClassFileCreator.getConstantPoolFromBytes(classFileBytes); + String pCode = + InvokeMethods.getPcodeForInvoke(1, constantPool, JavaInvocationType.INVOKE_DYNAMIC); + StringBuilder expected = new StringBuilder(); - String descriptor = DescriptorDecoder.getDescriptorForInvoke(1, constantPool, JavaInvocationType.INVOKE_DYNAMIC); - List categories = DescriptorDecoder.getParameterCategories(descriptor); + String descriptor = DescriptorDecoder.getDescriptorForInvoke(1, constantPool, + JavaInvocationType.INVOKE_DYNAMIC); + List categories = + DescriptorDecoder.getParameterCategories(descriptor); InvokeMethods.emitPcodeToMoveParams(expected, categories, false, 24); - InvokeMethods.emitPcodeToResolveMethodReference(expected, 1, constantPool, JavaInvocationType.INVOKE_DYNAMIC); - PcodeTextEmitter.emitIndirectCall(expected, InvokeMethods.CALL_TARGET); - PcodeTextEmitter.emitPushCat1Value(expected, InvokeMethods.CAT_1_RETURN); - System.out.println(pCode); - System.out.println(expected); - - + InvokeMethods.emitPcodeToResolveMethodReference(expected, 1, constantPool, + JavaInvocationType.INVOKE_DYNAMIC); + PcodeTextEmitter.emitIndirectCall(expected, InvokeMethods.CALL_TARGET); + PcodeTextEmitter.emitPushCat1Value(expected, InvokeMethods.CAT_1_RETURN); + assertEquals("incorrect pcode for invoke dynamic: (JJII)I", expected.toString(), pCode); } diff --git a/Ghidra/Processors/JVM/src/test/java/ghidra/app/util/pcodeInject/PcodeTextEmitterTest.java b/Ghidra/Processors/JVM/src/test/java/ghidra/app/util/pcodeInject/PcodeTextEmitterTest.java index 5e672e919f..ccd5cda15d 100644 --- a/Ghidra/Processors/JVM/src/test/java/ghidra/app/util/pcodeInject/PcodeTextEmitterTest.java +++ b/Ghidra/Processors/JVM/src/test/java/ghidra/app/util/pcodeInject/PcodeTextEmitterTest.java @@ -22,35 +22,35 @@ import org.junit.Test; public class PcodeTextEmitterTest { @Test - public void testEmitPushType1Value(){ + public void testEmitPushType1Value() { StringBuilder pCode = new StringBuilder(); PcodeTextEmitter.emitPushCat1Value(pCode, "x"); assertTrue(pCode.toString().equals("SP = SP - 4;\n*:4 SP = x;\n")); } @Test - public void testEmitPushType2Value(){ + public void testEmitPushType2Value() { StringBuilder pCode = new StringBuilder(); PcodeTextEmitter.emitPushCat2Value(pCode, "x"); assertTrue(pCode.toString().equals("SP = SP - 8;\n*:8 SP = x;\n")); } @Test - public void testEmitPopType1Value(){ + public void testEmitPopType1Value() { StringBuilder pCode = new StringBuilder(); PcodeTextEmitter.emitPopCat1Value(pCode, "x"); assertTrue(pCode.toString().equals("x:4 = *:4 SP;\nSP = SP + 4;\n")); } @Test - public void testEmitPopType2Value(){ + public void testEmitPopType2Value() { StringBuilder pCode = new StringBuilder(); PcodeTextEmitter.emitPopCat2Value(pCode, "x"); assertTrue(pCode.toString().equals("x:8 = *:8 SP;\nSP = SP + 8;\n")); } - @Test - public void testEmitVarnodeBytesFromPcodeOpCall(){ + @Test + public void testEmitVarnodeBytesFromPcodeOpCall() { StringBuilder pCode = new StringBuilder(); //test no args @@ -64,9 +64,9 @@ public class PcodeTextEmitterTest { //two args pCode = new StringBuilder(); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 4, "PCODEOP", "ARG1", "ARG2"); - assertTrue(pCode.toString().equals("LHS:4 = PCODEOP(ARG1,ARG2);\n")); - + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 4, "PCODEOP", "ARG1", + "ARG2"); + assertTrue(pCode.toString().equals("LHS:4 = PCODEOP(ARG1,ARG2);\n")); //test no args pCode = new StringBuilder(); @@ -80,12 +80,13 @@ public class PcodeTextEmitterTest { //two args pCode = new StringBuilder(); - PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 8, "PCODEOP", "ARG1", "ARG2"); - assertTrue(pCode.toString().equals("LHS:8 = PCODEOP(ARG1,ARG2);\n")); + PcodeTextEmitter.emitAssignVarnodeFromPcodeOpCall(pCode, "LHS", 8, "PCODEOP", "ARG1", + "ARG2"); + assertTrue(pCode.toString().equals("LHS:8 = PCODEOP(ARG1,ARG2);\n")); } - @Test - public void testEmitVoidPcodeOpCall(){ + @Test + public void testEmitVoidPcodeOpCall() { StringBuilder pCode = new StringBuilder(); //test no args @@ -94,17 +95,17 @@ public class PcodeTextEmitterTest { //one arg pCode = new StringBuilder(); - PcodeTextEmitter.emitVoidPcodeOpCall(pCode,"PCODEOP", "ARG1"); + PcodeTextEmitter.emitVoidPcodeOpCall(pCode, "PCODEOP", "ARG1"); assertTrue(pCode.toString().equals("PCODEOP(ARG1);\n")); //two args pCode = new StringBuilder(); - PcodeTextEmitter.emitVoidPcodeOpCall(pCode,"PCODEOP", "ARG1", "ARG2"); - assertTrue(pCode.toString().equals("PCODEOP(ARG1,ARG2);\n")); + PcodeTextEmitter.emitVoidPcodeOpCall(pCode, "PCODEOP", "ARG1", "ARG2"); + assertTrue(pCode.toString().equals("PCODEOP(ARG1,ARG2);\n")); } @Test - public void testEmitAssignRegisterFromPcodeOpCall(){ + public void testEmitAssignRegisterFromPcodeOpCall() { //void call StringBuilder pCode = new StringBuilder(); PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, "REG", "TEST"); @@ -122,38 +123,59 @@ public class PcodeTextEmitterTest { } @Test - public void testEmitAssignConstantToRegister(){ + public void testEmitAssignConstantToRegister() { StringBuilder pCode = new StringBuilder(); PcodeTextEmitter.emitAssignConstantToRegister(pCode, "REGISTER", 0); assertTrue(pCode.toString().equals("REGISTER = 0x0;\n")); } @Test - public void testEmitLabelDef(){ + public void testEmitLabelDef() { StringBuilder pCode = new StringBuilder(); PcodeTextEmitter.emitLabelDefinition(pCode, "LABEL"); assertEquals("bad label definition emitted", "