mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GP-1529: Interrupt emulator when decoding uninitialized memory
This commit is contained in:
parent
738e662e82
commit
4aa54dd1f9
25 changed files with 274 additions and 100 deletions
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue