Merge remote-tracking branch 'origin/GP-5301_Dan_testEmuThumbPlt'

This commit is contained in:
Ryan Kurtz
2025-04-04 12:51:15 -04:00
46 changed files with 1702 additions and 367 deletions
@@ -26,8 +26,7 @@ import org.junit.Test;
import generic.test.AbstractGTest;
import ghidra.GhidraTestApplicationLayout;
import ghidra.app.plugin.assembler.Assemblers;
import ghidra.app.plugin.assembler.AssemblyBuffer;
import ghidra.app.plugin.assembler.*;
import ghidra.app.plugin.assembler.sleigh.sem.AssemblyPatternBlock;
import ghidra.framework.Application;
import ghidra.framework.ApplicationConfiguration;
@@ -303,11 +302,11 @@ public abstract class AbstractPcodeEmulatorTest extends AbstractGTest {
public void testSkipThumbStaysThumb() throws Exception {
PcodeEmulator emu = createEmulator(getLanguage(LANGID_ARMV8));
PcodeArithmetic<byte[]> arithmetic = emu.getArithmetic();
AddressSpace space = emu.getLanguage().getDefaultSpace();
Language language = emu.getLanguage();
AddressSpace space = language.getDefaultSpace();
Address entry = space.getAddress(0x00400000);
AssemblyBuffer asm = new AssemblyBuffer(Assemblers.getAssembler(emu.getLanguage()), entry);
Language language = asm.getAssembler().getLanguage();
Register regCtx = language.getContextBaseRegister();
Register regT = language.getRegister("T");
RegisterValue rvDefault = new RegisterValue(regCtx,
@@ -429,4 +428,60 @@ public abstract class AbstractPcodeEmulatorTest extends AbstractGTest {
arithmetic.toLong(thread.getState().getVar(r1, Reason.INSPECT), Purpose.INSPECT));
assertEquals(target, thread.getCounter());
}
public void testArmPltIntoThumbFunction() throws Exception {
PcodeEmulator emu = createEmulator(getLanguage(LANGID_ARMV8));
PcodeArithmetic<byte[]> arithmetic = emu.getArithmetic();
Language language = emu.getLanguage();
AddressSpace space = language.getDefaultSpace();
Address pltEntry = space.getAddress(0x00500000);
Assembler asm = Assemblers.getAssembler(language);
AssemblyBuffer pltAsm = new AssemblyBuffer(asm, pltEntry);
Register regCtx = language.getContextBaseRegister();
Register regT = language.getRegister("T");
RegisterValue rvDefault = new RegisterValue(regCtx, pltAsm.getAssembler()
.getContextAt(pltAsm.getNext())
.toBigInteger(regCtx.getNumBytes()));
RegisterValue rvThumb = rvDefault.assign(regT, BigInteger.ONE);
AssemblyPatternBlock ctxThumb = AssemblyPatternBlock.fromRegisterValue(rvThumb);
Address gotThumbFunc = space.getAddress(0x00510234);
long gotOffset = gotThumbFunc.getOffset() - pltEntry.getOffset() - 0x10000 - 8;
pltAsm.assemble("adr r12, 0x%s".formatted(pltEntry.add(8))); //("add r12, pc, #0, 12"); ?
pltAsm.assemble("add r12, r12, #0x10000"); // #16, 20");
// Assembler bug doesn't allow space in , # in this case
pltAsm.assemble("ldr pc, [r12,#0x%x]!".formatted(gotOffset));
Address funcEntry = space.getAddress(0x00400000);
AssemblyBuffer funcAsm = new AssemblyBuffer(asm, funcEntry);
funcAsm.assemble("adds r0, #1", ctxThumb);
Address funcEnd = funcAsm.getNext();
byte[] pltBytes = pltAsm.getBytes();
emu.getSharedState().setVar(pltEntry, pltBytes.length, false, pltBytes);
byte[] funcBytes = funcAsm.getBytes();
emu.getSharedState().setVar(funcEntry, funcBytes.length, false, funcBytes);
// +1 for THUMB mode
byte[] gotBytes = arithmetic.fromConst(funcEntry.getOffset() + 1, 4);
emu.getSharedState().setVar(gotThumbFunc, gotBytes.length, false, gotBytes);
PcodeThread<byte[]> thread = emu.newThread();
thread.overrideCounter(pltEntry);
thread.overrideContextWithDefault();
try {
thread.run();
}
catch (DecodePcodeExecutionException e) {
assertEquals(funcEnd, e.getProgramCounter());
}
Register r0 = emu.getLanguage().getRegister("r0");
assertEquals(1,
arithmetic.toLong(thread.getState().getVar(r0, Reason.INSPECT), Purpose.INSPECT));
}
}
@@ -2213,12 +2213,11 @@ public class JitCodeGeneratorTest extends AbstractJitTest {
Translation tr = translateLang(ID_TOYBE64, 0x00400000, """
imm r0,#123
add r0,#7
""",
Map.ofEntries(
Map.entry(0x00400002L, """
r1 = sleigh_userop(r0, 4:8);
emu_exec_decoded();
""")));
""", Map.ofEntries(
Map.entry(0x00400002L, """
r1 = sleigh_userop(r0, 4:8);
emu_exec_decoded();
""")));
tr.runDecodeErr(0x00400004);
assertEquals(123 + 7, tr.getLongRegVal("r0"));
@@ -2230,12 +2229,11 @@ public class JitCodeGeneratorTest extends AbstractJitTest {
Translation tr = translateLang(ID_TOYBE64, 0x00400000, """
imm r0,#123
add r0,#7
""",
Map.ofEntries(
Map.entry(0x00400002L, """
r1 = sleigh_userop(r0, 4:8);
emu_skip_decoded();
""")));
""", Map.ofEntries(
Map.entry(0x00400002L, """
r1 = sleigh_userop(r0, 4:8);
emu_skip_decoded();
""")));
tr.runDecodeErr(0x00400004);
assertEquals(123, tr.getLongRegVal("r0"));
@@ -2260,4 +2258,57 @@ public class JitCodeGeneratorTest extends AbstractJitTest {
}).count();
assertEquals(1, countSCarrys);
}
@Test
public void testCtxHazardousFallthrough() throws Exception {
Translation tr = translateLang(ID_ARMv8LE, 0x00400000, """
mov r0,#6
mov r1,#7
""", Map.ofEntries(
Map.entry(0x00400000L, """
setISAMode(1:1);
emu_exec_decoded();
""")));
tr.runClean();
assertEquals(6, tr.getLongRegVal("r0"));
// Should not execute second instruction, because of injected ctx change
assertEquals(0, tr.getLongRegVal("r1"));
}
@Test
public void testCtxMaybeHazardousFallthrough() throws Exception {
/**
* For this test to produce the "MAYBE" case, the multiple paths have to be
* <em>internal</em> to an instruction (or inject). All that logic is only applied on an
* instruction-by-instruction basis.
*/
Translation tr = translateLang(ID_ARMv8LE, 0x00400000, """
mov r0,#6
mov r1,#7
""", Map.ofEntries(
Map.entry(0x00400000L, """
if (!ZR) goto <skip>;
ISAModeSwitch = 1;
setISAMode(ISAModeSwitch);
<skip>
emu_exec_decoded();
""")));
tr.setLongRegVal("r1", 0); // Reset
tr.setLongRegVal("ZR", 0);
// Since ctx wasn't touched at runtime, we fall out of program
tr.runDecodeErr(0x00400008);
assertEquals(6, tr.getLongRegVal("r0"));
assertEquals(7, tr.getLongRegVal("r1"));
assertEquals(0, tr.getLongRegVal("ISAModeSwitch"));
tr.setLongRegVal("r1", 0); // Reset
tr.setLongRegVal("ZR", 1);
// Hazard causes exit before 2nd instruction
tr.runClean();
assertEquals(6, tr.getLongRegVal("r0"));
assertEquals(0, tr.getLongRegVal("r1"));
assertEquals(1, tr.getLongRegVal("ISAModeSwitch"));
}
}