GP-0: Fixes post GP-1529

This commit is contained in:
Dan 2023-03-31 10:10:00 -04:00
parent 3bbcc56886
commit 2fb2902721
14 changed files with 129 additions and 93 deletions

View file

@ -76,6 +76,10 @@ public class BytesTracePcodeExecutorStatePiece
}
}
protected AddressSetView intersectViewKnown(AddressSetView set) {
return backing.intersectViewKnown(set, true);
}
@Override
protected ULongSpanSet readUninitializedFromBacking(ULongSpanSet uninitialized) {
if (uninitialized.isEmpty()) {
@ -84,7 +88,7 @@ public class BytesTracePcodeExecutorStatePiece
// 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));
AddressSetView knownButUninit = intersectViewKnown(addrSet(uninitialized));
if (knownButUninit.isEmpty()) {
return uninitialized;
}

View file

@ -52,8 +52,8 @@ public class RequireHasKnownTraceCachedWriteBytesPcodeExecutorStatePiece
}
@Override
protected AddressSetView getKnown(PcodeTraceDataAccess backing) {
return backing.getKnownBefore();
protected AddressSetView getKnown(PcodeTraceDataAccess backing, AddressSetView set) {
return backing.intersectViewKnown(set, true);
}
@Override

View file

@ -50,8 +50,8 @@ public class RequireIsKnownTraceCachedWriteBytesPcodeExecutorStatePiece
spaceMap.fork());
}
protected AddressSetView getKnown(PcodeTraceDataAccess backing) {
return backing.getKnownNow();
protected AddressSetView getKnown(PcodeTraceDataAccess backing, AddressSetView set) {
return backing.intersectViewKnown(set, false);
}
protected AccessPcodeExecutionException excFor(AddressSetView unknown) {
@ -68,7 +68,7 @@ public class RequireIsKnownTraceCachedWriteBytesPcodeExecutorStatePiece
throw excFor(uninitialized);
}
// TODO: Could find first instead?
AddressSetView unknown = uninitialized.subtract(getKnown(backing));
AddressSetView unknown = uninitialized.subtract(getKnown(backing, uninitialized));
if (unknown.isEmpty()) {
return size;
}

View file

@ -23,6 +23,7 @@ import ghidra.trace.model.Lifespan;
import ghidra.trace.model.TraceTimeViewport;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.memory.*;
import ghidra.trace.util.TraceRegisterUtils;
/**
* An abstract data-access shim, for either memory or registers
@ -130,27 +131,8 @@ public abstract class AbstractPcodeTraceDataAccess implements InternalPcodeTrace
return hostSet.isEmpty() ? TraceMemoryState.KNOWN : TraceMemoryState.UNKNOWN;
}
protected AddressSetView doGetKnown(Lifespan span) {
TraceMemoryOperations ops = getMemoryOps(false);
if (ops == null) {
return new AddressSet();
}
return platform.mapHostToGuest(ops.getAddressesWithState(span,
s -> s == TraceMemoryState.KNOWN));
}
@Override
public AddressSetView getKnownNow() {
return doGetKnown(Lifespan.at(snap));
}
@Override
public AddressSetView getKnownBefore() {
return doGetKnown(Lifespan.since(snap));
}
@Override
public AddressSetView intersectViewKnown(AddressSetView guestView) {
public AddressSetView intersectViewKnown(AddressSetView guestView, boolean useFullSpans) {
TraceMemoryOperations ops = getMemoryOps(false);
if (ops == null) {
return new AddressSet();
@ -158,11 +140,20 @@ public abstract class AbstractPcodeTraceDataAccess implements InternalPcodeTrace
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));
if (useFullSpans) {
for (Lifespan span : viewport.getOrderedSpans()) {
hostKnown.add(ops.getAddressesWithState(span, hostView,
st -> st != null && st != TraceMemoryState.UNKNOWN));
}
}
AddressSetView hostResult = hostView.intersect(hostKnown);
else {
for (long snap : viewport.getOrderedSnaps()) {
hostKnown.add(ops.getAddressesWithState(snap, hostView,
st -> st != null && st != TraceMemoryState.UNKNOWN));
}
}
AddressSetView hostResult =
TraceRegisterUtils.getPhysicalSet(hostView.intersect(hostKnown));
return platform.mapHostToGuest(hostResult);
}
@ -176,7 +167,7 @@ public abstract class AbstractPcodeTraceDataAccess implements InternalPcodeTrace
AddressSetView hostView = toOverlay(platform.mapGuestToHost(guestView));
AddressSetView hostKnown = ops.getAddressesWithState(snap, hostView,
s -> s != null && s != TraceMemoryState.UNKNOWN);
AddressSetView hostResult = hostView.subtract(hostKnown);
AddressSetView hostResult = TraceRegisterUtils.getPhysicalSet(hostView.subtract(hostKnown));
return platform.mapHostToGuest(hostResult);
}

View file

@ -71,18 +71,9 @@ public class DefaultPcodeTraceThreadAccess
}
@Override
public AddressSetView getKnownNow() {
return memory.getKnownNow().union(registers.getKnownNow());
}
@Override
public AddressSetView getKnownBefore() {
return memory.getKnownBefore().union(registers.getKnownBefore());
}
@Override
public AddressSetView intersectViewKnown(AddressSetView view) {
return memory.intersectViewKnown(view).union(registers.intersectViewKnown(view));
public AddressSetView intersectViewKnown(AddressSetView view, boolean useFullSpans) {
return memory.intersectViewKnown(view, useFullSpans)
.union(registers.intersectViewKnown(view, useFullSpans));
}
@Override

View file

@ -63,43 +63,15 @@ public interface PcodeTraceDataAccess {
*/
TraceMemoryState getViewportState(AddressRange range);
/**
* Get the address set of {@link TraceMemoryState#KNOWN} memory in the source snapshot
*
* <p>
* Note, this does not consider the snapshot's viewport.
*
* @implNote This can be an expensive operation when the platform is a guest, since what would
* ordinarily be a lazy address set must be computed and translated to the guest
* address spaces.
*
* @return the address set
*/
AddressSetView getKnownNow();
/**
* Get the address set of {@link TraceMemoryState#KNOWN} memory among all snapshots from 0 to
* the source snapshot
*
* <p>
* Note, this does not consider the snapshot's viewport.
*
* @implNote This can be an expensive operation when the platform is a guest, since what would
* ordinarily be a lazy address set must be computed and translated to the guest
* address spaces.
*
* @return the address set
*/
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
* @param useFullSpans how to treat the viewport; true for ever known, false for known now.
* @return the intersection
*/
AddressSetView intersectViewKnown(AddressSetView view);
AddressSetView intersectViewKnown(AddressSetView view, boolean useFullSpans);
/**
* Compute the intersection of the given address set and the set of

View file

@ -290,7 +290,7 @@ public class DBTraceMemoryManager extends AbstractDBTraceSpaceBasedManager<DBTra
}
@Override
public AddressSetView getAddressesWithState(long snap, AddressSetView set,
public AddressSetView getAddressesWithState(Lifespan snap, AddressSetView set,
Predicate<TraceMemoryState> predicate) {
return delegateAddressSet(getActiveMemorySpaces(),
m -> m.getAddressesWithState(snap, set, predicate));
@ -311,6 +311,11 @@ public class DBTraceMemoryManager extends AbstractDBTraceSpaceBasedManager<DBTra
.toList());
}
protected Collection<Entry<TraceAddressSnapRange, TraceMemoryState>> doGetStates(Lifespan span,
AddressRange range) {
return delegateRead(range.getAddressSpace(), m -> m.doGetStates(span, range));
}
@Override
public Collection<Entry<TraceAddressSnapRange, TraceMemoryState>> getStates(long snap,
AddressRange range) {

View file

@ -434,7 +434,7 @@ public class DBTraceMemorySpace
}
@Override
public AddressSetView getAddressesWithState(long snap, AddressSetView set,
public AddressSetView getAddressesWithState(Lifespan span, AddressSetView set,
Predicate<TraceMemoryState> predicate) {
try (LockHold hold = LockHold.lock(lock.readLock())) {
AddressSet remains = new AddressSet(set);
@ -442,7 +442,7 @@ public class DBTraceMemorySpace
while (!remains.isEmpty()) {
AddressRange range = remains.getFirstRange();
remains.delete(range);
for (Entry<TraceAddressSnapRange, TraceMemoryState> entry : doGetStates(snap,
for (Entry<TraceAddressSnapRange, TraceMemoryState> entry : doGetStates(span,
range)) {
AddressRange foundRange = entry.getKey().getRange();
remains.delete(foundRange);
@ -455,21 +455,20 @@ public class DBTraceMemorySpace
}
}
protected Collection<Entry<TraceAddressSnapRange, TraceMemoryState>> doGetStates(long snap,
protected Collection<Entry<TraceAddressSnapRange, TraceMemoryState>> doGetStates(Lifespan span,
AddressRange range) {
// TODO: A better way to handle memory-mapped registers?
if (getAddressSpace().isRegisterSpace() && !range.getAddressSpace().isRegisterSpace()) {
return trace.getMemoryManager().getStates(snap, range);
return trace.getMemoryManager().doGetStates(span, range);
}
return stateMapSpace.reduce(TraceAddressSnapRangeQuery.intersecting(range.getMinAddress(),
range.getMaxAddress(), snap, snap)).entries();
return stateMapSpace.reduce(TraceAddressSnapRangeQuery.intersecting(range, span)).entries();
}
@Override
public Collection<Entry<TraceAddressSnapRange, TraceMemoryState>> getStates(long snap,
AddressRange range) {
assertInSpace(range);
return doGetStates(snap, range);
return doGetStates(Lifespan.at(snap), range);
}
@Override

View file

@ -268,6 +268,20 @@ public interface TraceMemoryOperations {
Entry<TraceAddressSnapRange, TraceMemoryState> getViewMostRecentStateEntry(long snap,
Address address);
/**
* Get at least the subset of addresses having state satisfying the given predicate
*
* @param snap the time
* @param set the set to examine
* @param predicate a predicate on state to search for
* @return the address set
* @see #getAddressesWithState(Lifespan, AddressSetView, Predicate)
*/
default AddressSetView getAddressesWithState(long snap, AddressSetView set,
Predicate<TraceMemoryState> predicate) {
return getAddressesWithState(Lifespan.at(snap), set, predicate);
}
/**
* Get at least the subset of addresses having state satisfying the given predicate
*
@ -288,7 +302,7 @@ public interface TraceMemoryOperations {
* @param predicate a predicate on state to search for
* @return the address set
*/
AddressSetView getAddressesWithState(long snap, AddressSetView set,
AddressSetView getAddressesWithState(Lifespan span, AddressSetView set,
Predicate<TraceMemoryState> predicate);
/**

View file

@ -60,6 +60,34 @@ public enum TraceRegisterUtils {
return result;
}
public static AddressRange getPhysicalRange(AddressRange range) {
AddressSpace space = range.getAddressSpace();
AddressSpace physical = space.getPhysicalSpace();
if (space == physical) {
return range;
}
return new AddressRangeImpl(
physical.getAddress(range.getMinAddress().getOffset()),
physical.getAddress(range.getMaxAddress().getOffset()));
}
/**
* Convert a set in an overlay space to the corresponding set in its physical space
*
* @param set a set contained entirely in one space
* @return the physical set
*/
public static AddressSetView getPhysicalSet(AddressSetView set) {
if (set.isEmpty() || !set.getMinAddress().getAddressSpace().isOverlaySpace()) {
return set;
}
AddressSet result = new AddressSet();
for (AddressRange rng : set) {
result.add(getPhysicalRange(rng));
}
return result;
}
public static byte[] padOrTruncate(byte[] arr, int length) {
if (arr.length == length) {
return arr;

View file

@ -942,6 +942,23 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
}
}
@Test(expected = DecodePcodeExecutionException.class)
public void testUninitialized() throws Throwable {
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "Toy:BE:64:default")) {
assertEquals(Register.NO_CONTEXT, tb.language.getContextBaseRegister());
TraceThread thread = initTrace(tb, """
pc = 0x00400000;
sp = 0x00110000;
""",
List.of()); // An empty, uninitialized program
BytesTracePcodeEmulator emu = new BytesTracePcodeEmulator(tb.host, 0);
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
emuThread.stepInstruction();
}
}
@Test
public void testMov_w_mW1_W0() throws Throwable {
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "dsPIC33F:LE:24:default")) {