GP-1650: Introduce Reason for reading state. Fix spurrious uninit warnings.

This commit is contained in:
Dan 2022-09-22 14:47:08 -04:00
parent 45165ea167
commit dcd54c6695
44 changed files with 224 additions and 151 deletions

View file

@ -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()),

View file

@ -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());

View file

@ -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);
}

View file

@ -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()),

View file

@ -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(

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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) {

View file

@ -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);
}
}

View file

@ -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();

View file

@ -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")));
}

View file

@ -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);
}
}

View file

@ -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) {

View file

@ -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;
}

View file

@ -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);
}
/**

View file

@ -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);

View file

@ -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());
}

View file

@ -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

View file

@ -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) {

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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();

View file

@ -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);

View file

@ -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);
}

View file

@ -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));
}
}

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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));

View file

@ -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);
}
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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

View file

@ -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 */

View file

@ -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);

View file

@ -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);
}
/**

View file

@ -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));
}
}

View file

@ -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));
}
}

View file

@ -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));
}
}

View file

@ -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)

View file

@ -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);
}
}

View file

@ -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

View file

@ -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());

View file

@ -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++) {