mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-1650: Introduce Reason for reading state. Fix spurrious uninit warnings.
This commit is contained in:
parent
45165ea167
commit
dcd54c6695
44 changed files with 224 additions and 151 deletions
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue