mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-1625: Improve consistency of DebuggerMemoryBytesProvider
This commit is contained in:
parent
7d189001d6
commit
8e3f97056b
9 changed files with 131 additions and 29 deletions
|
@ -19,6 +19,7 @@ import static ghidra.app.plugin.core.debug.gui.DebuggerResources.ICON_REGISTER_M
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.datatransfer.DataFlavor;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
|
@ -26,8 +27,7 @@ import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.swing.JLabel;
|
import javax.swing.*;
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.event.ChangeEvent;
|
import javax.swing.event.ChangeEvent;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ import ghidra.app.plugin.core.debug.utils.ProgramURLUtils;
|
||||||
import ghidra.app.plugin.core.marker.MarkerMarginProvider;
|
import ghidra.app.plugin.core.marker.MarkerMarginProvider;
|
||||||
import ghidra.app.plugin.core.marker.MarkerOverviewProvider;
|
import ghidra.app.plugin.core.marker.MarkerOverviewProvider;
|
||||||
import ghidra.app.services.*;
|
import ghidra.app.services.*;
|
||||||
|
import ghidra.app.services.DebuggerControlService.ControlModeChangeListener;
|
||||||
import ghidra.app.services.DebuggerListingService.LocationTrackingSpecChangeListener;
|
import ghidra.app.services.DebuggerListingService.LocationTrackingSpecChangeListener;
|
||||||
import ghidra.app.util.viewer.format.FormatManager;
|
import ghidra.app.util.viewer.format.FormatManager;
|
||||||
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
||||||
|
@ -293,7 +294,7 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
||||||
private DebuggerStaticMappingService mappingService;
|
private DebuggerStaticMappingService mappingService;
|
||||||
@AutoServiceConsumed
|
@AutoServiceConsumed
|
||||||
private DebuggerConsoleService consoleService;
|
private DebuggerConsoleService consoleService;
|
||||||
@AutoServiceConsumed
|
//@AutoServiceConsumed via method
|
||||||
private DebuggerControlService controlService;
|
private DebuggerControlService controlService;
|
||||||
@AutoServiceConsumed
|
@AutoServiceConsumed
|
||||||
private ProgramManager programManager;
|
private ProgramManager programManager;
|
||||||
|
@ -354,6 +355,12 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
||||||
|
|
||||||
protected final ForStaticSyncMappingChangeListener mappingChangeListener =
|
protected final ForStaticSyncMappingChangeListener mappingChangeListener =
|
||||||
new ForStaticSyncMappingChangeListener();
|
new ForStaticSyncMappingChangeListener();
|
||||||
|
private final ControlModeChangeListener controlModeChangeListener = (trace, mode) -> {
|
||||||
|
if (trace == current.getTrace()) {
|
||||||
|
// for Paste action
|
||||||
|
contextChanged();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
protected final boolean isMainListing;
|
protected final boolean isMainListing;
|
||||||
|
|
||||||
|
@ -597,6 +604,17 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AutoServiceConsumed
|
||||||
|
private void setControlService(DebuggerControlService controlService) {
|
||||||
|
if (this.controlService != null) {
|
||||||
|
this.controlService.removeModeChangeListener(controlModeChangeListener);
|
||||||
|
}
|
||||||
|
this.controlService = controlService;
|
||||||
|
if (this.controlService != null) {
|
||||||
|
this.controlService.addModeChangeListener(controlModeChangeListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@AutoServiceConsumed
|
@AutoServiceConsumed
|
||||||
private void setConsoleService(DebuggerConsoleService consoleService) {
|
private void setConsoleService(DebuggerConsoleService consoleService) {
|
||||||
if (consoleService != null) {
|
if (consoleService != null) {
|
||||||
|
@ -725,6 +743,14 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
||||||
return DateUtils.formatDateTimestamp(new Date(snapshot.getRealTime()));
|
return DateUtils.formatDateTimestamp(new Date(snapshot.getRealTime()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Icon getIcon() {
|
||||||
|
if (isMainListing()) {
|
||||||
|
return getBaseIcon();
|
||||||
|
}
|
||||||
|
return super.getIcon();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ListingActionContext newListingActionContext() {
|
protected ListingActionContext newListingActionContext() {
|
||||||
return new DebuggerListingActionContext(this);
|
return new DebuggerListingActionContext(this);
|
||||||
|
@ -740,6 +766,21 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
||||||
}
|
}
|
||||||
return context.getComponentProvider() == componentProvider;
|
return context.getComponentProvider() == componentProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canPaste(DataFlavor[] availableFlavors) {
|
||||||
|
if (controlService == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Trace trace = current.getTrace();
|
||||||
|
if (trace == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!controlService.getCurrentMode(trace).canEdit(current)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return super.canPaste(availableFlavors);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ public class DebuggerMemoryBytesPlugin
|
||||||
private void createActions() {
|
private void createActions() {
|
||||||
actionNewMemory = NewMemoryAction.builder(this)
|
actionNewMemory = NewMemoryAction.builder(this)
|
||||||
.enabled(true)
|
.enabled(true)
|
||||||
.onAction(c -> createNewDisconnectedProvider())
|
.onAction(c -> connectedProvider.cloneWindow())
|
||||||
.buildAndInstall(tool);
|
.buildAndInstall(tool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,14 +16,14 @@
|
||||||
package ghidra.app.plugin.core.debug.gui.memory;
|
package ghidra.app.plugin.core.debug.gui.memory;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.datatransfer.DataFlavor;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import javax.swing.JLabel;
|
import javax.swing.*;
|
||||||
import javax.swing.JPanel;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@ import ghidra.app.plugin.core.debug.gui.DebuggerResources.FollowsCurrentThreadAc
|
||||||
import ghidra.app.plugin.core.debug.gui.action.*;
|
import ghidra.app.plugin.core.debug.gui.action.*;
|
||||||
import ghidra.app.plugin.core.debug.gui.action.AutoReadMemorySpec.AutoReadMemorySpecConfigFieldCodec;
|
import ghidra.app.plugin.core.debug.gui.action.AutoReadMemorySpec.AutoReadMemorySpecConfigFieldCodec;
|
||||||
import ghidra.app.plugin.core.format.ByteBlock;
|
import ghidra.app.plugin.core.format.ByteBlock;
|
||||||
|
import ghidra.app.services.DebuggerControlService;
|
||||||
|
import ghidra.app.services.DebuggerControlService.ControlModeChangeListener;
|
||||||
import ghidra.app.services.DebuggerTraceManagerService;
|
import ghidra.app.services.DebuggerTraceManagerService;
|
||||||
import ghidra.debug.api.action.GoToInput;
|
import ghidra.debug.api.action.GoToInput;
|
||||||
import ghidra.debug.api.action.LocationTrackingSpec;
|
import ghidra.debug.api.action.LocationTrackingSpec;
|
||||||
|
@ -168,6 +170,8 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
||||||
|
|
||||||
@AutoServiceConsumed
|
@AutoServiceConsumed
|
||||||
private DebuggerTraceManagerService traceManager;
|
private DebuggerTraceManagerService traceManager;
|
||||||
|
//@AutoServiceConsumed via method
|
||||||
|
private DebuggerControlService controlService;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private final AutoService.Wiring autoServiceWiring;
|
private final AutoService.Wiring autoServiceWiring;
|
||||||
|
|
||||||
|
@ -191,6 +195,12 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
||||||
// TODO: followsCurrentSnap?
|
// TODO: followsCurrentSnap?
|
||||||
|
|
||||||
private final ListenerForChanges listenerForChanges = new ListenerForChanges();
|
private final ListenerForChanges listenerForChanges = new ListenerForChanges();
|
||||||
|
private final ControlModeChangeListener controlModeChangeListener = (trace, mode) -> {
|
||||||
|
if (trace == getCurrent().getTrace()) {
|
||||||
|
// for Paste action
|
||||||
|
contextChanged();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
DebuggerCoordinates current = DebuggerCoordinates.NOWHERE;
|
DebuggerCoordinates current = DebuggerCoordinates.NOWHERE;
|
||||||
private DebuggerCoordinates previous = DebuggerCoordinates.NOWHERE;
|
private DebuggerCoordinates previous = DebuggerCoordinates.NOWHERE;
|
||||||
|
@ -220,6 +230,13 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
||||||
readsMemTrait.goToCoordinates(current);
|
readsMemTrait.goToCoordinates(current);
|
||||||
locationLabel.goToCoordinates(current);
|
locationLabel.goToCoordinates(current);
|
||||||
|
|
||||||
|
if (isConnected) {
|
||||||
|
setTitle(DebuggerResources.TITLE_PROVIDER_MEMORY_BYTES);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setTitle("[" + DebuggerResources.TITLE_PROVIDER_MEMORY_BYTES + "]");
|
||||||
|
}
|
||||||
|
updateTitle(); // Actually, the subtitle
|
||||||
setHelpLocation(DebuggerResources.HELP_PROVIDER_MEMORY_BYTES);
|
setHelpLocation(DebuggerResources.HELP_PROVIDER_MEMORY_BYTES);
|
||||||
|
|
||||||
trackingLabel.addMouseListener(new MouseAdapter() {
|
trackingLabel.addMouseListener(new MouseAdapter() {
|
||||||
|
@ -339,11 +356,50 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
||||||
setSubTitle(computeSubTitle());
|
setSubTitle(computeSubTitle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Icon getIcon() {
|
||||||
|
if (isMainViewer()) {
|
||||||
|
return getBaseIcon();
|
||||||
|
}
|
||||||
|
return super.getIcon();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ByteViewerActionContext newByteViewerActionContext() {
|
protected ByteViewerActionContext newByteViewerActionContext() {
|
||||||
return new DebuggerMemoryBytesActionContext(this);
|
return new DebuggerMemoryBytesActionContext(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ByteViewerClipboardProvider newClipboardProvider() {
|
||||||
|
return new ByteViewerClipboardProvider(this, tool) {
|
||||||
|
@Override
|
||||||
|
public boolean canPaste(DataFlavor[] availableFlavors) {
|
||||||
|
if (controlService == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Trace trace = current.getTrace();
|
||||||
|
if (trace == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!controlService.getCurrentMode(trace).canEdit(current)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return super.canPaste(availableFlavors);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@AutoServiceConsumed
|
||||||
|
private void setControlService(DebuggerControlService controlService) {
|
||||||
|
if (this.controlService != null) {
|
||||||
|
this.controlService.removeModeChangeListener(controlModeChangeListener);
|
||||||
|
}
|
||||||
|
this.controlService = controlService;
|
||||||
|
if (this.controlService != null) {
|
||||||
|
this.controlService.addModeChangeListener(controlModeChangeListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void createActions() {
|
protected void createActions() {
|
||||||
initTraits();
|
initTraits();
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.debug.gui.memory;
|
package ghidra.app.plugin.core.debug.gui.memory;
|
||||||
|
|
||||||
import static ghidra.lifecycle.Unfinished.*;
|
import static ghidra.lifecycle.Unfinished.TODO;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
@ -49,7 +49,7 @@ import ghidra.app.plugin.core.debug.gui.DebuggerResources.FollowsCurrentThreadAc
|
||||||
import ghidra.app.plugin.core.debug.gui.action.*;
|
import ghidra.app.plugin.core.debug.gui.action.*;
|
||||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
|
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
|
||||||
import ghidra.app.plugin.core.debug.service.control.DebuggerControlServicePlugin;
|
import ghidra.app.plugin.core.debug.service.control.DebuggerControlServicePlugin;
|
||||||
import ghidra.app.services.*;
|
import ghidra.app.services.DebuggerControlService;
|
||||||
import ghidra.async.SwingExecutorService;
|
import ghidra.async.SwingExecutorService;
|
||||||
import ghidra.debug.api.control.ControlMode;
|
import ghidra.debug.api.control.ControlMode;
|
||||||
import ghidra.debug.api.model.TraceRecorder;
|
import ghidra.debug.api.model.TraceRecorder;
|
||||||
|
|
|
@ -79,7 +79,6 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
|
||||||
|
|
||||||
private static final String DIVIDER_LOCATION = "DividerLocation";
|
private static final String DIVIDER_LOCATION = "DividerLocation";
|
||||||
|
|
||||||
private ImageIcon navigatableIcon;
|
|
||||||
private Map<Program, ListingHighlightProvider> programHighlighterMap = new HashMap<>();
|
private Map<Program, ListingHighlightProvider> programHighlighterMap = new HashMap<>();
|
||||||
private ProgramHighlighterProvider highlighterAdapter;
|
private ProgramHighlighterProvider highlighterAdapter;
|
||||||
|
|
||||||
|
@ -845,19 +844,6 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
|
||||||
return currentStringSelection;
|
return currentStringSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Icon getIcon() {
|
|
||||||
if (isConnected()) {
|
|
||||||
return super.getIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (navigatableIcon == null) {
|
|
||||||
Icon primaryIcon = super.getIcon();
|
|
||||||
navigatableIcon = NavigatableIconFactory.createSnapshotOverlayIcon(primaryIcon);
|
|
||||||
}
|
|
||||||
return navigatableIcon;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Icon getNavigatableIcon() {
|
public Icon getNavigatableIcon() {
|
||||||
return getIcon();
|
return getIcon();
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -45,11 +44,11 @@ public abstract class NavigatableComponentProviderAdapter extends ComponentProvi
|
||||||
@Override
|
@Override
|
||||||
public Icon getIcon() {
|
public Icon getIcon() {
|
||||||
if (isConnected()) {
|
if (isConnected()) {
|
||||||
return super.getIcon();
|
return getBaseIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (navigatableIcon == null) {
|
if (navigatableIcon == null) {
|
||||||
Icon primaryIcon = super.getIcon();
|
Icon primaryIcon = getBaseIcon();
|
||||||
navigatableIcon = NavigatableIconFactory.createSnapshotOverlayIcon(primaryIcon);
|
navigatableIcon = NavigatableIconFactory.createSnapshotOverlayIcon(primaryIcon);
|
||||||
}
|
}
|
||||||
return navigatableIcon;
|
return navigatableIcon;
|
||||||
|
|
|
@ -57,7 +57,7 @@ public abstract class AbstractByteViewerPlugin<P extends ProgramByteViewerCompon
|
||||||
|
|
||||||
public P createNewDisconnectedProvider() {
|
public P createNewDisconnectedProvider() {
|
||||||
P newProvider = createProvider(false);
|
P newProvider = createProvider(false);
|
||||||
disconnectedProviders.add(newProvider);
|
addProvider(newProvider);
|
||||||
tool.showComponentProvider(newProvider, true);
|
tool.showComponentProvider(newProvider, true);
|
||||||
return newProvider;
|
return newProvider;
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
|
||||||
}
|
}
|
||||||
|
|
||||||
decorationComponent = new DecoratorPanel(panel, isConnected);
|
decorationComponent = new DecoratorPanel(panel, isConnected);
|
||||||
clipboardProvider = new ByteViewerClipboardProvider(this, tool);
|
clipboardProvider = newClipboardProvider();
|
||||||
addToTool();
|
addToTool();
|
||||||
|
|
||||||
createProgramActions();
|
createProgramActions();
|
||||||
|
@ -98,6 +98,10 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
|
||||||
registerNavigatable();
|
registerNavigatable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ByteViewerClipboardProvider newClipboardProvider() {
|
||||||
|
return new ByteViewerClipboardProvider(this, tool);
|
||||||
|
}
|
||||||
|
|
||||||
public void createProgramActions() {
|
public void createProgramActions() {
|
||||||
cloneByteViewerAction = new CloneByteViewerAction();
|
cloneByteViewerAction = new CloneByteViewerAction();
|
||||||
tool.addLocalAction(this, cloneByteViewerAction);
|
tool.addLocalAction(this, cloneByteViewerAction);
|
||||||
|
@ -343,11 +347,11 @@ public class ProgramByteViewerComponentProvider extends ByteViewerComponentProvi
|
||||||
@Override
|
@Override
|
||||||
public Icon getIcon() {
|
public Icon getIcon() {
|
||||||
if (isConnected()) {
|
if (isConnected()) {
|
||||||
return super.getIcon();
|
return getBaseIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (navigatableIcon == null) {
|
if (navigatableIcon == null) {
|
||||||
Icon primaryIcon = super.getIcon();
|
Icon primaryIcon = getBaseIcon();
|
||||||
navigatableIcon = NavigatableIconFactory.createSnapshotOverlayIcon(primaryIcon);
|
navigatableIcon = NavigatableIconFactory.createSnapshotOverlayIcon(primaryIcon);
|
||||||
}
|
}
|
||||||
return navigatableIcon;
|
return navigatableIcon;
|
||||||
|
|
|
@ -628,6 +628,22 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
|
||||||
dockingTool.getWindowManager().setIcon(this, icon);
|
dockingTool.getWindowManager().setIcon(this, icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the icon provided to {@link #setIcon(Icon)}
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This method is final, guaranteeing there is always a means for extensions of this class to
|
||||||
|
* obtain the original icon. Some classes may override {@link #getIcon()} to apply modifications
|
||||||
|
* when the icon is displayed in the UI. Further extensions of that class may wish to override
|
||||||
|
* {@link #getIcon()}, too, and so might want access to the original base icon. This method
|
||||||
|
* provides that access.
|
||||||
|
*
|
||||||
|
* @return the base icon
|
||||||
|
*/
|
||||||
|
protected final Icon getBaseIcon() {
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signals that this provider's action for showing the provider should appear in the main
|
* Signals that this provider's action for showing the provider should appear in the main
|
||||||
* toolbar
|
* toolbar
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue