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

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