mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-14 16:12:14 +00:00
GP-3571: Emulator heeds globalset
This commit is contained in:
parent
ba53037d3d
commit
79992c1d9c
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user