diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/VisibleAutoReadMemorySpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/VisibleAutoReadMemorySpec.java index bc64214a63..53fd1e3bfa 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/VisibleAutoReadMemorySpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/VisibleAutoReadMemorySpec.java @@ -55,8 +55,9 @@ public class VisibleAutoReadMemorySpec implements AutoReadMemorySpec { return AsyncUtils.NIL; } TraceRecorder recorder = coordinates.getRecorder(); - AddressSet visibleAccessible = - recorder.getAccessibleMemory().intersect(visible); + boolean ffv = coordinates.getView().getMemory().isForceFullView(); + AddressSetView visibleAccessible = + ffv ? visible : recorder.getAccessibleMemory().intersect(visible); TraceMemoryManager mm = coordinates.getTrace().getMemoryManager(); AddressSetView alreadyKnown = mm.getAddressesWithState(coordinates.getSnap(), visibleAccessible, diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/VisibleROOnceAutoReadMemorySpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/VisibleROOnceAutoReadMemorySpec.java index eeadedc261..3888765a7b 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/VisibleROOnceAutoReadMemorySpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/VisibleROOnceAutoReadMemorySpec.java @@ -57,8 +57,9 @@ public class VisibleROOnceAutoReadMemorySpec implements AutoReadMemorySpec { return AsyncUtils.NIL; } TraceRecorder recorder = coordinates.getRecorder(); - AddressSet visibleAccessible = - recorder.getAccessibleMemory().intersect(visible); + boolean ffv = coordinates.getView().getMemory().isForceFullView(); + AddressSetView visibleAccessible = + ffv ? visible : recorder.getAccessibleMemory().intersect(visible); TraceMemoryManager mm = coordinates.getTrace().getMemoryManager(); AddressSetView alreadyKnown = mm.getAddressesWithState(coordinates.getSnap(), visibleAccessible, diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DefaultMemoryRecorder.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DefaultMemoryRecorder.java index 8624a9bcc7..d433f4dcd2 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DefaultMemoryRecorder.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DefaultMemoryRecorder.java @@ -52,6 +52,11 @@ public class DefaultMemoryRecorder implements ManagedMemoryRecorder { return RecorderUtils.INSTANCE.readMemoryBlocks(recorder, BLOCK_BITS, set, monitor, toMap); } + @Override + public void offerProcessMemory(TargetMemory memory) { + recorder.getProcessMemory().addMemory(memory); + } + @Override public void offerProcessRegion(TargetMemoryRegion region) { TargetMemory mem = region.getMemory(); @@ -81,6 +86,11 @@ public class DefaultMemoryRecorder implements ManagedMemoryRecorder { }, path); } + @Override + public void removeProcessMemory(TargetMemory memory) { + recorder.getProcessMemory().removeMemory(memory); + } + @Override public void removeProcessRegion(TargetMemoryRegion region) { // Already removed from processMemory. That's how we knew to go here. diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderComposedMemory.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderComposedMemory.java index 227eb61138..f66ae9ff08 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderComposedMemory.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderComposedMemory.java @@ -115,6 +115,12 @@ public class RecorderComposedMemory implements AbstractRecorderMemory { return byRegion.get(floor.getValue()); } + @Override + public void addMemory(TargetMemory memory) { + // Do nothing + // This delegates by region, so need regions even if I have memory + } + @Override public void addRegion(TargetMemoryRegion region, TargetMemory memory) { synchronized (accessibilityByMemory) { @@ -129,6 +135,11 @@ public class RecorderComposedMemory implements AbstractRecorderMemory { } } + @Override + public void removeMemory(TargetMemory invalid) { + // Do nothing + } + @Override public boolean removeRegion(TargetObject invalid) { if (!(invalid instanceof TargetMemoryRegion)) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderSimpleMemory.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderSimpleMemory.java index d9e13356a2..7824771103 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderSimpleMemory.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderSimpleMemory.java @@ -37,6 +37,15 @@ public class RecorderSimpleMemory implements AbstractRecorderMemory { public RecorderSimpleMemory() { } + @Override + public void addMemory(TargetMemory memory) { + synchronized (this) { + if (this.memory == null) { + this.memory = memory; + } + } + } + @Override public void addRegion(TargetMemoryRegion region, TargetMemory memory) { synchronized (this) { @@ -47,6 +56,15 @@ public class RecorderSimpleMemory implements AbstractRecorderMemory { } } + @Override + public void removeMemory(TargetMemory invalid) { + synchronized (this) { + if (this.memory == invalid) { + this.memory = null; + } + } + } + @Override public boolean removeRegion(TargetObject invalid) { if (!(invalid instanceof TargetMemoryRegion)) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/TraceObjectManager.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/TraceObjectManager.java index 69032d44a3..c535414056 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/TraceObjectManager.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/TraceObjectManager.java @@ -358,6 +358,7 @@ public class TraceObjectManager { if (memMapper != null) { return; } + recorder.memoryRecorder.offerProcessMemory((TargetMemory) added); mapper.offerMemory((TargetMemory) added).thenAccept(mm -> { synchronized (this) { memMapper = mm; @@ -371,7 +372,7 @@ public class TraceObjectManager { } public void removeMemory(TargetObject removed) { - // Nothing for now + recorder.memoryRecorder.removeProcessMemory((TargetMemory) removed); } public void addMemoryRegion(TargetObject added) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/interfaces/AbstractRecorderMemory.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/interfaces/AbstractRecorderMemory.java index 89f6100add..02efe8bc89 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/interfaces/AbstractRecorderMemory.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/interfaces/AbstractRecorderMemory.java @@ -24,8 +24,12 @@ import ghidra.program.model.address.*; public interface AbstractRecorderMemory { + public void addMemory(TargetMemory memory); + public void addRegion(TargetMemoryRegion region, TargetMemory memory); + public void removeMemory(TargetMemory invalid); + public boolean removeRegion(TargetObject invalid); public CompletableFuture readMemory(Address address, int length); @@ -43,5 +47,4 @@ public interface AbstractRecorderMemory { DebuggerMemoryMapper memMapper); public AddressRange alignAndLimitToFloor(Address targetAddress, int length); - } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/interfaces/ManagedMemoryRecorder.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/interfaces/ManagedMemoryRecorder.java index 3537889458..b1e12e97b5 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/interfaces/ManagedMemoryRecorder.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/interfaces/ManagedMemoryRecorder.java @@ -15,15 +15,18 @@ */ package ghidra.app.plugin.core.debug.service.model.interfaces; +import ghidra.dbg.target.TargetMemory; import ghidra.dbg.target.TargetMemoryRegion; import ghidra.trace.model.memory.TraceMemoryRegion; public interface ManagedMemoryRecorder { + void offerProcessMemory(TargetMemory memory); void offerProcessRegion(TargetMemoryRegion region); + void removeProcessMemory(TargetMemory memory); + void removeProcessRegion(TargetMemoryRegion region); TraceMemoryRegion getTraceMemoryRegion(TargetMemoryRegion region); - } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/RecorderUtils.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/RecorderUtils.java index 54a1f22e71..7064328e8d 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/RecorderUtils.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/RecorderUtils.java @@ -54,10 +54,7 @@ public enum RecorderUtils { int blockSize = 1 << blockBits; int total = 0; - AddressSetView expSet = quantize(blockBits, set) - .intersect(recorder.getTrace() - .getMemoryManager() - .getRegionsAddressSet(recorder.getSnap())); + AddressSetView expSet = quantize(blockBits, set); for (AddressRange r : expSet) { total += Long.divideUnsigned(r.getLength() + blockSize - 1, blockSize); } diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java index 8c3ae29ece..d6e9aee085 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java @@ -38,6 +38,7 @@ import ghidra.app.plugin.core.debug.DebuggerCoordinates; import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest; import ghidra.app.plugin.core.debug.gui.DebuggerResources; import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractFollowsCurrentThreadAction; +import ghidra.app.plugin.core.debug.gui.action.AutoReadMemorySpec; import ghidra.app.plugin.core.debug.gui.action.DebuggerGoToDialog; import ghidra.app.plugin.core.debug.gui.console.DebuggerConsolePlugin; import ghidra.app.plugin.core.debug.gui.console.DebuggerConsoleProvider.BoundAction; @@ -687,6 +688,52 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI }); } + public void runTestAutoReadMemoryReadsWithForceFullView(AutoReadMemorySpec spec) + throws Throwable { + byte[] data = incBlock(); + byte[] zero = new byte[data.length]; + ByteBuffer buf = ByteBuffer.allocate(data.length); + listingProvider.setAutoReadMemorySpec(spec); + + createTestModel(); + mb.createTestProcessesAndThreads(); + + // NOTE: Do not add a region. Depend on Force full view! + // Populate target memory before recording + mb.testProcess1.memory.setMemory(mb.addr(0x55550000), data); + + TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1, + createTargetTraceMapper(mb.testProcess1)); + Trace trace = recorder.getTrace(); + waitRecorder(recorder); + traceManager.activateTrace(trace); + waitForSwing(); + + buf.clear(); + assertEquals(data.length, + trace.getMemoryManager().getBytes(recorder.getSnap(), addr(trace, 0x55550000), buf)); + assertArrayEquals(zero, buf.array()); + + runSwing(() -> trace.getProgramView().getMemory().setForceFullView(true)); + goToDyn(addr(trace, 0x55550000)); + waitRecorder(recorder); + + buf.clear(); + assertEquals(data.length, + trace.getMemoryManager().getBytes(recorder.getSnap(), addr(trace, 0x55550000), buf)); + assertArrayEquals(data, buf.array()); + } + + @Test + public void testAutoReadMemoryVisROOnceReadsWithForceFullView() throws Throwable { + runTestAutoReadMemoryReadsWithForceFullView(readVisROOnce); + } + + @Test + public void testAutoReadMemoryVisibleReadsWithForceFullView() throws Throwable { + runTestAutoReadMemoryReadsWithForceFullView(readVisible); + } + @Test public void testMemoryStateBackgroundColors() throws Exception { createAndOpenTrace(); @@ -1067,6 +1114,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI traceManager.activateTrace(tb.trace); } + waitForDomainObject(tb.trace); // In the module, but not in its section listingPlugin.goTo(tb.addr(0x00411234), true); @@ -1096,6 +1144,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI traceManager.activateTrace(tb.trace); } + waitForDomainObject(tb.trace); // In the module, but not in its section listingPlugin.goTo(tb.addr(0x00411234), true);