mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-0: Fixes post GP-1529
This commit is contained in:
parent
3bbcc56886
commit
2fb2902721
14 changed files with 129 additions and 93 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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")) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue