mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-18 16:40:08 +00:00
Merge remote-tracking branch 'origin/patch'
Conflicts: Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerReadsMemoryTrait.java
This commit is contained in:
commit
878ab5d664
Binary file not shown.
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 48 KiB |
@ -133,8 +133,7 @@ public interface DebuggerResources {
|
||||
ImageIcon ICON_AUTOREAD = ResourceManager.loadImage("images/autoread.png");
|
||||
|
||||
// TODO: Draw a real icon.
|
||||
ImageIcon ICON_READ_MEMORY = ICON_REGIONS;
|
||||
//ResourceManager.loadImage("images/read-memory.png");
|
||||
ImageIcon ICON_REFRESH_MEMORY = ICON_REFRESH;
|
||||
|
||||
ImageIcon ICON_RENAME_SNAPSHOT = ICON_TIME;
|
||||
|
||||
@ -789,12 +788,12 @@ public interface DebuggerResources {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractReadSelectedMemoryAction extends DockingAction {
|
||||
abstract class AbstractRefreshSelectedMemoryAction extends DockingAction {
|
||||
public static final String NAME = "Read Selected Memory";
|
||||
public static final Icon ICON = ICON_READ_MEMORY;
|
||||
public static final Icon ICON = ICON_REFRESH_MEMORY;
|
||||
public static final String HELP_ANCHOR = "read_memory";
|
||||
|
||||
public AbstractReadSelectedMemoryAction(Plugin owner) {
|
||||
public AbstractRefreshSelectedMemoryAction(Plugin owner) {
|
||||
super(NAME, owner.getName());
|
||||
setDescription(
|
||||
"(Re-)read and record memory for the selected addresses into the trace database");
|
||||
|
@ -16,7 +16,9 @@
|
||||
package ghidra.app.plugin.core.debug.gui.action;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.ComponentProvider;
|
||||
@ -27,12 +29,16 @@ import docking.menu.MultiStateDockingAction;
|
||||
import docking.widgets.EventTrigger;
|
||||
import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractReadSelectedMemoryAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractRefreshSelectedMemoryAction;
|
||||
import ghidra.app.plugin.core.debug.gui.action.AutoReadMemorySpec.AutoReadMemorySpecConfigFieldCodec;
|
||||
import ghidra.app.plugin.core.debug.utils.BackgroundUtils;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.app.services.TraceRecorderListener;
|
||||
import ghidra.app.util.viewer.listingpanel.AddressSetDisplayListener;
|
||||
import ghidra.dbg.DebuggerObjectModel;
|
||||
import ghidra.dbg.target.TargetMemory;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.util.PathMatcher;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.annotation.AutoConfigStateField;
|
||||
@ -49,10 +55,10 @@ public abstract class DebuggerReadsMemoryTrait {
|
||||
protected static final AutoConfigState.ClassHandler<DebuggerReadsMemoryTrait> CONFIG_STATE_HANDLER =
|
||||
AutoConfigState.wireHandler(DebuggerReadsMemoryTrait.class, MethodHandles.lookup());
|
||||
|
||||
protected class ReadSelectedMemoryAction extends AbstractReadSelectedMemoryAction {
|
||||
protected class RefreshSelectedMemoryAction extends AbstractRefreshSelectedMemoryAction {
|
||||
public static final String GROUP = DebuggerResources.GROUP_GENERAL;
|
||||
|
||||
public ReadSelectedMemoryAction() {
|
||||
public RefreshSelectedMemoryAction() {
|
||||
super(plugin);
|
||||
setToolBarData(new ToolBarData(ICON, GROUP));
|
||||
setEnabled(false);
|
||||
@ -60,22 +66,40 @@ public abstract class DebuggerReadsMemoryTrait {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
AddressSetView selection = getSelection();
|
||||
if (selection == null || selection.isEmpty() || !current.isAliveAndReadsPresent()) {
|
||||
if (!current.isAliveAndReadsPresent()) {
|
||||
return;
|
||||
}
|
||||
AddressSetView selection = getSelection();
|
||||
if (selection == null || selection.isEmpty()) {
|
||||
selection = visible;
|
||||
}
|
||||
final AddressSetView sel = selection;
|
||||
Trace trace = current.getTrace();
|
||||
TraceRecorder recorder = current.getRecorder();
|
||||
BackgroundUtils.async(tool, trace, NAME, true, true, false,
|
||||
(__, monitor) -> recorder.readMemoryBlocks(selection, monitor, false));
|
||||
BackgroundUtils.async(tool, trace, NAME, true, true, false, (_t, monitor) -> {
|
||||
TargetObject target = recorder.getTarget();
|
||||
DebuggerObjectModel model = target.getModel();
|
||||
model.invalidateAllLocalCaches();
|
||||
PathMatcher memMatcher = target.getSchema().searchFor(TargetMemory.class, true);
|
||||
Collection<TargetObject> memories = memMatcher.getCachedSuccessors(target).values();
|
||||
CompletableFuture<?>[] requests = memories.stream()
|
||||
.map(TargetObject::invalidateCaches)
|
||||
.toArray(CompletableFuture[]::new);
|
||||
return CompletableFuture.allOf(requests).thenCompose(_r -> {
|
||||
return recorder.readMemoryBlocks(sel, monitor, false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForContext(ActionContext context) {
|
||||
AddressSetView selection = getSelection();
|
||||
if (selection == null || selection.isEmpty() || !current.isAliveAndReadsPresent()) {
|
||||
if (!current.isAliveAndReadsPresent()) {
|
||||
return false;
|
||||
}
|
||||
AddressSetView selection = getSelection();
|
||||
if (selection == null || selection.isEmpty()) {
|
||||
selection = visible;
|
||||
}
|
||||
TraceRecorder recorder = current.getRecorder();
|
||||
// TODO: Either allow partial, or provide action to intersect with accessible
|
||||
if (!recorder.getAccessibleMemory().contains(selection)) {
|
||||
@ -96,7 +120,7 @@ public abstract class DebuggerReadsMemoryTrait {
|
||||
}
|
||||
|
||||
private void snapshotAdded(TraceSnapshot snapshot) {
|
||||
actionReadSelected.updateEnabled(null);
|
||||
actionRefreshSelected.updateEnabled(null);
|
||||
}
|
||||
|
||||
private void memStateChanged(TraceAddressSnapRange range, TraceMemoryState oldIsNull,
|
||||
@ -120,7 +144,7 @@ public abstract class DebuggerReadsMemoryTrait {
|
||||
@Override
|
||||
public void processMemoryAccessibilityChanged(TraceRecorder recorder) {
|
||||
Swing.runIfSwingOrRunLater(() -> {
|
||||
actionReadSelected.updateEnabled(null);
|
||||
actionRefreshSelected.updateEnabled(null);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -137,7 +161,7 @@ public abstract class DebuggerReadsMemoryTrait {
|
||||
}
|
||||
|
||||
protected MultiStateDockingAction<AutoReadMemorySpec> actionAutoRead;
|
||||
protected ReadSelectedMemoryAction actionReadSelected;
|
||||
protected RefreshSelectedMemoryAction actionRefreshSelected;
|
||||
|
||||
private final AutoReadMemorySpec defaultAutoSpec =
|
||||
AutoReadMemorySpec.fromConfigName(VisibleROOnceAutoReadMemorySpec.CONFIG_NAME);
|
||||
@ -257,10 +281,10 @@ public abstract class DebuggerReadsMemoryTrait {
|
||||
}
|
||||
}
|
||||
|
||||
public DockingAction installReadSelectedAction() {
|
||||
actionReadSelected = new ReadSelectedMemoryAction();
|
||||
provider.addLocalAction(actionReadSelected);
|
||||
return actionReadSelected;
|
||||
public DockingAction installRefreshSelectedAction() {
|
||||
actionRefreshSelected = new RefreshSelectedMemoryAction();
|
||||
provider.addLocalAction(actionRefreshSelected);
|
||||
return actionRefreshSelected;
|
||||
}
|
||||
|
||||
public AddressSetDisplayListener getDisplayListener() {
|
||||
|
@ -245,7 +245,7 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
||||
protected SyncToStaticListingAction actionSyncToStaticListing;
|
||||
protected FollowsCurrentThreadAction actionFollowsCurrentThread;
|
||||
protected MultiStateDockingAction<AutoReadMemorySpec> actionAutoReadMemory;
|
||||
protected DockingAction actionReadSelectedMemory;
|
||||
protected DockingAction actionRefreshSelectedMemory;
|
||||
protected DockingAction actionOpenProgram;
|
||||
protected MultiStateDockingAction<LocationTrackingSpec> actionTrackLocation;
|
||||
|
||||
@ -642,7 +642,7 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
||||
actionGoTo = goToTrait.installAction();
|
||||
actionTrackLocation = trackingTrait.installAction();
|
||||
actionAutoReadMemory = readsMemTrait.installAutoReadAction();
|
||||
actionReadSelectedMemory = readsMemTrait.installReadSelectedAction();
|
||||
actionRefreshSelectedMemory = readsMemTrait.installRefreshSelectedAction();
|
||||
|
||||
actionOpenProgram = OpenProgramAction.builder(plugin)
|
||||
.withContext(DebuggerOpenProgramActionContext.class)
|
||||
|
@ -152,7 +152,7 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
||||
protected DockingAction actionGoTo;
|
||||
protected FollowsCurrentThreadAction actionFollowsCurrentThread;
|
||||
protected MultiStateDockingAction<AutoReadMemorySpec> actionAutoReadMemory;
|
||||
protected DockingAction actionReadSelectedMemory;
|
||||
protected DockingAction actionRefreshSelectedMemory;
|
||||
protected MultiStateDockingAction<LocationTrackingSpec> actionTrackLocation;
|
||||
|
||||
protected ForMemoryBytesGoToTrait goToTrait;
|
||||
@ -286,7 +286,7 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
||||
actionGoTo = goToTrait.installAction();
|
||||
actionTrackLocation = trackingTrait.installAction();
|
||||
actionAutoReadMemory = readsMemTrait.installAutoReadAction();
|
||||
actionReadSelectedMemory = readsMemTrait.installReadSelectedAction();
|
||||
actionRefreshSelectedMemory = readsMemTrait.installRefreshSelectedAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -80,7 +80,7 @@ public class DebuggerListingPluginScreenShots extends GhidraScreenShotGenerator
|
||||
"clone", global, SourceType.USER_DEFINED);
|
||||
TraceSymbol childLabel = symbolManager
|
||||
.labels()
|
||||
.create(snap, null, tb.addr(0x00400034),
|
||||
.create(snap, null, tb.addr(0x00400032),
|
||||
"child", global, SourceType.USER_DEFINED);
|
||||
@SuppressWarnings("unused")
|
||||
TraceSymbol exitLabel = symbolManager
|
||||
|
@ -935,7 +935,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
byte[] data = incBlock();
|
||||
byte[] zero = new byte[data.length];
|
||||
ByteBuffer buf = ByteBuffer.allocate(data.length);
|
||||
assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertFalse(listingProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
listingProvider.setAutoReadMemorySpec(readNone);
|
||||
|
||||
// To verify enabled requires live target
|
||||
@ -950,12 +950,12 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
// Still
|
||||
assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertFalse(listingProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
|
||||
listingProvider.setSelection(sel);
|
||||
waitForSwing();
|
||||
// Still
|
||||
assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertFalse(listingProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
|
||||
// Now, simulate the sequence that typically enables the action
|
||||
createTestModel();
|
||||
@ -972,12 +972,12 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
|
||||
// NOTE: recordTargetContainerAndOpenTrace has already activated the trace
|
||||
// Action is still disabled, because it requires a selection
|
||||
assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertFalse(listingProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
|
||||
listingProvider.setSelection(sel);
|
||||
waitForSwing();
|
||||
// Now, it should be enabled
|
||||
assertTrue(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertTrue(listingProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
|
||||
// First check nothing captured yet
|
||||
buf.clear();
|
||||
@ -986,7 +986,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
assertArrayEquals(zero, buf.array());
|
||||
|
||||
// Verify that the action performs the expected task
|
||||
performAction(listingProvider.actionReadSelectedMemory);
|
||||
performAction(listingProvider.actionRefreshSelectedMemory);
|
||||
waitForBusyTool(tool);
|
||||
waitForDomainObject(trace);
|
||||
|
||||
@ -1001,28 +1001,28 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
||||
|
||||
// Verify that setting the memory inaccessible disables the action
|
||||
mb.testProcess1.memory.setAccessible(false);
|
||||
waitForPass(() -> assertFalse(listingProvider.actionReadSelectedMemory.isEnabled()));
|
||||
waitForPass(() -> assertFalse(listingProvider.actionRefreshSelectedMemory.isEnabled()));
|
||||
|
||||
// Verify that setting it accessible re-enables it (assuming we still have selection)
|
||||
mb.testProcess1.memory.setAccessible(true);
|
||||
waitForPass(() -> assertTrue(listingProvider.actionReadSelectedMemory.isEnabled()));
|
||||
waitForPass(() -> assertTrue(listingProvider.actionRefreshSelectedMemory.isEnabled()));
|
||||
|
||||
// Verify that moving into the past disables the action
|
||||
TraceSnapshot forced = recorder.forceSnapshot();
|
||||
waitForSwing(); // UI Wants to sync with new snap. Wait....
|
||||
traceManager.activateSnap(forced.getKey() - 1);
|
||||
waitForSwing();
|
||||
assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertFalse(listingProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
|
||||
// Verify that advancing to the present enables the action (assuming a selection)
|
||||
traceManager.activateSnap(forced.getKey());
|
||||
waitForSwing();
|
||||
assertTrue(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertTrue(listingProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
|
||||
// Verify that stopping the recording disables the action
|
||||
recorder.stopRecording();
|
||||
waitForSwing();
|
||||
assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertFalse(listingProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
|
||||
// TODO: When resume recording is implemented, verify action is enabled with selection
|
||||
}
|
||||
|
@ -746,7 +746,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
||||
byte[] data = incBlock();
|
||||
byte[] zero = new byte[data.length];
|
||||
ByteBuffer buf = ByteBuffer.allocate(data.length);
|
||||
assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertFalse(memBytesProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
runSwing(() -> memBytesProvider.setAutoReadMemorySpec(readNone));
|
||||
|
||||
// To verify enabled requires live target
|
||||
@ -761,12 +761,12 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
||||
traceManager.activateTrace(tb.trace);
|
||||
waitForSwing();
|
||||
// Still
|
||||
assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertFalse(memBytesProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
|
||||
memBytesProvider.setSelection(sel);
|
||||
waitForSwing();
|
||||
// Still
|
||||
assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertFalse(memBytesProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
|
||||
// Now, simulate the sequence that typically enables the action
|
||||
createTestModel();
|
||||
@ -783,12 +783,12 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
||||
|
||||
// NOTE: recordTargetContainerAndOpenTrace has already activated the trace
|
||||
// Action is still disabled, because it requires a selection
|
||||
assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertFalse(memBytesProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
|
||||
memBytesProvider.setSelection(sel);
|
||||
waitForSwing();
|
||||
// Now, it should be enabled
|
||||
assertTrue(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertTrue(memBytesProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
|
||||
// First check nothing recorded yet
|
||||
buf.clear();
|
||||
@ -797,7 +797,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
||||
assertArrayEquals(zero, buf.array());
|
||||
|
||||
// Verify that the action performs the expected task
|
||||
performAction(memBytesProvider.actionReadSelectedMemory);
|
||||
performAction(memBytesProvider.actionRefreshSelectedMemory);
|
||||
waitForBusyTool(tool);
|
||||
waitForDomainObject(trace);
|
||||
|
||||
@ -812,28 +812,28 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
||||
|
||||
// Verify that setting the memory inaccessible disables the action
|
||||
mb.testProcess1.memory.setAccessible(false);
|
||||
waitForPass(() -> assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled()));
|
||||
waitForPass(() -> assertFalse(memBytesProvider.actionRefreshSelectedMemory.isEnabled()));
|
||||
|
||||
// Verify that setting it accessible re-enables it (assuming we still have selection)
|
||||
mb.testProcess1.memory.setAccessible(true);
|
||||
waitForPass(() -> assertTrue(memBytesProvider.actionReadSelectedMemory.isEnabled()));
|
||||
waitForPass(() -> assertTrue(memBytesProvider.actionRefreshSelectedMemory.isEnabled()));
|
||||
|
||||
// Verify that moving into the past disables the action
|
||||
TraceSnapshot forced = recorder.forceSnapshot();
|
||||
waitForSwing(); // UI Wants to sync with new snap. Wait....
|
||||
traceManager.activateSnap(forced.getKey() - 1);
|
||||
waitForSwing();
|
||||
assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertFalse(memBytesProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
|
||||
// Verify that advancing to the present enables the action (assuming a selection)
|
||||
traceManager.activateSnap(forced.getKey());
|
||||
waitForSwing();
|
||||
assertTrue(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertTrue(memBytesProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
|
||||
// Verify that stopping the recording disables the action
|
||||
recorder.stopRecording();
|
||||
waitForSwing();
|
||||
assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
|
||||
assertFalse(memBytesProvider.actionRefreshSelectedMemory.isEnabled());
|
||||
|
||||
// TODO: When resume recording is implemented, verify action is enabled with selection
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user