mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-01 09:15:09 +08:00
Merge remote-tracking branch 'origin/GP-5301_Dan_testEmuThumbPlt'
This commit is contained in:
+59
-4
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
+63
-12
@@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user