GP-3571: Emulator heeds globalset

This commit is contained in:
Dan 2023-06-28 15:43:51 -04:00
parent ba53037d3d
commit 79992c1d9c
3 changed files with 153 additions and 2 deletions

View File

@ -940,8 +940,44 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
assertEquals(BigInteger.valueOf(0x0010fff8),
regs.getValue(x64, 1, tb.reg(x64, "RSP")).getUnsignedValue());
assertEquals(new BigInteger("efbeed0d00000000",16), // Guest is LE, host is BE
assertEquals(new BigInteger("efbeed0d00000000", 16), // Guest is LE, host is BE
TraceSleighUtils.evaluate(changedExpr, tb.trace, 1, thread, 0));
}
}
@Test
public void testITECC_VMOVCCF32() throws Throwable {
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "ARM:LE:32:v8T")) {
TraceThread thread = initTrace(tb, """
pc = 0x00400000;
sp = 0x00110000;
s1 = 0x12341234;
CY = 1;
""",
List.of(
"ite cc"));
//"vmov.cc.f32 s1,0xbf000000"));
try (Transaction tx = tb.startTransaction()) {
tb.trace.getMemoryManager()
.putBytes(0, tb.addr(0x00400002), tb.buf(0xfe, 0xee, 0x00, 0x0a));
}
BytesTracePcodeEmulator emu = new BytesTracePcodeEmulator(tb.host, 0);
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
emuThread.stepInstruction();
emuThread.stepPcodeOp(); // decode
assertEquals("vmov.cc.f32 s1,0xbf000000", emuThread.getInstruction().toString());
emuThread.finishInstruction();
try (Transaction tx = tb.startTransaction()) {
emu.writeDown(tb.host, 1, 1);
}
assertEquals(BigInteger.valueOf(0x00400006),
TraceSleighUtils.evaluate("pc", tb.trace, 1, thread, 0));
assertEquals(BigInteger.valueOf(0x12341234), // Unaffected
TraceSleighUtils.evaluate("s1", tb.trace, 1, thread, 0));
}
}
}

View File

@ -20,6 +20,8 @@ import java.util.*;
import ghidra.app.emulator.Emulator;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.app.plugin.processors.sleigh.SleighParserContext;
import ghidra.app.util.PseudoInstruction;
import ghidra.pcode.exec.*;
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
@ -27,6 +29,7 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.util.ProgramContextImpl;
import ghidra.util.Msg;
@ -457,6 +460,33 @@ public class DefaultPcodeThread<T> implements PcodeThread<T> {
}
}
protected RegisterValue getContextAfterCommits() {
PseudoInstruction pins = (PseudoInstruction) instruction;
try {
SleighParserContext parserCtx = (SleighParserContext) pins.getParserContext();
var procCtx = new DisassemblerContextAdapter() {
RegisterValue ctxVal = new RegisterValue(language.getContextBaseRegister());
@Override
public void setFutureRegisterValue(Address address, RegisterValue value) {
if (!value.getRegister().isProcessorContext()) {
return;
}
if (!address.equals(counter)) {
Msg.warn(this, "Context applied somewhere other than the counter.");
return;
}
ctxVal = ctxVal.assign(value.getRegister(), value);
}
};
parserCtx.applyCommits(procCtx);
return procCtx.ctxVal;
}
catch (MemoryAccessException e) {
throw new AssertionError(e);
}
}
/**
* Resolve a finished instruction, advancing the program counter if necessary
*/
@ -469,7 +499,10 @@ public class DefaultPcodeThread<T> implements PcodeThread<T> {
overrideCounter(counter.addWrap(decoder.getLastLengthWithDelays()));
}
if (contextreg != Register.NO_CONTEXT) {
overrideContext(defaultContext.getFlowValue(instruction.getRegisterValue(contextreg)));
RegisterValue flowCtx =
defaultContext.getFlowValue(instruction.getRegisterValue(contextreg));
RegisterValue commitCtx = getContextAfterCommits();
overrideContext(flowCtx.combineValues(commitCtx));
}
postExecuteInstruction();
frame = null;

View File

@ -0,0 +1,82 @@
/* ###
* 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.pcode.emu;
import java.math.BigInteger;
import java.util.List;
import ghidra.program.model.address.Address;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.ContextChangeException;
public interface DisassemblerContextAdapter extends DisassemblerContext {
@Override
default Register getBaseContextRegister() {
throw new UnsupportedOperationException();
}
@Override
default List<Register> getRegisters() {
throw new UnsupportedOperationException();
}
@Override
default Register getRegister(String name) {
throw new UnsupportedOperationException();
}
@Override
default BigInteger getValue(Register register, boolean signed) {
throw new UnsupportedOperationException();
}
@Override
default RegisterValue getRegisterValue(Register register) {
throw new UnsupportedOperationException();
}
@Override
default boolean hasValue(Register register) {
throw new UnsupportedOperationException();
}
@Override
default void setValue(Register register, BigInteger value)
throws ContextChangeException {
throw new UnsupportedOperationException();
}
@Override
default void setRegisterValue(RegisterValue value) throws ContextChangeException {
throw new UnsupportedOperationException();
}
@Override
default void clearRegister(Register register) throws ContextChangeException {
throw new UnsupportedOperationException();
}
@Override
default void setFutureRegisterValue(Address address, RegisterValue value) {
throw new UnsupportedOperationException();
}
@Override
default void setFutureRegisterValue(Address fromAddr, Address toAddr,
RegisterValue value) {
throw new UnsupportedOperationException();
}
}