GP-1529: Interrupt emulator when decoding uninitialized memory

This commit is contained in:
Dan 2023-03-29 16:36:17 -04:00
parent 738e662e82
commit 4aa54dd1f9
25 changed files with 274 additions and 100 deletions

View file

@ -21,7 +21,8 @@ import java.util.Map;
import generic.ULongSpan;
import generic.ULongSpan.ULongSpanSet;
import ghidra.generic.util.datastruct.SemisparseByteArray;
import ghidra.pcode.exec.*;
import ghidra.pcode.exec.AbstractBytesPcodeExecutorStatePiece;
import ghidra.pcode.exec.BytesPcodeExecutorStateSpace;
import ghidra.pcode.exec.trace.BytesTracePcodeExecutorStatePiece.CachedSpace;
import ghidra.pcode.exec.trace.data.PcodeTraceDataAccess;
import ghidra.program.model.address.*;
@ -76,19 +77,29 @@ public class BytesTracePcodeExecutorStatePiece
}
@Override
protected void readUninitializedFromBacking(ULongSpanSet uninitialized) {
if (!uninitialized.isEmpty()) {
// TODO: Warn or bail when reading UNKNOWN bytes
// NOTE: Read without regard to gaps
// NOTE: Cannot write those gaps, though!!!
ULongSpan bound = uninitialized.bound();
ByteBuffer buf = ByteBuffer.allocate((int) bound.length());
backing.getBytes(space.getAddress(bound.min()), buf);
for (ULongSpan span : uninitialized.spans()) {
bytes.putData(span.min(), buf.array(), (int) (span.min() - bound.min()),
(int) span.length());
}
protected ULongSpanSet readUninitializedFromBacking(ULongSpanSet uninitialized) {
if (uninitialized.isEmpty()) {
return uninitialized;
}
// TODO: Warn or bail when reading UNKNOWN bytes
// NOTE: Read without regard to gaps
// NOTE: Cannot write those gaps, though!!!
AddressSetView knownButUninit = backing.intersectViewKnown(addrSet(uninitialized));
if (knownButUninit.isEmpty()) {
return uninitialized;
}
AddressRange knownBound = new AddressRangeImpl(
knownButUninit.getMinAddress(),
knownButUninit.getMaxAddress());
ByteBuffer buf = ByteBuffer.allocate((int) knownBound.getLength());
backing.getBytes(knownBound.getMinAddress(), buf);
for (AddressRange range : knownButUninit) {
bytes.putData(range.getMinAddress().getOffset(), buf.array(),
(int) (range.getMinAddress().subtract(knownBound.getMinAddress())),
(int) range.getLength());
}
ULongSpan uninitBound = uninitialized.bound();
return bytes.getUninitialized(uninitBound.min(), uninitBound.max());
}
protected void warnUnknown(AddressSetView unknown) {

View file

@ -30,6 +30,11 @@ import ghidra.trace.model.memory.TraceMemorySpace;
public class RequireIsKnownTraceCachedWriteBytesPcodeExecutorStatePiece
extends AbstractCheckedTraceCachedWriteBytesPcodeExecutorStatePiece {
/**
* Construct a piece
*
* @param data the trace-data access shim
*/
public RequireIsKnownTraceCachedWriteBytesPcodeExecutorStatePiece(PcodeTraceDataAccess data) {
super(data);
}
@ -45,11 +50,6 @@ public class RequireIsKnownTraceCachedWriteBytesPcodeExecutorStatePiece
spaceMap.fork());
}
/**
* Construct a piece
*
* @param data the trace-data access shim
*/
protected AddressSetView getKnown(PcodeTraceDataAccess backing) {
return backing.getKnownNow();
}

View file

@ -149,6 +149,23 @@ public abstract class AbstractPcodeTraceDataAccess implements InternalPcodeTrace
return doGetKnown(Lifespan.since(snap));
}
@Override
public AddressSetView intersectViewKnown(AddressSetView guestView) {
TraceMemoryOperations ops = getMemoryOps(false);
if (ops == null) {
return new AddressSet();
}
AddressSetView hostView = toOverlay(platform.mapGuestToHost(guestView));
AddressSet hostKnown = new AddressSet();
for (long sn : viewport.getOrderedSnaps()) {
hostKnown.add(ops.getAddressesWithState(sn, hostView,
st -> st != null && st != TraceMemoryState.UNKNOWN));
}
AddressSetView hostResult = hostView.intersect(hostKnown);
return platform.mapHostToGuest(hostResult);
}
@Override
public AddressSetView intersectUnknown(AddressSetView guestView) {
TraceMemoryOperations ops = getMemoryOps(false);

View file

@ -80,6 +80,11 @@ public class DefaultPcodeTraceThreadAccess
return memory.getKnownBefore().union(registers.getKnownBefore());
}
@Override
public AddressSetView intersectViewKnown(AddressSetView view) {
return memory.intersectViewKnown(view).union(registers.intersectViewKnown(view));
}
@Override
public AddressSetView intersectUnknown(AddressSetView view) {
return memory.intersectUnknown(view).union(registers.intersectUnknown(view));

View file

@ -92,6 +92,15 @@ public interface PcodeTraceDataAccess {
*/
AddressSetView getKnownBefore();
/**
* Compute the intersection of the given address set and the set of
* {@link TraceMemoryState#KNOWN} or (@link {@link TraceMemoryState#ERROR} memory
*
* @param view the address set
* @return the intersection
*/
AddressSetView intersectViewKnown(AddressSetView view);
/**
* Compute the intersection of the given address set and the set of
* {@link TraceMemoryState#UNKNOWN} memory

View file

@ -221,7 +221,7 @@ public class TraceSleighUtilsTest extends AbstractGhidraHeadlessIntegrationTest
new PcodeExecutor<>(sp.getLanguage(),
BytesPcodeArithmetic.forLanguage(b.language),
new DirectBytesTracePcodeExecutorState(b.host, 0, thread, 0),
Reason.EXECUTE);
Reason.EXECUTE_READ);
sp.execute(executor, PcodeUseropLibrary.nil());
}

View file

@ -62,7 +62,7 @@ class TestThread implements PcodeThread<Void> {
@Override
public PcodeExecutor<Void> getExecutor() {
return new PcodeExecutor<>(TraceScheduleTest.TOY_BE_64_LANG, machine.getArithmetic(),
getState(), Reason.EXECUTE) {
getState(), Reason.EXECUTE_READ) {
public PcodeFrame execute(PcodeProgram program, PcodeUseropLibrary<Void> library) {
machine.record.add("x:" + name);
// TODO: Verify the actual effect