diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/pcode/exec/trace/TraceCachedWriteBytesPcodeExecutorState.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/pcode/exec/trace/TraceCachedWriteBytesPcodeExecutorState.java index ee9c0e3360..f40028c6ea 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/pcode/exec/trace/TraceCachedWriteBytesPcodeExecutorState.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/pcode/exec/trace/TraceCachedWriteBytesPcodeExecutorState.java @@ -131,7 +131,8 @@ public class TraceCachedWriteBytesPcodeExecutorState public byte[] read(long offset, int size) { if (source != null) { // TODO: Warn or bail when reading UNKNOWN bytes - // NOTE: Not going to worry about gaps here: + // NOTE: Read without regard to gaps + // NOTE: Cannot write those gaps, though!!! RangeSet uninitialized = cache.getUninitialized(offset, offset + size); if (!uninitialized.isEmpty()) { @@ -141,7 +142,11 @@ public class TraceCachedWriteBytesPcodeExecutorState long upper = upper(toRead); ByteBuffer buf = ByteBuffer.allocate((int) (upper - lower + 1)); source.getBytes(snap, space.getAddress(lower), buf); - cache.putData(lower, buf.array()); + for (Range rng : uninitialized.asRanges()) { + long l = lower(rng); + long u = upper(rng); + cache.putData(l, buf.array(), (int) (l - lower), (int) (u - l + 1)); + } } } byte[] data = new byte[size]; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/pcode/exec/trace/TracePcodeEmulatorTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/pcode/exec/trace/TracePcodeEmulatorTest.java index 568c3ad71f..3d7da631ad 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/pcode/exec/trace/TracePcodeEmulatorTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/pcode/exec/trace/TracePcodeEmulatorTest.java @@ -705,4 +705,31 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes TraceSleighUtils.evaluate("RAX", tb.trace, 1, thread, 0)); } } + + @Test + public void testCachedReadAfterSmallWrite() throws Throwable { + try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) { + TraceThread thread = initTrace(tb, + List.of( + "RIP = 0x00400000;", + "RSP = 0x00110000;", + "RAX = 0x12345678;"), + List.of( + "XOR AH, AH", + "MOV RCX, RAX")); + + TracePcodeEmulator emu = new TracePcodeEmulator(tb.trace, 0); + PcodeThread emuThread = emu.newThread(thread.getPath()); + emuThread.overrideContextWithDefault(); + emuThread.stepInstruction(); + emuThread.stepInstruction(); + + try (UndoableTransaction tid = tb.startTransaction()) { + emu.writeDown(tb.trace, 1, 1, false); + } + + assertEquals(BigInteger.valueOf(0x12340078), + TraceSleighUtils.evaluate("RAX", tb.trace, 1, thread, 0)); + } + } }