GP-5460: Fix branching from injected p-code in emulation.

This commit is contained in:
Dan 2025-03-24 20:04:23 +00:00
parent 6b24b84bd8
commit f0a9e138e2
2 changed files with 96 additions and 3 deletions

View file

@ -474,7 +474,7 @@ public class PcodeExecutor<T> {
}
else {
branchToOffset(op, target.getOffset(), frame);
branchToAddress(op, target);
branchToAddress(op, checkInjectedTarget(target));
}
}
@ -530,6 +530,28 @@ public class PcodeExecutor<T> {
return op.getInput(0);
}
/**
* Check and correct the given target address, if it resides in "NO ADDRESS" space.
*
* <p>
* At some point, we made a change to set the "target address" of compiled p-code userops to
* {@link Address#NO_ADDRESS} instead of pretending its at {@code ram:00000000}. This is
* philosophically cleaner, but leads to a practical issue in that the p-code compiler sets the
* target address of any branch to be in the same space, which for injects, will wind up in "NO
* ADDRESS." I don't know the use case for having target addresses anywhere but default space,
* so I'll maintain that behavior, but if it ever lands in "NO ADDRESS," we're going to assume
* it was an inject, and that the intended target was the default space.
*
* @param target the proposed target address
* @return the same or corrected target address
*/
protected Address checkInjectedTarget(Address target) {
if (target.getAddressSpace() != Address.NO_ADDRESS.getAddressSpace()) {
return target;
}
return language.getDefaultSpace().getAddress(target.getOffset());
}
/**
* Perform the actual logic of an indirect branch p-code op
*
@ -548,7 +570,7 @@ public class PcodeExecutor<T> {
long concrete = arithmetic.toLong(offset, Purpose.BRANCH);
Address target = op.getSeqnum().getTarget().getNewAddress(concrete, true);
branchToAddress(op, target);
branchToAddress(op, checkInjectedTarget(target));
}
/**
@ -576,7 +598,7 @@ public class PcodeExecutor<T> {
public void executeCall(PcodeOp op, PcodeFrame frame, PcodeUseropLibrary<T> library) {
Address target = getBranchTarget(op);
branchToOffset(op, target.getOffset(), frame);
branchToAddress(op, target);
branchToAddress(op, checkInjectedTarget(target));
}
/**

View file

@ -298,4 +298,75 @@ public abstract class AbstractPcodeEmulatorTest extends AbstractGTest {
arithmetic.toLong(thread.getState().getVar(r1, Reason.INSPECT), Purpose.INSPECT));
assertEquals(inject, thread.getCounter());
}
@Test
public void testInjectedBranch() throws Exception {
PcodeEmulator emu = createEmulator(getLanguage(LANGID_TOY_BE));
PcodeArithmetic<byte[]> arithmetic = emu.getArithmetic();
AddressSpace space = emu.getLanguage().getDefaultSpace();
AssemblyBuffer asm = new AssemblyBuffer(Assemblers.getAssembler(emu.getLanguage()),
space.getAddress(0x00400000));
asm.assemble("imm r1, #1");
Address inject = asm.getNext();
asm.assemble("add r1, #1");
Address target = asm.getNext();
byte[] bytes = asm.getBytes();
emu.getSharedState().setVar(asm.getEntry(), bytes.length, false, bytes);
PcodeThread<byte[]> thread = emu.newThread();
thread.overrideCounter(asm.getEntry());
emu.inject(inject, "goto 0x%08x;".formatted(target.getOffset()));
try {
thread.run();
fail("Should have crashed on decode error");
}
catch (DecodePcodeExecutionException e) {
// Space assertion is subsumed by counter assertion
}
Register r1 = emu.getLanguage().getRegister("r1");
assertEquals(1,
arithmetic.toLong(thread.getState().getVar(r1, Reason.INSPECT), Purpose.INSPECT));
assertEquals(target, thread.getCounter());
}
@Test
public void testInjectedIndirectBranch() throws Exception {
PcodeEmulator emu = createEmulator(getLanguage(LANGID_TOY_BE));
PcodeArithmetic<byte[]> arithmetic = emu.getArithmetic();
AddressSpace space = emu.getLanguage().getDefaultSpace();
AssemblyBuffer asm = new AssemblyBuffer(Assemblers.getAssembler(emu.getLanguage()),
space.getAddress(0x00400000));
asm.assemble("imm r1, #1");
Address inject = asm.getNext();
asm.assemble("add r1, #1");
Address target = asm.getNext();
byte[] bytes = asm.getBytes();
emu.getSharedState().setVar(asm.getEntry(), bytes.length, false, bytes);
PcodeThread<byte[]> thread = emu.newThread();
thread.overrideCounter(asm.getEntry());
emu.inject(inject, """
r2 = 0x%08x;
goto [r2];
""".formatted(target.getOffset()));
try {
thread.run();
fail("Should have crashed on decode error");
}
catch (DecodePcodeExecutionException e) {
// Space assertion is subsumed by counter assertion
}
Register r1 = emu.getLanguage().getRegister("r1");
assertEquals(1,
arithmetic.toLong(thread.getState().getVar(r1, Reason.INSPECT), Purpose.INSPECT));
assertEquals(target, thread.getCounter());
}
}