mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-09-13 21:56:19 +00:00
GP-1650: Introduce Reason for reading state. Fix spurrious uninit warnings.
This commit is contained in:
parent
45165ea167
commit
dcd54c6695
|
@ -37,6 +37,7 @@ import ghidra.app.services.ProgramManager;
|
|||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.pcode.emu.PcodeThread;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.pcode.exec.trace.TraceSleighUtils;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
|
@ -191,8 +192,8 @@ public class DebuggerEmuExampleScript extends GhidraScript {
|
|||
* This works the same as in the stand-alone case.
|
||||
*/
|
||||
println("RCX = " +
|
||||
Utils.bytesToLong(thread.getState().getVar(language.getRegister("RCX")), 8,
|
||||
language.isBigEndian()));
|
||||
Utils.bytesToLong(thread.getState().getVar(language.getRegister("RCX"), Reason.INSPECT),
|
||||
8, language.isBigEndian()));
|
||||
|
||||
println("RCX = " + Utils.bytesToLong(
|
||||
SleighProgramCompiler.compileExpression(language, "RCX").evaluate(thread.getExecutor()),
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.List;
|
|||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.pcode.struct.StructuredSleigh;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
@ -75,17 +76,19 @@ public class DemoPcodeUseropLibrary extends AnnotatedPcodeUseropLibrary<byte[]>
|
|||
* @return the length of the string in bytes
|
||||
*/
|
||||
@PcodeUserop
|
||||
public byte[] print_utf8(@OpState PcodeExecutorState<byte[]> state, byte[] start) {
|
||||
public byte[] print_utf8(@OpExecutor PcodeExecutor<byte[]> executor, byte[] start) {
|
||||
PcodeExecutorState<byte[]> state = executor.getState();
|
||||
long offset = Utils.bytesToLong(start, start.length, language.isBigEndian());
|
||||
long end = offset;
|
||||
while (state.getVar(space, end, 1, true)[0] != 0) {
|
||||
Reason reason = executor.getReason();
|
||||
while (state.getVar(space, end, 1, true, reason)[0] != 0) {
|
||||
end++;
|
||||
}
|
||||
if (end == offset) {
|
||||
script.println("");
|
||||
return Utils.longToBytes(0, Long.BYTES, language.isBigEndian());
|
||||
}
|
||||
byte[] bytes = state.getVar(space, offset, (int) (end - offset), true);
|
||||
byte[] bytes = state.getVar(space, offset, (int) (end - offset), true, reason);
|
||||
String str = new String(bytes, UTF8);
|
||||
script.println(str);
|
||||
return Utils.longToBytes(end - offset, Long.BYTES, language.isBigEndian());
|
||||
|
|
|
@ -24,6 +24,7 @@ import ghidra.pcode.emu.sys.AnnotatedEmuSyscallUseropLibrary;
|
|||
import ghidra.pcode.emu.sys.EmuSyscallLibrary;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.pcode.struct.StructuredSleigh;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
@ -102,13 +103,15 @@ public class DemoSyscallLibrary extends AnnotatedEmuSyscallUseropLibrary<byte[]>
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* The dispatcher doesn't know where the system call number is stored. It relies on this method
|
||||
* to read that number from the state. Here we'll assume the target is x64 and RAX contains the
|
||||
* syscall number.
|
||||
*/
|
||||
@Override
|
||||
public long readSyscallNumber(PcodeExecutorStatePiece<byte[], byte[]> state) {
|
||||
return Utils.bytesToLong(state.getVar(regRAX), regRAX.getNumBytes(),
|
||||
public long readSyscallNumber(PcodeExecutorState<byte[]> state, Reason reason) {
|
||||
return Utils.bytesToLong(state.getVar(regRAX, reason), regRAX.getNumBytes(),
|
||||
machine.getLanguage().isBigEndian());
|
||||
}
|
||||
|
||||
|
@ -165,7 +168,7 @@ public class DemoSyscallLibrary extends AnnotatedEmuSyscallUseropLibrary<byte[]>
|
|||
*/
|
||||
@PcodeUserop
|
||||
@EmuSyscall("write")
|
||||
public void demo_write(byte[] str, byte[] end) {
|
||||
public void demo_write(@OpExecutor PcodeExecutor<byte[]> executor, byte[] str, byte[] end) {
|
||||
AddressSpace space = machine.getLanguage().getDefaultSpace();
|
||||
/**
|
||||
* Because we have concrete {@code byte[]}, we could use Utils.bytesToLong, but for
|
||||
|
@ -178,8 +181,8 @@ public class DemoSyscallLibrary extends AnnotatedEmuSyscallUseropLibrary<byte[]>
|
|||
long strLong = arithmetic.toLong(str, Purpose.LOAD);
|
||||
long endLong = arithmetic.toLong(end, Purpose.OTHER);
|
||||
|
||||
byte[] stringBytes =
|
||||
machine.getSharedState().getVar(space, strLong, (int) (endLong - strLong), true);
|
||||
byte[] stringBytes = machine.getSharedState()
|
||||
.getVar(space, strLong, (int) (endLong - strLong), true, executor.getReason());
|
||||
String string = new String(stringBytes, UTF8);
|
||||
script.println(string);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import ghidra.app.script.GhidraScript;
|
|||
import ghidra.pcode.emu.PcodeEmulator;
|
||||
import ghidra.pcode.emu.PcodeThread;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
@ -136,8 +137,8 @@ public class StandAloneEmuExampleScript extends GhidraScript {
|
|||
* convenient.
|
||||
*/
|
||||
println("RCX = " +
|
||||
Utils.bytesToLong(thread.getState().getVar(language.getRegister("RCX")), 8,
|
||||
language.isBigEndian()));
|
||||
Utils.bytesToLong(thread.getState().getVar(language.getRegister("RCX"), Reason.INSPECT),
|
||||
8, language.isBigEndian()));
|
||||
|
||||
println("RCX = " + Utils.bytesToLong(
|
||||
SleighProgramCompiler.compileExpression(language, "RCX").evaluate(thread.getExecutor()),
|
||||
|
|
|
@ -32,6 +32,7 @@ import ghidra.pcode.emu.PcodeThread;
|
|||
import ghidra.pcode.emu.sys.EmuInvalidSystemCallException;
|
||||
import ghidra.pcode.emu.sys.EmuSyscallLibrary;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.model.address.*;
|
||||
|
@ -210,7 +211,8 @@ public class StandAloneSyscallEmuExampleScript extends GhidraScript {
|
|||
* convenient.
|
||||
*/
|
||||
println("RDI = " +
|
||||
Utils.bytesToLong(thread.getState().getVar(language.getRegister("RDI")), 8,
|
||||
Utils.bytesToLong(
|
||||
thread.getState().getVar(language.getRegister("RDI"), Reason.INSPECT), 8,
|
||||
language.isBigEndian()));
|
||||
|
||||
println("RDI = " + Utils.bytesToLong(
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.stream.Stream;
|
|||
import ghidra.docking.settings.SettingsImpl;
|
||||
import ghidra.pcode.exec.PcodeArithmetic;
|
||||
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.pcode.exec.PcodeExecutorState;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
@ -65,11 +66,11 @@ public class UniqueRow {
|
|||
}
|
||||
|
||||
public byte[] getBytes(Varnode vn) {
|
||||
return arithmetic.toConcrete(state.getVar(vn), Purpose.INSPECT);
|
||||
return arithmetic.toConcrete(state.getVar(vn, Reason.INSPECT), Purpose.INSPECT);
|
||||
}
|
||||
|
||||
public BigInteger getValue(Varnode vn) {
|
||||
return arithmetic.toBigInteger(state.getVar(vn), Purpose.INSPECT);
|
||||
return arithmetic.toBigInteger(state.getVar(vn, Reason.INSPECT), Purpose.INSPECT);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ import ghidra.docking.settings.Settings;
|
|||
import ghidra.docking.settings.SettingsImpl;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.pcode.exec.trace.*;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.address.*;
|
||||
|
@ -185,8 +186,9 @@ public class WatchRow {
|
|||
}
|
||||
|
||||
@Override
|
||||
public byte[] getVar(AddressSpace space, long offset, int size, boolean quantize) {
|
||||
byte[] data = super.getVar(space, offset, size, quantize);
|
||||
public byte[] getVar(AddressSpace space, long offset, int size, boolean quantize,
|
||||
Reason reason) {
|
||||
byte[] data = super.getVar(space, offset, size, quantize, reason);
|
||||
if (space.isMemorySpace()) {
|
||||
offset = quantizeOffset(space, offset);
|
||||
}
|
||||
|
@ -222,7 +224,7 @@ public class WatchRow {
|
|||
public ReadDepsPcodeExecutor(ReadDepsTraceBytesPcodeExecutorStatePiece depsState,
|
||||
SleighLanguage language, PairedPcodeArithmetic<byte[], Address> arithmetic,
|
||||
PcodeExecutorState<Pair<byte[], Address>> state) {
|
||||
super(language, arithmetic, state);
|
||||
super(language, arithmetic, state, Reason.INSPECT);
|
||||
this.depsPiece = depsState;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,25 +47,25 @@ public abstract class AbstractRWTargetPcodeExecutorStatePiece
|
|||
protected abstract void fillUninitialized(AddressSet uninitialized);
|
||||
|
||||
@Override
|
||||
public byte[] read(long offset, int size) {
|
||||
public byte[] read(long offset, int size, Reason reason) {
|
||||
if (backing != null) {
|
||||
AddressSet uninitialized =
|
||||
addrSet(bytes.getUninitialized(offset, offset + size - 1));
|
||||
if (uninitialized.isEmpty()) {
|
||||
return super.read(offset, size);
|
||||
return super.read(offset, size, reason);
|
||||
}
|
||||
|
||||
fillUninitialized(uninitialized);
|
||||
|
||||
AddressSetView unknown = backing.intersectUnknown(
|
||||
addrSet(bytes.getUninitialized(offset, offset + size - 1)));
|
||||
if (!unknown.isEmpty()) {
|
||||
if (!unknown.isEmpty() && reason == Reason.EXECUTE) {
|
||||
warnUnknown(unknown);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: What to flush when bytes in the trace change?
|
||||
return super.read(offset, size);
|
||||
return super.read(offset, size, reason);
|
||||
}
|
||||
|
||||
protected <T> T waitTimeout(CompletableFuture<T> future) {
|
||||
|
|
|
@ -21,6 +21,7 @@ import ghidra.app.plugin.core.debug.service.emulation.data.DefaultPcodeDebuggerA
|
|||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.pcode.emu.ThreadPcodeExecutorState;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.guest.TracePlatform;
|
||||
|
@ -83,6 +84,7 @@ public enum DebuggerPcodeUtils {
|
|||
PcodeExecutorState<byte[]> state = executorStateForCoordinates(tool, coordinates);
|
||||
|
||||
SleighLanguage slang = (SleighLanguage) state.getLanguage();
|
||||
return new PcodeExecutor<>(slang, BytesPcodeArithmetic.forLanguage(slang), state);
|
||||
return new PcodeExecutor<>(slang, BytesPcodeArithmetic.forLanguage(slang), state,
|
||||
Reason.INSPECT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import ghidra.app.services.DebuggerEmulationService;
|
|||
import ghidra.app.services.DebuggerTraceManagerService;
|
||||
import ghidra.pcode.emu.PcodeThread;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.pcode.exec.trace.TraceSleighUtils;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
|
@ -171,7 +172,7 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
|||
PcodeProgram prog = SleighProgramCompiler.compileProgram(language, "test", sleigh,
|
||||
PcodeUseropLibrary.nil());
|
||||
PcodeExecutor<byte[]> executor =
|
||||
new PcodeExecutor<>(language, BytesPcodeArithmetic.BIG_ENDIAN, null);
|
||||
new PcodeExecutor<>(language, BytesPcodeArithmetic.BIG_ENDIAN, null, Reason.INSPECT);
|
||||
PcodeFrame frame = executor.begin(prog);
|
||||
PcodeRowHtmlFormatter formatter = pcodeProvider.new PcodeRowHtmlFormatter(language, frame);
|
||||
return formatter.getRows();
|
||||
|
|
|
@ -30,6 +30,7 @@ import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
|||
import ghidra.app.services.ActionSource;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.dbg.model.TestTargetRegisterBankInThread;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.pcode.exec.trace.DirectBytesTracePcodeExecutorState;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.lang.Register;
|
||||
|
@ -126,7 +127,7 @@ public class TraceRecorderPcodeExecTest extends AbstractGhidraHeadedDebuggerGUIT
|
|||
|
||||
executor.execute(prog, PcodeUseropLibrary.nil());
|
||||
// Ignore return value. We'll assert that it got written to the trace
|
||||
executor.state.getVar(language.getRegister("r2"));
|
||||
executor.state.getVar(language.getRegister("r2"), Reason.INSPECT);
|
||||
|
||||
assertEquals(BigInteger.valueOf(11), new BigInteger(1, regs.regVals.get("r2")));
|
||||
}
|
||||
|
|
|
@ -41,14 +41,14 @@ public abstract class AbstractCheckedTraceCachedWriteBytesPcodeExecutorStatePiec
|
|||
}
|
||||
|
||||
@Override
|
||||
public byte[] read(long offset, int size) {
|
||||
public byte[] read(long offset, int size, Reason reason) {
|
||||
RangeSet<UnsignedLong> uninitialized =
|
||||
bytes.getUninitialized(offset, offset + size - 1);
|
||||
if (!uninitialized.isEmpty()) {
|
||||
size = checkUninitialized(backing, space.getAddress(offset), size,
|
||||
addrSet(uninitialized));
|
||||
}
|
||||
return super.read(offset, size);
|
||||
return super.read(offset, size, reason);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ public class DirectBytesTracePcodeExecutorStatePiece
|
|||
}
|
||||
|
||||
@Override
|
||||
protected byte[] getUnique(long offset, int size) {
|
||||
protected byte[] getUnique(long offset, int size, Reason reason) {
|
||||
byte[] data = new byte[size];
|
||||
unique.getData(offset, data);
|
||||
return data;
|
||||
|
@ -120,7 +120,7 @@ public class DirectBytesTracePcodeExecutorStatePiece
|
|||
}
|
||||
|
||||
@Override
|
||||
protected byte[] getFromSpace(AddressSpace space, long offset, int size) {
|
||||
protected byte[] getFromSpace(AddressSpace space, long offset, int size, Reason reason) {
|
||||
ByteBuffer buf = ByteBuffer.allocate(size);
|
||||
int read = data.getBytes(space.getAddress(offset), buf);
|
||||
if (read != size) {
|
||||
|
|
|
@ -78,7 +78,7 @@ public class TraceMemoryStatePcodeExecutorStatePiece extends
|
|||
}
|
||||
|
||||
@Override
|
||||
protected TraceMemoryState getUnique(long offset, int size) {
|
||||
protected TraceMemoryState getUnique(long offset, int size, Reason reason) {
|
||||
RangeSet<UnsignedLong> remains = TreeRangeSet.create();
|
||||
Range<UnsignedLong> range = range(offset, size);
|
||||
remains.add(range);
|
||||
|
@ -106,12 +106,13 @@ public class TraceMemoryStatePcodeExecutorStatePiece extends
|
|||
}
|
||||
|
||||
@Override
|
||||
protected TraceMemoryState getFromSpace(AddressSpace space, long offset, int size) {
|
||||
protected TraceMemoryState getFromSpace(AddressSpace space, long offset, int size,
|
||||
Reason reason) {
|
||||
return data.getViewportState(range(space, offset, size));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceMemoryState getFromNullSpace(int size) {
|
||||
protected TraceMemoryState getFromNullSpace(int size, Reason reason) {
|
||||
return TraceMemoryState.UNKNOWN;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.commons.lang3.tuple.Pair;
|
|||
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
@ -61,7 +62,7 @@ public enum TraceSleighUtils {
|
|||
throw new IllegalArgumentException("TracePlatform must use a SLEIGH language");
|
||||
}
|
||||
return new PcodeExecutor<>((SleighLanguage) language,
|
||||
BytesPcodeArithmetic.forLanguage(language), state);
|
||||
BytesPcodeArithmetic.forLanguage(language), state, Reason.INSPECT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,7 +103,7 @@ public enum TraceSleighUtils {
|
|||
}
|
||||
return new PcodeExecutor<>((SleighLanguage) language, new PairedPcodeArithmetic<>(
|
||||
BytesPcodeArithmetic.forLanguage(language), TraceMemoryStatePcodeArithmetic.INSTANCE),
|
||||
paired);
|
||||
paired, Reason.INSPECT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,13 +29,12 @@ import com.google.common.collect.Range;
|
|||
|
||||
import ghidra.app.plugin.assembler.*;
|
||||
import ghidra.app.plugin.assembler.sleigh.sem.AssemblyPatternBlock;
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.dbg.target.schema.SchemaContext;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
|
||||
import ghidra.dbg.target.schema.XmlSchemaContext;
|
||||
import ghidra.lifecycle.Unfinished;
|
||||
import ghidra.pcode.emu.PcodeThread;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.pcode.exec.trace.data.PcodeTraceDataAccess;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressRangeImpl;
|
||||
|
@ -158,7 +157,7 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
|
||||
assertEquals(tb.addr(0x00400007), emuThread.getCounter());
|
||||
assertArrayEquals(tb.arr(0x07, 0, 0x40, 0, 0, 0, 0, 0),
|
||||
emuThread.getState().getVar(pc));
|
||||
emuThread.getState().getVar(pc, Reason.INSPECT));
|
||||
|
||||
emuThread.stepInstruction();
|
||||
|
||||
|
@ -220,11 +219,11 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
|
||||
assertEquals(tb.addr(0x00401000), emuThread.getCounter());
|
||||
assertArrayEquals(tb.arr(0, 0x10, 0x40, 0),
|
||||
emuThread.getState().getVar(pc));
|
||||
emuThread.getState().getVar(pc, Reason.INSPECT));
|
||||
assertEquals(new RegisterValue(ctxreg, BigInteger.valueOf(0x8000_0000_0000_0000L)),
|
||||
emuThread.getContext());
|
||||
assertArrayEquals(tb.arr(0x80, 0, 0, 0, 0, 0, 0, 0),
|
||||
emuThread.getState().getVar(ctxreg));
|
||||
emuThread.getState().getVar(ctxreg, Reason.INSPECT));
|
||||
|
||||
emuThread.stepInstruction();
|
||||
|
||||
|
@ -610,7 +609,7 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
|
||||
assertEquals(tb.addr(0x00400007), emuThread.getCounter());
|
||||
assertArrayEquals(tb.arr(0x07, 0, 0x40, 0, 0, 0, 0, 0),
|
||||
emuThread.getState().getVar(pc));
|
||||
emuThread.getState().getVar(pc, Reason.INSPECT));
|
||||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
emu.writeDown(tb.host, 1, 1);
|
||||
|
@ -647,7 +646,7 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
|
||||
assertEquals(tb.addr(0x00400002), emuThread.getCounter());
|
||||
assertArrayEquals(tb.arr(0x02, 0, 0x40, 0, 0, 0, 0, 0),
|
||||
emuThread.getState().getVar(pc));
|
||||
emuThread.getState().getVar(pc, Reason.INSPECT));
|
||||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
emu.writeDown(tb.host, 1, 1);
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.junit.Test;
|
|||
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.util.DefaultLanguageService;
|
||||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||
|
@ -220,7 +221,8 @@ public class TraceSleighUtilsTest extends AbstractGhidraHeadlessIntegrationTest
|
|||
PcodeExecutor<byte[]> executor =
|
||||
new PcodeExecutor<>(sp.getLanguage(),
|
||||
BytesPcodeArithmetic.forLanguage(b.language),
|
||||
new DirectBytesTracePcodeExecutorState(b.host, 0, thread, 0));
|
||||
new DirectBytesTracePcodeExecutorState(b.host, 0, thread, 0),
|
||||
Reason.EXECUTE);
|
||||
sp.execute(executor, PcodeUseropLibrary.nil());
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
|||
import ghidra.pcode.emu.PcodeThread;
|
||||
import ghidra.pcode.emu.ThreadPcodeExecutorState;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
|
@ -61,7 +62,7 @@ class TestThread implements PcodeThread<Void> {
|
|||
@Override
|
||||
public PcodeExecutor<Void> getExecutor() {
|
||||
return new PcodeExecutor<>(TraceScheduleTest.TOY_BE_64_LANG, machine.getArithmetic(),
|
||||
getState()) {
|
||||
getState(), Reason.EXECUTE) {
|
||||
public PcodeFrame execute(PcodeProgram program, PcodeUseropLibrary<Void> library) {
|
||||
machine.record.add("x:" + name);
|
||||
// TODO: Verify the actual effect
|
||||
|
|
|
@ -22,6 +22,7 @@ import ghidra.app.emulator.Emulator;
|
|||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
|
@ -143,7 +144,7 @@ public class DefaultPcodeThread<T> implements PcodeThread<T> {
|
|||
* @param state the composite state assigned to the thread
|
||||
*/
|
||||
public PcodeThreadExecutor(DefaultPcodeThread<T> thread) {
|
||||
super(thread.language, thread.arithmetic, thread.state);
|
||||
super(thread.language, thread.arithmetic, thread.state, Reason.EXECUTE);
|
||||
this.thread = thread;
|
||||
}
|
||||
|
||||
|
@ -340,12 +341,13 @@ public class DefaultPcodeThread<T> implements PcodeThread<T> {
|
|||
|
||||
@Override
|
||||
public void reInitialize() {
|
||||
long offset = arithmetic.toLong(state.getVar(pc), Purpose.BRANCH);
|
||||
long offset = arithmetic.toLong(state.getVar(pc, executor.getReason()), Purpose.BRANCH);
|
||||
setCounter(language.getDefaultSpace().getAddress(offset, true));
|
||||
|
||||
if (contextreg != Register.NO_CONTEXT) {
|
||||
try {
|
||||
BigInteger ctx = arithmetic.toBigInteger(state.getVar(contextreg), Purpose.CONTEXT);
|
||||
BigInteger ctx = arithmetic.toBigInteger(state.getVar(
|
||||
contextreg, executor.getReason()), Purpose.CONTEXT);
|
||||
assignContext(new RegisterValue(contextreg, ctx));
|
||||
}
|
||||
catch (AccessPcodeExecutionException e) {
|
||||
|
|
|
@ -177,7 +177,7 @@ public class ModifiedPcodeThread<T> extends DefaultPcodeThread<T> {
|
|||
*/
|
||||
protected int getBytesChunk(byte[] res, AddressSpace spc, long off, int size,
|
||||
boolean stopOnUnintialized) {
|
||||
T t = state.getVar(spc, off, size, true);
|
||||
T t = state.getVar(spc, off, size, true, executor.getReason());
|
||||
byte[] val = arithmetic.toConcrete(t, Purpose.OTHER);
|
||||
System.arraycopy(val, 0, res, 0, val.length);
|
||||
return val.length;
|
||||
|
|
|
@ -82,11 +82,11 @@ public class ThreadPcodeExecutorState<T> implements PcodeExecutorState<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public T getVar(AddressSpace space, T offset, int size, boolean quantize) {
|
||||
public T getVar(AddressSpace space, T offset, int size, boolean quantize, Reason reason) {
|
||||
if (isThreadLocalSpace(space)) {
|
||||
return localState.getVar(space, offset, size, quantize);
|
||||
return localState.getVar(space, offset, size, quantize, reason);
|
||||
}
|
||||
return sharedState.getVar(space, offset, size, quantize);
|
||||
return sharedState.getVar(space, offset, size, quantize, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -26,7 +26,8 @@ import ghidra.pcode.emu.unix.EmuUnixFileSystem;
|
|||
import ghidra.pcode.emu.unix.EmuUnixUser;
|
||||
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
|
||||
import ghidra.pcode.exec.PcodeExecutor;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece;
|
||||
import ghidra.pcode.exec.PcodeExecutorState;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.model.lang.Register;
|
||||
|
@ -91,8 +92,8 @@ public class EmuLinuxAmd64SyscallUseropLibrary<T> extends AbstractEmuLinuxSyscal
|
|||
}
|
||||
|
||||
@Override
|
||||
public long readSyscallNumber(PcodeExecutorStatePiece<T, T> state) {
|
||||
return machine.getArithmetic().toLong(state.getVar(regRAX), Purpose.OTHER);
|
||||
public long readSyscallNumber(PcodeExecutorState<T> state, Reason reason) {
|
||||
return machine.getArithmetic().toLong(state.getVar(regRAX, reason), Purpose.OTHER);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,6 +27,7 @@ import ghidra.pcode.emu.unix.EmuUnixFileSystem;
|
|||
import ghidra.pcode.emu.unix.EmuUnixUser;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.FileDataTypeManager;
|
||||
import ghidra.program.model.lang.Register;
|
||||
|
@ -92,8 +93,8 @@ public class EmuLinuxX86SyscallUseropLibrary<T> extends AbstractEmuLinuxSyscallU
|
|||
}
|
||||
|
||||
@Override
|
||||
public long readSyscallNumber(PcodeExecutorStatePiece<T, T> state) {
|
||||
return machine.getArithmetic().toLong(state.getVar(regEAX), Purpose.OTHER);
|
||||
public long readSyscallNumber(PcodeExecutorState<T> state, Reason reason) {
|
||||
return machine.getArithmetic().toLong(state.getVar(regEAX, reason), Purpose.OTHER);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -121,7 +122,7 @@ public class EmuLinuxX86SyscallUseropLibrary<T> extends AbstractEmuLinuxSyscallU
|
|||
if (intNo == 0x80) {
|
||||
// A CALLIND follows to the return of swi().... OK.
|
||||
// We'll just make that "fall through" instead
|
||||
T next = executor.getState().getVar(regEIP);
|
||||
T next = executor.getState().getVar(regEIP, executor.getReason());
|
||||
PcodeThreadExecutor<T> te = (PcodeThreadExecutor<T>) executor;
|
||||
int pcSize = regEIP.getNumBytes();
|
||||
int iLen = te.getThread().getInstruction().getLength();
|
||||
|
|
|
@ -24,6 +24,7 @@ import generic.jar.ResourceFile;
|
|||
import ghidra.framework.Application;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.AnnotatedPcodeUseropLibrary.*;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.PrototypeModel;
|
||||
import ghidra.program.model.listing.Function;
|
||||
|
@ -206,9 +207,11 @@ public interface EmuSyscallLibrary<T> extends PcodeUseropLibrary<T> {
|
|||
* database. Until then, we require system-specific implementations.
|
||||
*
|
||||
* @param state the executor's state
|
||||
* @param the reason for reading state, probably {@link Reason#EXECUTE}, but should be taken
|
||||
* from the executor
|
||||
* @return the system call number
|
||||
*/
|
||||
long readSyscallNumber(PcodeExecutorStatePiece<T, T> state);
|
||||
long readSyscallNumber(PcodeExecutorState<T> state, Reason reason);
|
||||
|
||||
/**
|
||||
* Try to handle an error, usually by returning it to the user program
|
||||
|
@ -239,7 +242,7 @@ public interface EmuSyscallLibrary<T> extends PcodeUseropLibrary<T> {
|
|||
@PcodeUserop
|
||||
default void syscall(@OpExecutor PcodeExecutor<T> executor,
|
||||
@OpLibrary PcodeUseropLibrary<T> library) {
|
||||
long syscallNumber = readSyscallNumber(executor.getState());
|
||||
long syscallNumber = readSyscallNumber(executor.getState(), executor.getReason());
|
||||
EmuSyscallDefinition<T> syscall = getSyscalls().get(syscallNumber);
|
||||
if (syscall == null) {
|
||||
throw new EmuInvalidSystemCallException(syscallNumber);
|
||||
|
|
|
@ -24,6 +24,7 @@ import ghidra.pcode.emu.sys.EmuProcessExitedException;
|
|||
import ghidra.pcode.emu.unix.EmuUnixFileSystem.OpenFlag;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.data.StringDataInstance;
|
||||
import ghidra.program.model.data.StringDataType;
|
||||
|
@ -286,7 +287,7 @@ public abstract class AbstractEmuUnixSyscallUseropLibrary<T>
|
|||
// TODO: Not ideal to require concrete size. What are the alternatives, though?
|
||||
// TODO: size should actually be long (size_t)
|
||||
int size = (int) arithmetic.toLong(count, Purpose.OTHER);
|
||||
T buf = state.getVar(space, bufPtr, size, true);
|
||||
T buf = state.getVar(space, bufPtr, size, true, Reason.EXECUTE);
|
||||
// TODO: Write back into state? "write" shouldn't touch the buffer....
|
||||
return desc.write(buf);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ package ghidra.pcode.exec;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.Language;
|
||||
|
@ -68,7 +67,8 @@ public abstract class AbstractBytesPcodeExecutorStatePiece<S extends BytesPcodeE
|
|||
|
||||
@Override
|
||||
public int getBytes(ByteBuffer buffer, int addressOffset) {
|
||||
byte[] data = source.read(address.getOffset() + addressOffset, buffer.remaining());
|
||||
byte[] data = source.read(address.getOffset() + addressOffset, buffer.remaining(),
|
||||
Reason.EXECUTE);
|
||||
buffer.put(data);
|
||||
return data.length;
|
||||
}
|
||||
|
@ -129,8 +129,8 @@ public abstract class AbstractBytesPcodeExecutorStatePiece<S extends BytesPcodeE
|
|||
}
|
||||
|
||||
@Override
|
||||
protected byte[] getFromSpace(S space, long offset, int size) {
|
||||
byte[] read = space.read(offset, size);
|
||||
protected byte[] getFromSpace(S space, long offset, int size, Reason reason) {
|
||||
byte[] read = space.read(offset, size, reason);
|
||||
if (read.length != size) {
|
||||
throw new AccessPcodeExecutionException("Incomplete read (" + read.length +
|
||||
" of " + size + " bytes)");
|
||||
|
@ -139,7 +139,7 @@ public abstract class AbstractBytesPcodeExecutorStatePiece<S extends BytesPcodeE
|
|||
}
|
||||
|
||||
@Override
|
||||
public MemBuffer getConcreteBuffer(Address address, Purpose purpose) {
|
||||
public MemBuffer getConcreteBuffer(Address address, PcodeArithmetic.Purpose purpose) {
|
||||
return new StateMemBuffer(address, getForSpace(address.getAddressSpace(), false));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,11 +166,12 @@ public abstract class AbstractLongOffsetPcodeExecutorStatePiece<A, T, S>
|
|||
*
|
||||
* @param offset the offset in unique space to get the value
|
||||
* @param size the number of bytes to read (the size of the value)
|
||||
* @param reason the reason for reading state
|
||||
* @return the read value
|
||||
*/
|
||||
protected T getUnique(long offset, int size) {
|
||||
protected T getUnique(long offset, int size, Reason reason) {
|
||||
S s = getForSpace(uniqueSpace, false);
|
||||
return getFromSpace(s, offset, size);
|
||||
return getFromSpace(s, offset, size, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -200,9 +201,10 @@ public abstract class AbstractLongOffsetPcodeExecutorStatePiece<A, T, S>
|
|||
* @param space the address space
|
||||
* @param offset the offset within the space
|
||||
* @param size the number of bytes to read (the size of the value)
|
||||
* @param reason the reason for reading state
|
||||
* @return the read value
|
||||
*/
|
||||
protected abstract T getFromSpace(S space, long offset, int size);
|
||||
protected abstract T getFromSpace(S space, long offset, int size, Reason reason);
|
||||
|
||||
/**
|
||||
* In case spaces are generated lazily, and we're reading from a space that doesn't yet exist,
|
||||
|
@ -212,9 +214,10 @@ public abstract class AbstractLongOffsetPcodeExecutorStatePiece<A, T, S>
|
|||
* By default, the returned value is 0, which should be reasonable for all implementations.
|
||||
*
|
||||
* @param size the number of bytes to read (the size of the value)
|
||||
* @param reason the reason for reading state
|
||||
* @return the default value
|
||||
*/
|
||||
protected T getFromNullSpace(int size) {
|
||||
protected T getFromNullSpace(int size, Reason reason) {
|
||||
return arithmetic.fromConst(0, size);
|
||||
}
|
||||
|
||||
|
@ -240,25 +243,25 @@ public abstract class AbstractLongOffsetPcodeExecutorStatePiece<A, T, S>
|
|||
}
|
||||
|
||||
@Override
|
||||
public T getVar(AddressSpace space, A offset, int size, boolean quantize) {
|
||||
public T getVar(AddressSpace space, A offset, int size, boolean quantize, Reason reason) {
|
||||
long lOffset = addressArithmetic.toLong(offset, Purpose.LOAD);
|
||||
return getVar(space, lOffset, size, quantize);
|
||||
return getVar(space, lOffset, size, quantize, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getVar(AddressSpace space, long offset, int size, boolean quantize) {
|
||||
public T getVar(AddressSpace space, long offset, int size, boolean quantize, Reason reason) {
|
||||
checkRange(space, offset, size);
|
||||
if (space.isConstantSpace()) {
|
||||
return arithmetic.fromConst(offset, size);
|
||||
}
|
||||
if (space.isUniqueSpace()) {
|
||||
return getUnique(offset, size);
|
||||
return getUnique(offset, size, reason);
|
||||
}
|
||||
S s = getForSpace(space, false);
|
||||
if (s == null) {
|
||||
return getFromNullSpace(size);
|
||||
return getFromNullSpace(size, reason);
|
||||
}
|
||||
offset = quantizeOffset(space, offset);
|
||||
return getFromSpace(s, offset, size);
|
||||
return getFromSpace(s, offset, size, reason);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,7 +75,8 @@ public class AddressOfPcodeExecutorStatePiece
|
|||
}
|
||||
|
||||
@Override
|
||||
public Address getVar(AddressSpace space, byte[] offset, int size, boolean quantize) {
|
||||
public Address getVar(AddressSpace space, byte[] offset, int size, boolean quantize,
|
||||
Reason reason) {
|
||||
long lOffset = addressArithmetic.toLong(offset, Purpose.LOAD);
|
||||
if (!space.isUniqueSpace()) {
|
||||
return space.getAddress(lOffset);
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.stream.Stream;
|
|||
import org.apache.commons.lang3.reflect.TypeUtils;
|
||||
|
||||
import ghidra.pcode.emu.linux.EmuLinuxAmd64SyscallUseropLibrary;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
import utilities.util.AnnotationUtilities;
|
||||
|
||||
|
@ -352,7 +353,7 @@ public abstract class AnnotatedPcodeUseropLibrary<T> implements PcodeUseropLibra
|
|||
for (int i = 0; i < posIns.size(); i++) {
|
||||
int pos = posIns.get(i);
|
||||
if (posTs.contains(pos)) {
|
||||
args.set(pos, state.getVar(inVars.get(i)));
|
||||
args.set(pos, state.getVar(inVars.get(i), executor.getReason()));
|
||||
}
|
||||
else {
|
||||
args.set(pos, inVars.get(i));
|
||||
|
@ -424,10 +425,11 @@ public abstract class AnnotatedPcodeUseropLibrary<T> implements PcodeUseropLibra
|
|||
}
|
||||
}
|
||||
|
||||
protected Object[] readVars(PcodeExecutorState<T> state, List<Varnode> vars) {
|
||||
protected Object[] readVars(PcodeExecutorState<T> state, List<Varnode> vars,
|
||||
Reason reason) {
|
||||
Object[] vals = (Object[]) Array.newInstance(opRawType, vars.size());
|
||||
for (int i = 0; i < vals.length; i++) {
|
||||
vals[i] = state.getVar(vars.get(i));
|
||||
vals[i] = state.getVar(vars.get(i), reason);
|
||||
}
|
||||
return vals;
|
||||
}
|
||||
|
@ -436,7 +438,7 @@ public abstract class AnnotatedPcodeUseropLibrary<T> implements PcodeUseropLibra
|
|||
protected void placeInputs(PcodeExecutor<T> executor, List<Object> args,
|
||||
List<Varnode> inVars) {
|
||||
if (opRawType != null) {
|
||||
args.set(posIns, readVars(executor.getState(), inVars));
|
||||
args.set(posIns, readVars(executor.getState(), inVars, executor.getReason()));
|
||||
}
|
||||
else {
|
||||
args.set(posIns, inVars.toArray(Varnode[]::new));
|
||||
|
|
|
@ -21,6 +21,7 @@ import com.google.common.collect.*;
|
|||
import com.google.common.primitives.UnsignedLong;
|
||||
|
||||
import ghidra.generic.util.datastruct.SemisparseByteArray;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.lang.Register;
|
||||
|
@ -99,7 +100,7 @@ public class BytesPcodeExecutorStateSpace<B> {
|
|||
* @param size the number of bytes to read (the size of the value)
|
||||
* @return the bytes read
|
||||
*/
|
||||
protected byte[] readBytes(long offset, int size) {
|
||||
protected byte[] readBytes(long offset, int size, Reason reason) {
|
||||
byte[] data = new byte[size];
|
||||
bytes.getData(offset, data);
|
||||
return data;
|
||||
|
@ -158,16 +159,17 @@ public class BytesPcodeExecutorStateSpace<B> {
|
|||
*
|
||||
* @param offset the offset
|
||||
* @param size the number of bytes to read (the size of the value)
|
||||
* @param reason the reason for reading state
|
||||
* @return the bytes read
|
||||
*/
|
||||
public byte[] read(long offset, int size) {
|
||||
public byte[] read(long offset, int size, Reason reason) {
|
||||
if (backing != null) {
|
||||
readUninitializedFromBacking(bytes.getUninitialized(offset, offset + size - 1));
|
||||
}
|
||||
RangeSet<UnsignedLong> stillUninit = bytes.getUninitialized(offset, offset + size - 1);
|
||||
if (!stillUninit.isEmpty()) {
|
||||
if (!stillUninit.isEmpty() && reason == Reason.EXECUTE) {
|
||||
warnUninit(stillUninit);
|
||||
}
|
||||
return readBytes(offset, size);
|
||||
return readBytes(offset, size, reason);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,8 +52,8 @@ public class DefaultPcodeExecutorState<T> implements PcodeExecutorState<T> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public T getVar(AddressSpace space, T offset, int size, boolean quantize) {
|
||||
return piece.getVar(space, offset, size, quantize);
|
||||
public T getVar(AddressSpace space, T offset, int size, boolean quantize, Reason reason) {
|
||||
return piece.getVar(space, offset, size, quantize, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -112,7 +112,8 @@ public class PairedPcodeExecutorState<L, R> implements PcodeExecutorState<Pair<L
|
|||
}
|
||||
|
||||
@Override
|
||||
public Pair<L, R> getVar(AddressSpace space, Pair<L, R> offset, int size, boolean quantize) {
|
||||
return piece.getVar(space, offset.getLeft(), size, quantize);
|
||||
public Pair<L, R> getVar(AddressSpace space, Pair<L, R> offset, int size, boolean quantize,
|
||||
Reason reason) {
|
||||
return piece.getVar(space, offset.getLeft(), size, quantize, reason);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,10 +93,11 @@ public class PairedPcodeExecutorStatePiece<A, L, R>
|
|||
}
|
||||
|
||||
@Override
|
||||
public Pair<L, R> getVar(AddressSpace space, A offset, int size, boolean quantize) {
|
||||
public Pair<L, R> getVar(AddressSpace space, A offset, int size, boolean quantize,
|
||||
Reason reason) {
|
||||
return Pair.of(
|
||||
left.getVar(space, offset, size, quantize),
|
||||
right.getVar(space, offset, size, quantize));
|
||||
left.getVar(space, offset, size, quantize, reason),
|
||||
right.getVar(space, offset, size, quantize, reason));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -45,7 +45,7 @@ public interface PcodeArithmetic<T> {
|
|||
int SIZEOF_SIZEOF = 8;
|
||||
|
||||
/**
|
||||
* Various reasons the emulator may require a concrete value
|
||||
* Reasons for requiring a concrete value
|
||||
*/
|
||||
enum Purpose {
|
||||
/** The value is needed to parse an instruction */
|
||||
|
|
|
@ -22,6 +22,7 @@ import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
|||
import ghidra.pcode.emu.PcodeEmulator;
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.pcode.exec.PcodeUseropLibrary.PcodeUseropDefinition;
|
||||
import ghidra.pcode.opbehavior.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
@ -43,6 +44,7 @@ public class PcodeExecutor<T> {
|
|||
protected final SleighLanguage language;
|
||||
protected final PcodeArithmetic<T> arithmetic;
|
||||
protected final PcodeExecutorState<T> state;
|
||||
protected final Reason reason;
|
||||
protected final Register pc;
|
||||
protected final int pointerSize;
|
||||
|
||||
|
@ -52,12 +54,14 @@ public class PcodeExecutor<T> {
|
|||
* @param language the processor language
|
||||
* @param arithmetic an implementation of arithmetic p-code ops
|
||||
* @param state an implementation of load/store p-code ops
|
||||
* @param reason a reason for reading the state with this executor
|
||||
*/
|
||||
public PcodeExecutor(SleighLanguage language, PcodeArithmetic<T> arithmetic,
|
||||
PcodeExecutorState<T> state) {
|
||||
PcodeExecutorState<T> state, Reason reason) {
|
||||
this.language = language;
|
||||
this.arithmetic = arithmetic;
|
||||
this.state = state;
|
||||
this.reason = reason;
|
||||
|
||||
this.pc = language.getProgramCounter();
|
||||
this.pointerSize = language.getDefaultSpace().getPointerSize();
|
||||
|
@ -90,6 +94,15 @@ public class PcodeExecutor<T> {
|
|||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reason for reading state with this executor
|
||||
*
|
||||
* @return the reason
|
||||
*/
|
||||
public Reason getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile and execute a block of Sleigh
|
||||
*
|
||||
|
@ -295,7 +308,7 @@ public class PcodeExecutor<T> {
|
|||
public void executeUnaryOp(PcodeOp op, UnaryOpBehavior b) {
|
||||
Varnode in1Var = op.getInput(0);
|
||||
Varnode outVar = op.getOutput();
|
||||
T in1 = state.getVar(in1Var);
|
||||
T in1 = state.getVar(in1Var, reason);
|
||||
T out = arithmetic.unaryOp(op, in1);
|
||||
state.setVar(outVar, out);
|
||||
}
|
||||
|
@ -310,8 +323,8 @@ public class PcodeExecutor<T> {
|
|||
Varnode in1Var = op.getInput(0);
|
||||
Varnode in2Var = op.getInput(1);
|
||||
Varnode outVar = op.getOutput();
|
||||
T in1 = state.getVar(in1Var);
|
||||
T in2 = state.getVar(in2Var);
|
||||
T in1 = state.getVar(in1Var, reason);
|
||||
T in2 = state.getVar(in2Var, reason);
|
||||
T out = arithmetic.binaryOp(op, in1, in2);
|
||||
state.setVar(outVar, out);
|
||||
}
|
||||
|
@ -325,10 +338,10 @@ public class PcodeExecutor<T> {
|
|||
int spaceID = getIntConst(op.getInput(0));
|
||||
AddressSpace space = language.getAddressFactory().getAddressSpace(spaceID);
|
||||
Varnode inOffset = op.getInput(1);
|
||||
T offset = state.getVar(inOffset);
|
||||
T offset = state.getVar(inOffset, reason);
|
||||
Varnode outvar = op.getOutput();
|
||||
|
||||
T out = state.getVar(space, offset, outvar.getSize(), true);
|
||||
T out = state.getVar(space, offset, outvar.getSize(), true, reason);
|
||||
T mod = arithmetic.modAfterLoad(outvar.getSize(), inOffset.getSize(), offset,
|
||||
outvar.getSize(), out);
|
||||
state.setVar(outvar, mod);
|
||||
|
@ -343,10 +356,10 @@ public class PcodeExecutor<T> {
|
|||
int spaceID = getIntConst(op.getInput(0));
|
||||
AddressSpace space = language.getAddressFactory().getAddressSpace(spaceID);
|
||||
Varnode inOffset = op.getInput(1);
|
||||
T offset = state.getVar(inOffset);
|
||||
T offset = state.getVar(inOffset, reason);
|
||||
Varnode valVar = op.getInput(2);
|
||||
|
||||
T val = state.getVar(valVar);
|
||||
T val = state.getVar(valVar, reason);
|
||||
T mod = arithmetic.modBeforeStore(valVar.getSize(), inOffset.getSize(), offset,
|
||||
valVar.getSize(), val);
|
||||
state.setVar(space, offset, valVar.getSize(), true, mod);
|
||||
|
@ -425,7 +438,7 @@ public class PcodeExecutor<T> {
|
|||
*/
|
||||
public void executeConditionalBranch(PcodeOp op, PcodeFrame frame) {
|
||||
Varnode condVar = op.getInput(1);
|
||||
T cond = state.getVar(condVar);
|
||||
T cond = state.getVar(condVar, reason);
|
||||
if (arithmetic.isTrue(cond, Purpose.CONDITION)) {
|
||||
doExecuteBranch(op, frame);
|
||||
}
|
||||
|
@ -444,7 +457,7 @@ public class PcodeExecutor<T> {
|
|||
* @param frame the frame
|
||||
*/
|
||||
protected void doExecuteIndirectBranch(PcodeOp op, PcodeFrame frame) {
|
||||
T offset = state.getVar(op.getInput(0));
|
||||
T offset = state.getVar(op.getInput(0), reason);
|
||||
branchToOffset(offset, frame);
|
||||
|
||||
long concrete = arithmetic.toLong(offset, Purpose.BRANCH);
|
||||
|
|
|
@ -39,6 +39,16 @@ import ghidra.program.model.pcode.Varnode;
|
|||
*/
|
||||
public interface PcodeExecutorStatePiece<A, T> {
|
||||
|
||||
/**
|
||||
* Reasons for reading state
|
||||
*/
|
||||
enum Reason {
|
||||
/** The value is needed by the emulator in the course of execution */
|
||||
EXECUTE,
|
||||
/** The value is being inspected */
|
||||
INSPECT
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a range, if only to verify the range is valid
|
||||
*
|
||||
|
@ -141,23 +151,25 @@ public interface PcodeExecutorStatePiece<A, T> {
|
|||
* Get the value of a register variable
|
||||
*
|
||||
* @param reg the register
|
||||
* @param reason the reason for reading the register
|
||||
* @return the value
|
||||
*/
|
||||
default T getVar(Register reg) {
|
||||
default T getVar(Register reg, Reason reason) {
|
||||
Address address = reg.getAddress();
|
||||
return getVar(address.getAddressSpace(), address.getOffset(), reg.getMinimumByteSize(),
|
||||
true);
|
||||
true, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a variable
|
||||
*
|
||||
* @param var the variable
|
||||
* @param reason the reason for reading the variable
|
||||
* @return the value
|
||||
*/
|
||||
default T getVar(Varnode var) {
|
||||
default T getVar(Varnode var, Reason reason) {
|
||||
Address address = var.getAddress();
|
||||
return getVar(address.getAddressSpace(), address.getOffset(), var.getSize(), true);
|
||||
return getVar(address.getAddressSpace(), address.getOffset(), var.getSize(), true, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -167,9 +179,10 @@ public interface PcodeExecutorStatePiece<A, T> {
|
|||
* @param offset the offset within the space
|
||||
* @param size the size of the variable
|
||||
* @param quantize true to quantize to the language's "addressable unit"
|
||||
* @param reason the reason for reading the variable
|
||||
* @return the value
|
||||
*/
|
||||
T getVar(AddressSpace space, A offset, int size, boolean quantize);
|
||||
T getVar(AddressSpace space, A offset, int size, boolean quantize, Reason reason);
|
||||
|
||||
/**
|
||||
* Get the value of a variable
|
||||
|
@ -181,12 +194,13 @@ public interface PcodeExecutorStatePiece<A, T> {
|
|||
* @param offset the offset within the space
|
||||
* @param size the size of the variable
|
||||
* @param quantize true to quantize to the language's "addressable unit"
|
||||
* @param reason the reason for reading the variable
|
||||
* @return the value
|
||||
*/
|
||||
default T getVar(AddressSpace space, long offset, int size, boolean quantize) {
|
||||
default T getVar(AddressSpace space, long offset, int size, boolean quantize, Reason reason) {
|
||||
checkRange(space, offset, size);
|
||||
A aOffset = getAddressArithmetic().fromConst(offset, space.getPointerSize());
|
||||
return getVar(space, aOffset, size, quantize);
|
||||
return getVar(space, aOffset, size, quantize, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -198,10 +212,11 @@ public interface PcodeExecutorStatePiece<A, T> {
|
|||
* @param address the address of the variable
|
||||
* @param size the size of the variable
|
||||
* @param quantize true to quantize to the language's "addressable unit"
|
||||
* @param reason the reason for reading the variable
|
||||
* @return the value
|
||||
*/
|
||||
default T getVar(Address address, int size, boolean quantize) {
|
||||
return getVar(address.getAddressSpace(), address.getOffset(), size, quantize);
|
||||
default T getVar(Address address, int size, boolean quantize, Reason reason) {
|
||||
return getVar(address.getAddressSpace(), address.getOffset(), size, quantize, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -35,6 +35,7 @@ import ghidra.pcode.emu.sys.SyscallTestHelper.SyscallName;
|
|||
import ghidra.pcode.emu.unix.*;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.Language;
|
||||
|
@ -210,7 +211,7 @@ public class EmuLinuxAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadles
|
|||
// Step through write and verify return value and actual output effect
|
||||
thread.stepInstruction(5);
|
||||
assertArrayEquals(arithmetic.fromConst(BYTES_HW.length, regRAX.getNumBytes()),
|
||||
thread.getState().getVar(regRAX));
|
||||
thread.getState().getVar(regRAX, Reason.INSPECT));
|
||||
assertArrayEquals(BYTES_HW, stdout.toByteArray());
|
||||
|
||||
stepGroupExit(thread);
|
||||
|
@ -241,9 +242,9 @@ public class EmuLinuxAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadles
|
|||
// Step through write and verify return value and actual output effect
|
||||
thread.stepInstruction(5);
|
||||
assertArrayEquals(arithmetic.fromConst(BYTES_HW.length, regRAX.getNumBytes()),
|
||||
thread.getState().getVar(regRAX));
|
||||
thread.getState().getVar(regRAX, Reason.INSPECT));
|
||||
assertArrayEquals(BYTES_HW,
|
||||
emu.getSharedState().getVar(space, 0x00400800, BYTES_HW.length, true));
|
||||
emu.getSharedState().getVar(space, 0x00400800, BYTES_HW.length, true, Reason.INSPECT));
|
||||
|
||||
stepGroupExit(thread);
|
||||
}
|
||||
|
@ -295,7 +296,7 @@ public class EmuLinuxAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadles
|
|||
thread.stepInstruction(5);
|
||||
|
||||
assertEquals(BYTES_HW.length,
|
||||
arithmetic.toLong(thread.getState().getVar(regRAX), Purpose.OTHER));
|
||||
arithmetic.toLong(thread.getState().getVar(regRAX, Reason.INSPECT), Purpose.OTHER));
|
||||
assertArrayEquals(BYTES_HW, stdout.toByteArray());
|
||||
|
||||
stepGroupExit(thread);
|
||||
|
@ -350,11 +351,11 @@ public class EmuLinuxAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadles
|
|||
thread.stepInstruction(5);
|
||||
|
||||
assertEquals(BYTES_HW.length,
|
||||
arithmetic.toLong(thread.getState().getVar(regRAX), Purpose.OTHER));
|
||||
assertArrayEquals(BYTES_HELLO,
|
||||
emu.getSharedState().getVar(space, strHello.getOffset(), BYTES_HELLO.length, true));
|
||||
assertArrayEquals(BYTES_WORLD,
|
||||
emu.getSharedState().getVar(space, strWorld.getOffset(), BYTES_WORLD.length, true));
|
||||
arithmetic.toLong(thread.getState().getVar(regRAX, Reason.INSPECT), Purpose.OTHER));
|
||||
assertArrayEquals(BYTES_HELLO, emu.getSharedState()
|
||||
.getVar(space, strHello.getOffset(), BYTES_HELLO.length, true, Reason.INSPECT));
|
||||
assertArrayEquals(BYTES_WORLD, emu.getSharedState()
|
||||
.getVar(space, strWorld.getOffset(), BYTES_WORLD.length, true, Reason.INSPECT));
|
||||
|
||||
stepGroupExit(thread);
|
||||
}
|
||||
|
@ -431,6 +432,6 @@ public class EmuLinuxAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadles
|
|||
execute(thread);
|
||||
|
||||
assertArrayEquals(BYTES_HW,
|
||||
emu.getSharedState().getVar(space, 0x00400800, BYTES_HW.length, true));
|
||||
emu.getSharedState().getVar(space, 0x00400800, BYTES_HW.length, true, Reason.INSPECT));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import ghidra.pcode.emu.sys.SyscallTestHelper.SyscallName;
|
|||
import ghidra.pcode.emu.unix.*;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.Register;
|
||||
|
@ -210,7 +211,7 @@ public class EmuLinuxX86SyscallUseropLibraryTest extends AbstractGhidraHeadlessI
|
|||
// Step through write and verify return value and actual output effect
|
||||
thread.stepInstruction(5);
|
||||
assertArrayEquals(arithmetic.fromConst(BYTES_HW.length, regEAX.getNumBytes()),
|
||||
thread.getState().getVar(regEAX));
|
||||
thread.getState().getVar(regEAX, Reason.INSPECT));
|
||||
assertArrayEquals(BYTES_HW, stdout.toByteArray());
|
||||
|
||||
stepGroupExit(thread);
|
||||
|
@ -241,9 +242,9 @@ public class EmuLinuxX86SyscallUseropLibraryTest extends AbstractGhidraHeadlessI
|
|||
// Step through write and verify return value and actual output effect
|
||||
thread.stepInstruction(5);
|
||||
assertArrayEquals(arithmetic.fromConst(BYTES_HW.length, regEAX.getNumBytes()),
|
||||
thread.getState().getVar(regEAX));
|
||||
thread.getState().getVar(regEAX, Reason.INSPECT));
|
||||
assertArrayEquals(BYTES_HW,
|
||||
emu.getSharedState().getVar(space, 0x00400800, BYTES_HW.length, true));
|
||||
emu.getSharedState().getVar(space, 0x00400800, BYTES_HW.length, true, Reason.INSPECT));
|
||||
|
||||
stepGroupExit(thread);
|
||||
}
|
||||
|
@ -295,7 +296,7 @@ public class EmuLinuxX86SyscallUseropLibraryTest extends AbstractGhidraHeadlessI
|
|||
thread.stepInstruction(5);
|
||||
|
||||
assertEquals(BYTES_HW.length,
|
||||
arithmetic.toLong(thread.getState().getVar(regEAX), Purpose.OTHER));
|
||||
arithmetic.toLong(thread.getState().getVar(regEAX, Reason.INSPECT), Purpose.OTHER));
|
||||
assertArrayEquals(BYTES_HW, stdout.toByteArray());
|
||||
|
||||
stepGroupExit(thread);
|
||||
|
@ -350,11 +351,11 @@ public class EmuLinuxX86SyscallUseropLibraryTest extends AbstractGhidraHeadlessI
|
|||
thread.stepInstruction(5);
|
||||
|
||||
assertEquals(BYTES_HW.length,
|
||||
arithmetic.toLong(thread.getState().getVar(regEAX), Purpose.OTHER));
|
||||
assertArrayEquals(BYTES_HELLO,
|
||||
emu.getSharedState().getVar(space, strHello.getOffset(), BYTES_HELLO.length, true));
|
||||
assertArrayEquals(BYTES_WORLD,
|
||||
emu.getSharedState().getVar(space, strWorld.getOffset(), BYTES_WORLD.length, true));
|
||||
arithmetic.toLong(thread.getState().getVar(regEAX, Reason.INSPECT), Purpose.OTHER));
|
||||
assertArrayEquals(BYTES_HELLO, emu.getSharedState()
|
||||
.getVar(space, strHello.getOffset(), BYTES_HELLO.length, true, Reason.INSPECT));
|
||||
assertArrayEquals(BYTES_WORLD, emu.getSharedState()
|
||||
.getVar(space, strWorld.getOffset(), BYTES_WORLD.length, true, Reason.INSPECT));
|
||||
|
||||
stepGroupExit(thread);
|
||||
}
|
||||
|
@ -431,6 +432,6 @@ public class EmuLinuxX86SyscallUseropLibraryTest extends AbstractGhidraHeadlessI
|
|||
execute(thread);
|
||||
|
||||
assertArrayEquals(BYTES_HW,
|
||||
emu.getSharedState().getVar(space, 0x00400800, BYTES_HW.length, true));
|
||||
emu.getSharedState().getVar(space, 0x00400800, BYTES_HW.length, true, Reason.INSPECT));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
|||
import ghidra.pcode.emu.*;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataTypeConflictHandler;
|
||||
import ghidra.program.model.data.PointerDataType;
|
||||
|
@ -62,8 +63,8 @@ public class EmuAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadlessInte
|
|||
}
|
||||
|
||||
@Override
|
||||
public long readSyscallNumber(PcodeExecutorStatePiece<byte[], byte[]> state) {
|
||||
return machine.getArithmetic().toLong(state.getVar(regRAX), Purpose.OTHER);
|
||||
public long readSyscallNumber(PcodeExecutorState<byte[]> state, Reason reason) {
|
||||
return machine.getArithmetic().toLong(state.getVar(regRAX, reason), Purpose.OTHER);
|
||||
}
|
||||
|
||||
@PcodeUserop
|
||||
|
@ -192,7 +193,7 @@ public class EmuAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadlessInte
|
|||
thread.stepInstruction(4);
|
||||
|
||||
assertArrayEquals(arithmetic.fromConst(0xbeef, regRAX.getNumBytes()),
|
||||
thread.getState().getVar(regRAX));
|
||||
thread.getState().getVar(regRAX, Reason.INSPECT));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -211,6 +212,6 @@ public class EmuAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadlessInte
|
|||
thread.stepInstruction(4);
|
||||
|
||||
assertArrayEquals(arithmetic.fromConst(0xbeef, regRAX.getNumBytes()),
|
||||
thread.getState().getVar(regRAX));
|
||||
thread.getState().getVar(regRAX, Reason.INSPECT));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.junit.Test;
|
|||
|
||||
import ghidra.app.plugin.processors.sleigh.SleighException;
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.lang.LanguageID;
|
||||
import ghidra.program.model.lang.Register;
|
||||
|
@ -48,7 +49,7 @@ public class AnnotatedPcodeUseropLibraryTest extends AbstractGhidraHeadlessInteg
|
|||
(SleighLanguage) getLanguageService().getLanguage(new LanguageID(languageId));
|
||||
PcodeExecutorState<byte[]> state = new BytesPcodeExecutorState(language);
|
||||
PcodeArithmetic<byte[]> arithmetic = BytesPcodeArithmetic.forLanguage(language);
|
||||
return new PcodeExecutor<>(language, arithmetic, state);
|
||||
return new PcodeExecutor<>(language, arithmetic, state, Reason.EXECUTE);
|
||||
}
|
||||
|
||||
protected <T> void executeSleigh(PcodeExecutor<T> executor, PcodeUseropLibrary<T> library,
|
||||
|
@ -154,7 +155,7 @@ public class AnnotatedPcodeUseropLibraryTest extends AbstractGhidraHeadlessInteg
|
|||
Register r0 = executor.getLanguage().getRegister("r0");
|
||||
|
||||
executeSleigh(executor, library, "r0 = __testop();");
|
||||
assertBytes(1234, 8, executor.getState().getVar(r0));
|
||||
assertBytes(1234, 8, executor.getState().getVar(r0, Reason.INSPECT));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -174,7 +175,7 @@ public class AnnotatedPcodeUseropLibraryTest extends AbstractGhidraHeadlessInteg
|
|||
|
||||
executor.getState().setVar(r0, Utils.longToBytes(10, 8, true));
|
||||
executeSleigh(executor, library, "r1 = __testop(r0, 59:8);");
|
||||
assertBytes(159, 8, executor.getState().getVar(r1));
|
||||
assertBytes(159, 8, executor.getState().getVar(r1, Reason.INSPECT));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -281,7 +282,7 @@ public class AnnotatedPcodeUseropLibraryTest extends AbstractGhidraHeadlessInteg
|
|||
assertRegVarnode(r0, library.outVar);
|
||||
assertRegVarnode(r1, library.inVar0);
|
||||
assertBytes(1234, 8, library.inVal1);
|
||||
assertBytes(1234, 8, executor.getState().getVar(r0));
|
||||
assertBytes(1234, 8, executor.getState().getVar(r0, Reason.INSPECT));
|
||||
}
|
||||
|
||||
@Test(expected = SleighException.class)
|
||||
|
|
|
@ -68,7 +68,7 @@ public abstract class AbstractTaintPcodeExecutorStatePiece<S extends TaintSpace>
|
|||
* Extension point: Create the actual space map
|
||||
*
|
||||
* <p>
|
||||
* This will need to be implemented by each state piece, i.e., non-abstract derivating class.
|
||||
* This will need to be implemented by each state piece, i.e., non-abstract derivative class.
|
||||
* The space map will provide instances of {@code <S>}, which will provide the actual (extended)
|
||||
* storage logic.
|
||||
*
|
||||
|
@ -100,7 +100,7 @@ public abstract class AbstractTaintPcodeExecutorStatePiece<S extends TaintSpace>
|
|||
* the storage space.
|
||||
*/
|
||||
@Override
|
||||
protected void setInSpace(TaintSpace space, long offset, int size, TaintVec val) {
|
||||
protected void setInSpace(S space, long offset, int size, TaintVec val) {
|
||||
space.set(offset, val);
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,7 @@ public abstract class AbstractTaintPcodeExecutorStatePiece<S extends TaintSpace>
|
|||
* the storage space.
|
||||
*/
|
||||
@Override
|
||||
protected TaintVec getFromSpace(TaintSpace space, long offset, int size) {
|
||||
protected TaintVec getFromSpace(S space, long offset, int size, Reason reason) {
|
||||
return space.get(offset, size);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ public class TaintPcodeThreadExecutor extends PcodeThreadExecutor<Pair<byte[], T
|
|||
*/
|
||||
@Override
|
||||
public void executeConditionalBranch(PcodeOp op, PcodeFrame frame) {
|
||||
Pair<byte[], TaintVec> condition = state.getVar(op.getInput(1));
|
||||
Pair<byte[], TaintVec> condition = state.getVar(op.getInput(1), reason);
|
||||
TaintVec taint = condition.getRight();
|
||||
if (!taint.union().isEmpty()) {
|
||||
// getInstruction may return null if an inject executes a CBRANCH
|
||||
|
|
|
@ -31,6 +31,7 @@ import ghidra.pcode.emu.sys.EmuProcessExitedException;
|
|||
import ghidra.pcode.emu.taint.lib.TaintEmuUnixFileSystem;
|
||||
import ghidra.pcode.emu.taint.lib.TaintFileReadsLinuxAmd64SyscallLibrary;
|
||||
import ghidra.pcode.exec.PcodeUseropLibrary;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
@ -146,7 +147,7 @@ public class TaintPcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
|||
thread.overrideContextWithDefault();
|
||||
thread.stepInstruction();
|
||||
|
||||
Pair<byte[], TaintVec> endRAX = thread.getState().getVar(regRAX);
|
||||
Pair<byte[], TaintVec> endRAX = thread.getState().getVar(regRAX, Reason.INSPECT);
|
||||
assertEquals(0,
|
||||
Utils.bytesToLong(endRAX.getLeft(), regRAX.getNumBytes(), language.isBigEndian()));
|
||||
assertEquals(TaintVec.empties(regRAX.getNumBytes()), endRAX.getRight());
|
||||
|
@ -184,8 +185,8 @@ public class TaintPcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
|||
PcodeThread<?> thread = launchThread(start);
|
||||
execute(thread);
|
||||
|
||||
Pair<byte[], TaintVec> buf =
|
||||
emulator.getSharedState().getVar(space, 0x00400800, BYTES_HW.length, true);
|
||||
Pair<byte[], TaintVec> buf = emulator.getSharedState()
|
||||
.getVar(space, 0x00400800, BYTES_HW.length, true, Reason.INSPECT);
|
||||
assertArrayEquals(BYTES_HW, buf.getLeft());
|
||||
assertEquals(TaintVec.array("myfile", 0, BYTES_HW.length), buf.getRight());
|
||||
}
|
||||
|
@ -197,7 +198,7 @@ public class TaintPcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
|||
thread.getExecutor().executeSleigh("*:8 0x00400000:8 = taint_arr(*:8 0x004000000:8);");
|
||||
|
||||
Pair<byte[], TaintVec> taintVal =
|
||||
emulator.getSharedState().getVar(space, 0x00400000, 8, true);
|
||||
emulator.getSharedState().getVar(space, 0x00400000, 8, true, Reason.INSPECT);
|
||||
assertArrayEquals(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, taintVal.getLeft());
|
||||
assertEquals(TaintVec.array("arr_0", 0, 8), taintVal.getRight());
|
||||
}
|
||||
|
@ -227,7 +228,7 @@ public class TaintPcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
|||
thread.overrideContextWithDefault();
|
||||
thread.stepInstruction();
|
||||
|
||||
Pair<byte[], TaintVec> endRBX = thread.getState().getVar(regRBX);
|
||||
Pair<byte[], TaintVec> endRBX = thread.getState().getVar(regRBX, Reason.INSPECT);
|
||||
assertEquals(0x100f0e0d0c0b0a09L,
|
||||
Utils.bytesToLong(endRBX.getLeft(), regRBX.getNumBytes(), language.isBigEndian()));
|
||||
TaintSet fromIndirect = TaintVec.array("RAX", 0, 8).union().tagged("indR");
|
||||
|
@ -262,7 +263,7 @@ public class TaintPcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
|||
thread.stepInstruction();
|
||||
|
||||
Pair<byte[], TaintVec> endMem =
|
||||
emulator.getSharedState().getVar(dyn, 0x0807060504030201L, 8, true);
|
||||
emulator.getSharedState().getVar(dyn, 0x0807060504030201L, 8, true, Reason.INSPECT);
|
||||
assertEquals(0x100f0e0d0c0b0a09L,
|
||||
Utils.bytesToLong(endMem.getLeft(), regRBX.getNumBytes(), language.isBigEndian()));
|
||||
TaintSet fromIndirect = TaintVec.array("RAX", 0, 8).union().tagged("indW");
|
||||
|
@ -293,7 +294,7 @@ public class TaintPcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
|||
thread.overrideContextWithDefault();
|
||||
thread.stepInstruction();
|
||||
|
||||
Pair<byte[], TaintVec> endRAX = thread.getState().getVar(regRAX);
|
||||
Pair<byte[], TaintVec> endRAX = thread.getState().getVar(regRAX, Reason.INSPECT);
|
||||
assertEquals(0,
|
||||
Utils.bytesToLong(endRAX.getLeft(), regRAX.getNumBytes(), language.isBigEndian()));
|
||||
assertEquals(TaintVec.empties(regRAX.getNumBytes()), endRAX.getRight());
|
||||
|
|
|
@ -33,6 +33,7 @@ import ghidra.dbg.target.schema.SchemaContext;
|
|||
import ghidra.dbg.target.schema.XmlSchemaContext;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
|
||||
import ghidra.pcode.emu.PcodeThread;
|
||||
import ghidra.pcode.exec.PcodeExecutorStatePiece.Reason;
|
||||
import ghidra.pcode.exec.trace.AbstractTracePcodeEmulatorTest;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Register;
|
||||
|
@ -90,7 +91,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
emuThread.getExecutor().executeSleigh("RAX = *0x00400000:8;");
|
||||
|
||||
Pair<byte[], TaintVec> valRAX =
|
||||
emuThread.getState().getVar(tb.language.getRegister("RAX"));
|
||||
emuThread.getState().getVar(tb.language.getRegister("RAX"), Reason.INSPECT);
|
||||
TaintVec exp = TaintVec.empties(8);
|
||||
TaintSet testTaint = TaintSet.of(new TaintMark("test_0", Set.of()));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
@ -120,7 +121,7 @@ public class TaintTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
|||
emuThread.getExecutor().executeSleigh("RAX = RBX;");
|
||||
|
||||
Pair<byte[], TaintVec> valRAX =
|
||||
emuThread.getState().getVar(regRAX);
|
||||
emuThread.getState().getVar(regRAX, Reason.INSPECT);
|
||||
TaintVec exp = TaintVec.empties(8);
|
||||
TaintSet testTaint = TaintSet.of(new TaintMark("test_0", Set.of()));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
|
Loading…
Reference in a new issue