InvokeMethodsTest passes

This commit is contained in:
caheckman 2020-07-29 13:39:20 -04:00
parent 822ea1a376
commit f4d25ccebb
4 changed files with 97 additions and 70 deletions

View file

@ -44,16 +44,16 @@ public class InvokeMethods {
/**
* Emits the pcode for an invoke instruction.
* @param pCode is the pcode accumulator
* @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
* @param type - the JavaInvocationType of the invocation
* @return - the pcode as a string
*/
public static String getPcodeForInvoke(int offset, AbstractConstantPoolInfoJava[] constantPool,
public static void getPcodeForInvoke(PcodeOpEmitter pCode, int offset,
AbstractConstantPoolInfoJava[] constantPool,
JavaInvocationType type) {
StringBuilder pCode = new StringBuilder();
String descriptor = DescriptorDecoder.getDescriptorForInvoke(offset, constantPool, type);
List<JavaComputationalCategory> categories =
DescriptorDecoder.getParameterCategories(descriptor);
@ -67,33 +67,31 @@ public class InvokeMethods {
}
emitPcodeToMoveParams(pCode, categories, includeThisPointer, stackPurge);
emitPcodeToResolveMethodReference(pCode, offset, constantPool, type);
PcodeTextEmitter.emitIndirectCall(pCode, CALL_TARGET);
pCode.emitIndirectCall(CALL_TARGET);
JavaComputationalCategory retType =
DescriptorDecoder.getReturnCategoryOfMethodDescriptor(descriptor);
switch (retType) {
case CAT_1:
PcodeTextEmitter.emitPushCat1Value(pCode, CAT_1_RETURN);
pCode.emitPushCat1Value(CAT_1_RETURN);
break;
case CAT_2:
PcodeTextEmitter.emitPushCat2Value(pCode, CAT_2_RETURN);
pCode.emitPushCat2Value(CAT_2_RETURN);
break;
default:
break;
}
return pCode.toString();
}
/**
* Emits the pcode for an invoke instruction.
* @param pCode is the pcode accumulator
* @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,
public static void getPcodeForInvokeDynamic(PcodeOpEmitter pCode, int offset,
AbstractConstantPoolInfoJava[] constantPool) {
StringBuilder pCode = new StringBuilder();
String invokeDynamicDescriptor = DescriptorDecoder.getDescriptorForInvoke(offset,
constantPool, JavaInvocationType.INVOKE_DYNAMIC);
List<JavaComputationalCategory> categories =
@ -104,21 +102,20 @@ public class InvokeMethods {
emitPcodeToMoveParams(pCode, categories, false, stackPurge);
emitPcodeToResolveMethodReference(pCode, offset, constantPool,
JavaInvocationType.INVOKE_DYNAMIC);
PcodeTextEmitter.emitIndirectCall(pCode, CALL_TARGET);
pCode.emitIndirectCall(CALL_TARGET);
JavaComputationalCategory retType =
DescriptorDecoder.getReturnCategoryOfMethodDescriptor(invokeDynamicDescriptor);
switch (retType) {
case CAT_1:
PcodeTextEmitter.emitPushCat1Value(pCode, CAT_1_RETURN);
pCode.emitPushCat1Value(CAT_1_RETURN);
break;
case CAT_2:
PcodeTextEmitter.emitPushCat2Value(pCode, CAT_2_RETURN);
pCode.emitPushCat2Value(CAT_2_RETURN);
break;
default:
break;
}
return pCode.toString();
}
/**
@ -128,25 +125,26 @@ public class InvokeMethods {
* @param pCode - the pcode buffer
* @param categories - the list of computational categories on the top of the stack
* @param includeThisPointer - true if the first element on the stack is an implicit this parameter
* @param totalSize -
*/
static void emitPcodeToMoveParams(StringBuilder pCode,
static void emitPcodeToMoveParams(PcodeOpEmitter pCode,
List<JavaComputationalCategory> categories, boolean includeThisPointer, int totalSize) {
//pop the parameters off of the stack
for (int i = categories.size() - 1; i >= 0; --i) {
switch (categories.get(i)) {
case CAT_1:
PcodeTextEmitter.emitPopCat1Value(pCode, PARAMETER + Integer.toString(i));
pCode.emitPopCat1Value(PARAMETER + Integer.toString(i));
totalSize -= 4;
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4,
pCode.emitWriteToMemory(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,
pCode.emitPopCat1Value(PARAMETER + Integer.toString(i));
pCode.emitWriteToMemory(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,
pCode.emitPopCat1Value(PARAMETER_PART2 + Integer.toString(i));
pCode.emitWriteToMemory(PARAM_SPACE, 4,
Integer.toString(totalSize - 4) + ":4",
PARAMETER_PART2 + Integer.toString(i));
totalSize -= 8;
@ -157,9 +155,9 @@ public class InvokeMethods {
}
//pop off the this pointer if there is one
if (includeThisPointer) {
PcodeTextEmitter.emitPopCat1Value(pCode, THIS);
pCode.emitPopCat1Value(THIS);
totalSize -= 4;
PcodeTextEmitter.emitWriteToMemory(pCode, PARAM_SPACE, 4,
pCode.emitWriteToMemory(PARAM_SPACE, 4,
Integer.toString(totalSize) + ":4", THIS);
}
@ -172,31 +170,31 @@ public class InvokeMethods {
* @param constantPool - the constant pool
* @param type - the type of the invocation
*/
static void emitPcodeToResolveMethodReference(StringBuilder pCode, int offset,
static void emitPcodeToResolveMethodReference(PcodeOpEmitter pCode, int offset,
AbstractConstantPoolInfoJava[] constantPool, JavaInvocationType type) {
switch (type) {
case INVOKE_DYNAMIC:
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
pCode.emitAssignRegisterFromPcodeOpCall(CALL_TARGET,
ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset),
ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
break;
case INVOKE_INTERFACE:
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
pCode.emitAssignRegisterFromPcodeOpCall(CALL_TARGET,
ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset),
ConstantPoolJava.CPOOL_INVOKEINTERFACE);
break;
case INVOKE_SPECIAL:
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
pCode.emitAssignRegisterFromPcodeOpCall(CALL_TARGET,
ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset),
ConstantPoolJava.CPOOL_INVOKESPECIAL);
break;
case INVOKE_STATIC:
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
pCode.emitAssignRegisterFromPcodeOpCall(CALL_TARGET,
ConstantPoolJava.CPOOL_OP, STATIC_OFFSET, Integer.toString(offset),
ConstantPoolJava.CPOOL_INVOKESTATIC);
break;
case INVOKE_VIRTUAL:
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(pCode, CALL_TARGET,
pCode.emitAssignRegisterFromPcodeOpCall(CALL_TARGET,
ConstantPoolJava.CPOOL_OP, THIS, Integer.toString(offset),
ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
break;

View file

@ -114,6 +114,13 @@ public class PcodeOpEmitter {
defSpaceId = getConstant(defSpace.getSpaceID(), 8);
}
public void defineTemp(String name, int size) {
Varnode vn = findVarnode(name, size);
if (!vn.isUnique() || vn.getSize() != size) {
throw new IllegalArgumentException("Name is already assigned: " + name);
}
}
/**
* Emits pcode to push a value of computational category 1 onto the stack.
* @param valueName - name of varnode to push.
@ -253,7 +260,7 @@ public class PcodeOpEmitter {
* @param pcodeop
* @param args
*/
public void emitAssignRegisterFromPcodeOpCall(StringBuilder pCode, String register,
public void emitAssignRegisterFromPcodeOpCall(String register,
String pcodeop, String... args) {
Symbol useropSym = language.getSymbolTable().findGlobalSymbol(pcodeop);
Varnode out = findRegister(register);
@ -290,7 +297,15 @@ public class PcodeOpEmitter {
AddressSpace spc = language.getAddressFactory().getAddressSpace(space);
// TODO: find correct space id
in[0] = getConstant(spc.getSpaceID(), 8);
in[1] = findRegister(offset);
if (offset.charAt(0) <= '9') {
String[] piece = offset.split(":");
int sz = Integer.parseInt(piece[1]);
long val = Long.decode(piece[0]);
in[1] = getConstant(val, sz);
}
else {
in[1] = findRegister(offset);
}
in[2] = findVarnode(value, size);
PcodeOp op = new PcodeOp(opAddress, seqnum++, PcodeOp.STORE, in);
opList.add(op);

View file

@ -21,12 +21,27 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.javaclass.format.DescriptorDecoder;
import ghidra.javaclass.format.constantpool.AbstractConstantPoolInfoJava;
import ghidra.program.model.address.Address;
import ghidra.program.model.lang.LanguageID;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
public class InvokeMethodsTest {
public class InvokeMethodsTest extends AbstractGhidraHeadlessIntegrationTest {
private SleighLanguage language;
private Address opAddress;
@Before
public void setUp() throws Exception {
language =
(SleighLanguage) getLanguageService().getLanguage(new LanguageID("JVM:BE:32:default"));
opAddress = language.getAddressFactory().getDefaultAddressSpace().getAddress(0x10000);
}
@Test
public void testEmitPcodeToResolveMethodReferenceInvokeDynamic() throws IOException {
@ -43,15 +58,14 @@ public class InvokeMethodsTest {
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
StringBuilder pCode = new StringBuilder();
PcodeOpEmitter pCode = new PcodeOpEmitter(language, opAddress);
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
JavaInvocationType.INVOKE_DYNAMIC);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
PcodeOpEmitter expected = new PcodeOpEmitter(language, opAddress);
expected.emitAssignRegisterFromPcodeOpCall(InvokeMethods.CALL_TARGET,
ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKEDYNAMIC);
assertEquals("incorrect pcode for dynamic invocation", expected.toString(),
pCode.toString());
assertEquals("incorrect pcode for dynamic invocation", expected, pCode);
}
@Test
@ -70,16 +84,17 @@ public class InvokeMethodsTest {
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
StringBuilder pCode = new StringBuilder();
PcodeOpEmitter pCode = new PcodeOpEmitter(language, opAddress);
pCode.defineTemp(InvokeMethods.THIS, 4);
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
JavaInvocationType.INVOKE_INTERFACE);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
PcodeOpEmitter expected = new PcodeOpEmitter(language, opAddress);
expected.defineTemp(InvokeMethods.THIS, 4);
expected.emitAssignRegisterFromPcodeOpCall(InvokeMethods.CALL_TARGET,
ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1",
ConstantPoolJava.CPOOL_INVOKEINTERFACE);
assertEquals("incorrect pcode for interface method invocation", expected.toString(),
pCode.toString());
assertEquals("incorrect pcode for interface method invocation", expected, pCode);
}
@Test
@ -98,16 +113,17 @@ public class InvokeMethodsTest {
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
StringBuilder pCode = new StringBuilder();
PcodeOpEmitter pCode = new PcodeOpEmitter(language, opAddress);
pCode.defineTemp(InvokeMethods.THIS, 4);
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
JavaInvocationType.INVOKE_SPECIAL);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
PcodeOpEmitter expected = new PcodeOpEmitter(language, opAddress);
expected.defineTemp(InvokeMethods.THIS, 4);
expected.emitAssignRegisterFromPcodeOpCall(InvokeMethods.CALL_TARGET,
ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1",
ConstantPoolJava.CPOOL_INVOKESPECIAL);
assertEquals("incorrect pcode for special method invocation", expected.toString(),
pCode.toString());
assertEquals("incorrect pcode for special method invocation", expected, pCode);
}
@Test
@ -126,15 +142,14 @@ public class InvokeMethodsTest {
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
StringBuilder pCode = new StringBuilder();
PcodeOpEmitter pCode = new PcodeOpEmitter(language, opAddress);
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
JavaInvocationType.INVOKE_STATIC);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
PcodeOpEmitter expected = new PcodeOpEmitter(language, opAddress);
expected.emitAssignRegisterFromPcodeOpCall(InvokeMethods.CALL_TARGET,
ConstantPoolJava.CPOOL_OP, "0", "1", ConstantPoolJava.CPOOL_INVOKESTATIC);
assertEquals("incorrect pcode for static method invocation", expected.toString(),
pCode.toString());
assertEquals("incorrect pcode for static method invocation", expected, pCode);
}
@Test
@ -153,25 +168,25 @@ public class InvokeMethodsTest {
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
StringBuilder pCode = new StringBuilder();
PcodeOpEmitter pCode = new PcodeOpEmitter(language, opAddress);
pCode.defineTemp(InvokeMethods.THIS, 4);
InvokeMethods.emitPcodeToResolveMethodReference(pCode, 1, constantPool,
JavaInvocationType.INVOKE_VIRTUAL);
StringBuilder expected = new StringBuilder();
PcodeTextEmitter.emitAssignRegisterFromPcodeOpCall(expected, InvokeMethods.CALL_TARGET,
PcodeOpEmitter expected = new PcodeOpEmitter(language, opAddress);
expected.defineTemp(InvokeMethods.THIS, 4);
expected.emitAssignRegisterFromPcodeOpCall(InvokeMethods.CALL_TARGET,
ConstantPoolJava.CPOOL_OP, InvokeMethods.THIS, "1",
ConstantPoolJava.CPOOL_INVOKEVIRTUAL);
assertEquals("incorrect pcode for static method invocation", expected.toString(),
pCode.toString());
assertEquals("incorrect pcode for static method invocation", expected, pCode);
}
@Test
public void testEmitPcodeToReverseStackNoParamsNoThis() {
StringBuilder pCode = new StringBuilder();
PcodeOpEmitter pCode = new PcodeOpEmitter(language, opAddress);
//InvokeMethods.emitPcodeToReverseStack(pCode, new ArrayList<JavaComputationalCategory>(), false);
StringBuilder expected = new StringBuilder();
assertEquals("incorrect pcode reversing stack: no params no this", expected.toString(),
pCode.toString());
PcodeOpEmitter expected = new PcodeOpEmitter(language, opAddress);
assertEquals("incorrect pcode reversing stack: no params no this", expected, pCode);
}
//test bad category
@ -190,10 +205,10 @@ public class InvokeMethodsTest {
byte[] classFileBytes = TestClassFileCreator.getByteArray(classFile);
AbstractConstantPoolInfoJava[] constantPool =
TestClassFileCreator.getConstantPoolFromBytes(classFileBytes);
String pCode =
InvokeMethods.getPcodeForInvoke(1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
PcodeOpEmitter pCode = new PcodeOpEmitter(language, opAddress);
InvokeMethods.getPcodeForInvoke(pCode, 1, constantPool, JavaInvocationType.INVOKE_DYNAMIC);
StringBuilder expected = new StringBuilder();
PcodeOpEmitter expected = new PcodeOpEmitter(language, opAddress);
String descriptor = DescriptorDecoder.getDescriptorForInvoke(1, constantPool,
JavaInvocationType.INVOKE_DYNAMIC);
List<JavaComputationalCategory> categories =
@ -202,11 +217,10 @@ public class InvokeMethodsTest {
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);
assertEquals("incorrect pcode for invoke dynamic: (JJII)I", expected.toString(), pCode);
expected.emitIndirectCall(InvokeMethods.CALL_TARGET);
expected.emitPushCat1Value(InvokeMethods.CAT_1_RETURN);
assertEquals("incorrect pcode for invoke dynamic: (JJII)I", expected, pCode);
}
}

View file

@ -31,8 +31,8 @@ import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
public class ReferenceMethodsTest extends AbstractGhidraHeadlessIntegrationTest {
SleighLanguage language;
Address opAddress;
private SleighLanguage language;
private Address opAddress;
public ReferenceMethodsTest() {