mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +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
|
@Override
|
||||||
protected ULongSpanSet readUninitializedFromBacking(ULongSpanSet uninitialized) {
|
protected ULongSpanSet readUninitializedFromBacking(ULongSpanSet uninitialized) {
|
||||||
if (uninitialized.isEmpty()) {
|
if (uninitialized.isEmpty()) {
|
||||||
|
@ -84,7 +88,7 @@ public class BytesTracePcodeExecutorStatePiece
|
||||||
// TODO: Warn or bail when reading UNKNOWN bytes
|
// TODO: Warn or bail when reading UNKNOWN bytes
|
||||||
// NOTE: Read without regard to gaps
|
// NOTE: Read without regard to gaps
|
||||||
// NOTE: Cannot write those gaps, though!!!
|
// NOTE: Cannot write those gaps, though!!!
|
||||||
AddressSetView knownButUninit = backing.intersectViewKnown(addrSet(uninitialized));
|
AddressSetView knownButUninit = intersectViewKnown(addrSet(uninitialized));
|
||||||
if (knownButUninit.isEmpty()) {
|
if (knownButUninit.isEmpty()) {
|
||||||
return uninitialized;
|
return uninitialized;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,8 +52,8 @@ public class RequireHasKnownTraceCachedWriteBytesPcodeExecutorStatePiece
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AddressSetView getKnown(PcodeTraceDataAccess backing) {
|
protected AddressSetView getKnown(PcodeTraceDataAccess backing, AddressSetView set) {
|
||||||
return backing.getKnownBefore();
|
return backing.intersectViewKnown(set, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -50,8 +50,8 @@ public class RequireIsKnownTraceCachedWriteBytesPcodeExecutorStatePiece
|
||||||
spaceMap.fork());
|
spaceMap.fork());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AddressSetView getKnown(PcodeTraceDataAccess backing) {
|
protected AddressSetView getKnown(PcodeTraceDataAccess backing, AddressSetView set) {
|
||||||
return backing.getKnownNow();
|
return backing.intersectViewKnown(set, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AccessPcodeExecutionException excFor(AddressSetView unknown) {
|
protected AccessPcodeExecutionException excFor(AddressSetView unknown) {
|
||||||
|
@ -68,7 +68,7 @@ public class RequireIsKnownTraceCachedWriteBytesPcodeExecutorStatePiece
|
||||||
throw excFor(uninitialized);
|
throw excFor(uninitialized);
|
||||||
}
|
}
|
||||||
// TODO: Could find first instead?
|
// TODO: Could find first instead?
|
||||||
AddressSetView unknown = uninitialized.subtract(getKnown(backing));
|
AddressSetView unknown = uninitialized.subtract(getKnown(backing, uninitialized));
|
||||||
if (unknown.isEmpty()) {
|
if (unknown.isEmpty()) {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import ghidra.trace.model.Lifespan;
|
||||||
import ghidra.trace.model.TraceTimeViewport;
|
import ghidra.trace.model.TraceTimeViewport;
|
||||||
import ghidra.trace.model.guest.TracePlatform;
|
import ghidra.trace.model.guest.TracePlatform;
|
||||||
import ghidra.trace.model.memory.*;
|
import ghidra.trace.model.memory.*;
|
||||||
|
import ghidra.trace.util.TraceRegisterUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract data-access shim, for either memory or registers
|
* 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;
|
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
|
@Override
|
||||||
public AddressSetView getKnownNow() {
|
public AddressSetView intersectViewKnown(AddressSetView guestView, boolean useFullSpans) {
|
||||||
return doGetKnown(Lifespan.at(snap));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AddressSetView getKnownBefore() {
|
|
||||||
return doGetKnown(Lifespan.since(snap));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AddressSetView intersectViewKnown(AddressSetView guestView) {
|
|
||||||
TraceMemoryOperations ops = getMemoryOps(false);
|
TraceMemoryOperations ops = getMemoryOps(false);
|
||||||
if (ops == null) {
|
if (ops == null) {
|
||||||
return new AddressSet();
|
return new AddressSet();
|
||||||
|
@ -158,11 +140,20 @@ public abstract class AbstractPcodeTraceDataAccess implements InternalPcodeTrace
|
||||||
|
|
||||||
AddressSetView hostView = toOverlay(platform.mapGuestToHost(guestView));
|
AddressSetView hostView = toOverlay(platform.mapGuestToHost(guestView));
|
||||||
AddressSet hostKnown = new AddressSet();
|
AddressSet hostKnown = new AddressSet();
|
||||||
for (long sn : viewport.getOrderedSnaps()) {
|
if (useFullSpans) {
|
||||||
hostKnown.add(ops.getAddressesWithState(sn, hostView,
|
for (Lifespan span : viewport.getOrderedSpans()) {
|
||||||
st -> st != null && st != TraceMemoryState.UNKNOWN));
|
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);
|
return platform.mapHostToGuest(hostResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +167,7 @@ public abstract class AbstractPcodeTraceDataAccess implements InternalPcodeTrace
|
||||||
AddressSetView hostView = toOverlay(platform.mapGuestToHost(guestView));
|
AddressSetView hostView = toOverlay(platform.mapGuestToHost(guestView));
|
||||||
AddressSetView hostKnown = ops.getAddressesWithState(snap, hostView,
|
AddressSetView hostKnown = ops.getAddressesWithState(snap, hostView,
|
||||||
s -> s != null && s != TraceMemoryState.UNKNOWN);
|
s -> s != null && s != TraceMemoryState.UNKNOWN);
|
||||||
AddressSetView hostResult = hostView.subtract(hostKnown);
|
AddressSetView hostResult = TraceRegisterUtils.getPhysicalSet(hostView.subtract(hostKnown));
|
||||||
return platform.mapHostToGuest(hostResult);
|
return platform.mapHostToGuest(hostResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,18 +71,9 @@ public class DefaultPcodeTraceThreadAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressSetView getKnownNow() {
|
public AddressSetView intersectViewKnown(AddressSetView view, boolean useFullSpans) {
|
||||||
return memory.getKnownNow().union(registers.getKnownNow());
|
return memory.intersectViewKnown(view, useFullSpans)
|
||||||
}
|
.union(registers.intersectViewKnown(view, useFullSpans));
|
||||||
|
|
||||||
@Override
|
|
||||||
public AddressSetView getKnownBefore() {
|
|
||||||
return memory.getKnownBefore().union(registers.getKnownBefore());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AddressSetView intersectViewKnown(AddressSetView view) {
|
|
||||||
return memory.intersectViewKnown(view).union(registers.intersectViewKnown(view));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -63,43 +63,15 @@ public interface PcodeTraceDataAccess {
|
||||||
*/
|
*/
|
||||||
TraceMemoryState getViewportState(AddressRange range);
|
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
|
* Compute the intersection of the given address set and the set of
|
||||||
* {@link TraceMemoryState#KNOWN} or (@link {@link TraceMemoryState#ERROR} memory
|
* {@link TraceMemoryState#KNOWN} or (@link {@link TraceMemoryState#ERROR} memory
|
||||||
*
|
*
|
||||||
* @param view the address set
|
* @param view the address set
|
||||||
|
* @param useFullSpans how to treat the viewport; true for ever known, false for known now.
|
||||||
* @return the intersection
|
* @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
|
* Compute the intersection of the given address set and the set of
|
||||||
|
|
|
@ -290,7 +290,7 @@ public class DBTraceMemoryManager extends AbstractDBTraceSpaceBasedManager<DBTra
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressSetView getAddressesWithState(long snap, AddressSetView set,
|
public AddressSetView getAddressesWithState(Lifespan snap, AddressSetView set,
|
||||||
Predicate<TraceMemoryState> predicate) {
|
Predicate<TraceMemoryState> predicate) {
|
||||||
return delegateAddressSet(getActiveMemorySpaces(),
|
return delegateAddressSet(getActiveMemorySpaces(),
|
||||||
m -> m.getAddressesWithState(snap, set, predicate));
|
m -> m.getAddressesWithState(snap, set, predicate));
|
||||||
|
@ -311,6 +311,11 @@ public class DBTraceMemoryManager extends AbstractDBTraceSpaceBasedManager<DBTra
|
||||||
.toList());
|
.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Collection<Entry<TraceAddressSnapRange, TraceMemoryState>> doGetStates(Lifespan span,
|
||||||
|
AddressRange range) {
|
||||||
|
return delegateRead(range.getAddressSpace(), m -> m.doGetStates(span, range));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Entry<TraceAddressSnapRange, TraceMemoryState>> getStates(long snap,
|
public Collection<Entry<TraceAddressSnapRange, TraceMemoryState>> getStates(long snap,
|
||||||
AddressRange range) {
|
AddressRange range) {
|
||||||
|
|
|
@ -434,7 +434,7 @@ public class DBTraceMemorySpace
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressSetView getAddressesWithState(long snap, AddressSetView set,
|
public AddressSetView getAddressesWithState(Lifespan span, AddressSetView set,
|
||||||
Predicate<TraceMemoryState> predicate) {
|
Predicate<TraceMemoryState> predicate) {
|
||||||
try (LockHold hold = LockHold.lock(lock.readLock())) {
|
try (LockHold hold = LockHold.lock(lock.readLock())) {
|
||||||
AddressSet remains = new AddressSet(set);
|
AddressSet remains = new AddressSet(set);
|
||||||
|
@ -442,7 +442,7 @@ public class DBTraceMemorySpace
|
||||||
while (!remains.isEmpty()) {
|
while (!remains.isEmpty()) {
|
||||||
AddressRange range = remains.getFirstRange();
|
AddressRange range = remains.getFirstRange();
|
||||||
remains.delete(range);
|
remains.delete(range);
|
||||||
for (Entry<TraceAddressSnapRange, TraceMemoryState> entry : doGetStates(snap,
|
for (Entry<TraceAddressSnapRange, TraceMemoryState> entry : doGetStates(span,
|
||||||
range)) {
|
range)) {
|
||||||
AddressRange foundRange = entry.getKey().getRange();
|
AddressRange foundRange = entry.getKey().getRange();
|
||||||
remains.delete(foundRange);
|
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) {
|
AddressRange range) {
|
||||||
// TODO: A better way to handle memory-mapped registers?
|
// TODO: A better way to handle memory-mapped registers?
|
||||||
if (getAddressSpace().isRegisterSpace() && !range.getAddressSpace().isRegisterSpace()) {
|
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(),
|
return stateMapSpace.reduce(TraceAddressSnapRangeQuery.intersecting(range, span)).entries();
|
||||||
range.getMaxAddress(), snap, snap)).entries();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Entry<TraceAddressSnapRange, TraceMemoryState>> getStates(long snap,
|
public Collection<Entry<TraceAddressSnapRange, TraceMemoryState>> getStates(long snap,
|
||||||
AddressRange range) {
|
AddressRange range) {
|
||||||
assertInSpace(range);
|
assertInSpace(range);
|
||||||
return doGetStates(snap, range);
|
return doGetStates(Lifespan.at(snap), range);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -268,6 +268,20 @@ public interface TraceMemoryOperations {
|
||||||
Entry<TraceAddressSnapRange, TraceMemoryState> getViewMostRecentStateEntry(long snap,
|
Entry<TraceAddressSnapRange, TraceMemoryState> getViewMostRecentStateEntry(long snap,
|
||||||
Address address);
|
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
|
* 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
|
* @param predicate a predicate on state to search for
|
||||||
* @return the address set
|
* @return the address set
|
||||||
*/
|
*/
|
||||||
AddressSetView getAddressesWithState(long snap, AddressSetView set,
|
AddressSetView getAddressesWithState(Lifespan span, AddressSetView set,
|
||||||
Predicate<TraceMemoryState> predicate);
|
Predicate<TraceMemoryState> predicate);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -60,6 +60,34 @@ public enum TraceRegisterUtils {
|
||||||
return result;
|
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) {
|
public static byte[] padOrTruncate(byte[] arr, int length) {
|
||||||
if (arr.length == length) {
|
if (arr.length == length) {
|
||||||
return arr;
|
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
|
@Test
|
||||||
public void testMov_w_mW1_W0() throws Throwable {
|
public void testMov_w_mW1_W0() throws Throwable {
|
||||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "dsPIC33F:LE:24:default")) {
|
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "dsPIC33F:LE:24:default")) {
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.pcode.emu.taint.full;
|
package ghidra.pcode.emu.taint.full;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -30,18 +31,18 @@ import ghidra.app.plugin.core.debug.service.emulation.DebuggerEmulationServicePl
|
||||||
import ghidra.app.plugin.core.debug.service.emulation.DebuggerPcodeMachine;
|
import ghidra.app.plugin.core.debug.service.emulation.DebuggerPcodeMachine;
|
||||||
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin;
|
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin;
|
||||||
import ghidra.app.services.DebuggerEmulationService;
|
import ghidra.app.services.DebuggerEmulationService;
|
||||||
|
import ghidra.app.services.DebuggerEmulationService.EmulationResult;
|
||||||
import ghidra.app.services.DebuggerStaticMappingService;
|
import ghidra.app.services.DebuggerStaticMappingService;
|
||||||
import ghidra.pcode.emu.taint.trace.TaintTracePcodeEmulatorTest;
|
import ghidra.pcode.emu.taint.trace.TaintTracePcodeEmulatorTest;
|
||||||
import ghidra.pcode.emu.taint.trace.TaintTracePcodeExecutorStatePiece;
|
import ghidra.pcode.emu.taint.trace.TaintTracePcodeExecutorStatePiece;
|
||||||
import ghidra.program.model.address.AddressSpace;
|
import ghidra.program.model.address.AddressSpace;
|
||||||
import ghidra.program.model.util.StringPropertyMap;
|
import ghidra.program.model.util.StringPropertyMap;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.trace.model.DefaultTraceLocation;
|
import ghidra.trace.model.*;
|
||||||
import ghidra.trace.model.Lifespan;
|
|
||||||
import ghidra.trace.model.property.TracePropertyMap;
|
import ghidra.trace.model.property.TracePropertyMap;
|
||||||
import ghidra.trace.model.property.TracePropertyMapSpace;
|
import ghidra.trace.model.property.TracePropertyMapSpace;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
import ghidra.trace.model.time.schedule.TraceSchedule;
|
import ghidra.trace.model.time.schedule.*;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class TaintDebuggerPcodeEmulatorTest extends AbstractGhidraHeadedDebuggerGUITest {
|
public class TaintDebuggerPcodeEmulatorTest extends AbstractGhidraHeadedDebuggerGUITest {
|
||||||
|
@ -75,11 +76,19 @@ public class TaintDebuggerPcodeEmulatorTest extends AbstractGhidraHeadedDebugger
|
||||||
|
|
||||||
traceManager.activateTrace(tb.trace);
|
traceManager.activateTrace(tb.trace);
|
||||||
|
|
||||||
TraceSchedule time = TraceSchedule.parse("0:t0-1");
|
EmulationResult result =
|
||||||
emuService.emulate(tb.trace, time, TaskMonitor.DUMMY);
|
emuService.run(tb.host, TraceSchedule.snap(0), monitor, new Scheduler() {
|
||||||
traceManager.activateTime(time);
|
int calls = 0;
|
||||||
|
|
||||||
DebuggerPcodeMachine<?> emu = emuService.getCachedEmulator(tb.trace, time);
|
@Override
|
||||||
|
public TickStep nextSlice(Trace trace) {
|
||||||
|
// Expect decode of uninitialized memory immediately
|
||||||
|
assertEquals(0, calls++);
|
||||||
|
return new TickStep(0, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
DebuggerPcodeMachine<?> emu = emuService.getCachedEmulator(tb.trace, result.schedule());
|
||||||
assertTrue(emu instanceof TaintDebuggerPcodeEmulator);
|
assertTrue(emu instanceof TaintDebuggerPcodeEmulator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ import ghidra.util.Msg;
|
||||||
* @param <B> if this space is a cache, the type of object backing this space
|
* @param <B> if this space is a cache, the type of object backing this space
|
||||||
*/
|
*/
|
||||||
public class BytesPcodeExecutorStateSpace<B> {
|
public class BytesPcodeExecutorStateSpace<B> {
|
||||||
|
protected final static byte[] EMPTY = new byte[] {};
|
||||||
protected final SemisparseByteArray bytes;
|
protected final SemisparseByteArray bytes;
|
||||||
protected final Language language; // for logging diagnostics
|
protected final Language language; // for logging diagnostics
|
||||||
protected final AddressSpace space;
|
protected final AddressSpace space;
|
||||||
|
@ -197,8 +198,13 @@ public class BytesPcodeExecutorStateSpace<B> {
|
||||||
warnUninit(uninitialized);
|
warnUninit(uninitialized);
|
||||||
}
|
}
|
||||||
else if (reason == Reason.EXECUTE_DECODE) {
|
else if (reason == Reason.EXECUTE_DECODE) {
|
||||||
throw new DecodePcodeExecutionException("Cannot decode uninitialized memory",
|
/**
|
||||||
space.getAddress(offset));
|
* The callers may be reading ahead, so it's not appropriate to throw an exception here.
|
||||||
|
* Instead, communicate there's no more. If the buffer's empty on their end, they'll
|
||||||
|
* handle the error as appropriate. If it's in the emulator, the instruction decoder
|
||||||
|
* should eventually throw the decode exception.
|
||||||
|
*/
|
||||||
|
return EMPTY;
|
||||||
}
|
}
|
||||||
return readBytes(offset, size, reason);
|
return readBytes(offset, size, reason);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ public class DecodePcodeExecutionException extends PcodeExecutionException {
|
||||||
private final Address pc;
|
private final Address pc;
|
||||||
|
|
||||||
public DecodePcodeExecutionException(String message, Address pc) {
|
public DecodePcodeExecutionException(String message, Address pc) {
|
||||||
super(message + ", PC=" + pc);
|
super(message.contains("PC=") ? message : "%s (PC=%s)".formatted(message, pc));
|
||||||
this.pc = pc;
|
this.pc = pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue