mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-4311: Add Context menu to Location labels
This commit is contained in:
parent
247528c7fe
commit
1bd3fe3669
13 changed files with 231 additions and 149 deletions
|
@ -15,12 +15,18 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.debug.gui;
|
package ghidra.app.plugin.core.debug.gui;
|
||||||
|
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
|
|
||||||
import org.apache.commons.collections4.ComparatorUtils;
|
import org.apache.commons.collections4.ComparatorUtils;
|
||||||
|
|
||||||
|
import docking.ActionContext;
|
||||||
|
import docking.ComponentProvider;
|
||||||
|
import ghidra.app.plugin.core.debug.gui.memory.DebuggerRegionActionContext;
|
||||||
|
import ghidra.app.plugin.core.debug.gui.modules.DebuggerModuleActionContext;
|
||||||
|
import ghidra.app.plugin.core.debug.gui.modules.DebuggerSectionActionContext;
|
||||||
import ghidra.async.AsyncDebouncer;
|
import ghidra.async.AsyncDebouncer;
|
||||||
import ghidra.async.AsyncTimer;
|
import ghidra.async.AsyncTimer;
|
||||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||||
|
@ -204,4 +210,33 @@ public class DebuggerLocationLabel extends JLabel {
|
||||||
setText(label);
|
setText(label);
|
||||||
setToolTipText(label);
|
setToolTipText(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ActionContext getActionContext(ComponentProvider provider, MouseEvent event) {
|
||||||
|
TraceProgramView view = current.getView();
|
||||||
|
if (view == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (address == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
TraceSection section = getNearestSectionContaining();
|
||||||
|
if (section != null) {
|
||||||
|
return new DebuggerSectionActionContext(provider, Set.of(section), this, true);
|
||||||
|
}
|
||||||
|
TraceModule module = getNearestModuleContaining();
|
||||||
|
if (module != null) {
|
||||||
|
return new DebuggerModuleActionContext(provider, Set.of(module), this, true);
|
||||||
|
}
|
||||||
|
TraceMemoryRegion region = getRegionContaining();
|
||||||
|
if (region != null) {
|
||||||
|
return new DebuggerRegionActionContext(provider, Set.of(region), this, true);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Throwable t) {
|
||||||
|
// The error should already be displayed in the label
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -433,10 +433,9 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
||||||
* little conflated, since before the debugger, no one else presented a listing that could claim
|
* little conflated, since before the debugger, no one else presented a listing that could claim
|
||||||
* to be "main" except the "connected" one. Here, we treat "connected" to mean that the address
|
* to be "main" except the "connected" one. Here, we treat "connected" to mean that the address
|
||||||
* is synchronized exactly with the other providers. "Main" on the other hand, does not
|
* is synchronized exactly with the other providers. "Main" on the other hand, does not
|
||||||
* necessarily have that property, but it is still <em>not</em> a snapshot. It is the main
|
* necessarily have that property, but it is still <em>not</em> a clone. It is the main listing
|
||||||
* listing presented by this plugin, and so it has certain unique features. Calling
|
* presented by this plugin, and so it has certain unique features. Calling
|
||||||
* {@link DebuggerListingPlugin#getProvider()} will return the main dynamic listing, despite it
|
* {@link DebuggerListingPlugin#getProvider()} will return the main dynamic listing.
|
||||||
* not really being "connected."
|
|
||||||
*
|
*
|
||||||
* @return true if this is the main listing for the plugin.
|
* @return true if this is the main listing for the plugin.
|
||||||
*/
|
*/
|
||||||
|
@ -884,6 +883,14 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionContext getActionContext(MouseEvent event) {
|
||||||
|
if (event == null || event.getSource() != locationLabel) {
|
||||||
|
return super.getActionContext(event);
|
||||||
|
}
|
||||||
|
return locationLabel.getActionContext(this, event);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void programSelectionChanged(ProgramSelection selection, EventTrigger trigger) {
|
public void programSelectionChanged(ProgramSelection selection, EventTrigger trigger) {
|
||||||
super.programSelectionChanged(selection, trigger);
|
super.programSelectionChanged(selection, trigger);
|
||||||
|
|
|
@ -21,7 +21,6 @@ import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.table.TableColumn;
|
import javax.swing.table.TableColumn;
|
||||||
|
@ -116,27 +115,11 @@ public class DebuggerLegacyRegionsPanel extends JPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static RegionRow getSelectedRegionRow(ActionContext context) {
|
|
||||||
if (!(context instanceof DebuggerRegionActionContext)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
DebuggerRegionActionContext ctx = (DebuggerRegionActionContext) context;
|
|
||||||
Set<RegionRow> regions = ctx.getSelectedRegions();
|
|
||||||
if (regions.size() != 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return regions.iterator().next();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static Set<TraceMemoryRegion> getSelectedRegions(ActionContext context) {
|
protected static Set<TraceMemoryRegion> getSelectedRegions(ActionContext context) {
|
||||||
if (!(context instanceof DebuggerRegionActionContext)) {
|
if (!(context instanceof DebuggerRegionActionContext ctx)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
DebuggerRegionActionContext ctx = (DebuggerRegionActionContext) context;
|
return ctx.getSelectedRegions();
|
||||||
return ctx.getSelectedRegions()
|
|
||||||
.stream()
|
|
||||||
.map(r -> r.getRegion())
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class RegionsListener extends TraceDomainObjectListener {
|
private class RegionsListener extends TraceDomainObjectListener {
|
||||||
|
@ -279,16 +262,6 @@ public class DebuggerLegacyRegionsPanel extends JPanel {
|
||||||
return !ctx.getSelectedRegions().isEmpty();
|
return !ctx.getSelectedRegions().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<TraceMemoryRegion> getSelectedRegions(DebuggerRegionActionContext ctx) {
|
|
||||||
if (ctx == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return ctx.getSelectedRegions()
|
|
||||||
.stream()
|
|
||||||
.map(r -> r.getRegion())
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void navigateToSelectedRegion() {
|
protected void navigateToSelectedRegion() {
|
||||||
if (listingService != null) {
|
if (listingService != null) {
|
||||||
int selectedRow = regionTable.getSelectedRow();
|
int selectedRow = regionTable.getSelectedRow();
|
||||||
|
|
|
@ -27,6 +27,7 @@ import javax.swing.JPanel;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import docking.ActionContext;
|
||||||
import docking.action.DockingAction;
|
import docking.action.DockingAction;
|
||||||
import docking.action.ToggleDockingAction;
|
import docking.action.ToggleDockingAction;
|
||||||
import docking.menu.MultiStateDockingAction;
|
import docking.menu.MultiStateDockingAction;
|
||||||
|
@ -539,6 +540,10 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
||||||
@Override
|
@Override
|
||||||
protected void writeConfigState(SaveState saveState) {
|
protected void writeConfigState(SaveState saveState) {
|
||||||
super.writeConfigState(saveState);
|
super.writeConfigState(saveState);
|
||||||
|
|
||||||
|
CONFIG_STATE_HANDLER.writeConfigState(this, saveState);
|
||||||
|
trackingTrait.writeConfigState(saveState);
|
||||||
|
readsMemTrait.writeConfigState(saveState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -547,6 +552,7 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
||||||
|
|
||||||
CONFIG_STATE_HANDLER.readConfigState(this, saveState);
|
CONFIG_STATE_HANDLER.readConfigState(this, saveState);
|
||||||
trackingTrait.readConfigState(saveState);
|
trackingTrait.readConfigState(saveState);
|
||||||
|
readsMemTrait.readConfigState(saveState);
|
||||||
|
|
||||||
if (isMainViewer()) {
|
if (isMainViewer()) {
|
||||||
followsCurrentThread = true;
|
followsCurrentThread = true;
|
||||||
|
@ -555,7 +561,6 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
||||||
actionFollowsCurrentThread.setSelected(followsCurrentThread);
|
actionFollowsCurrentThread.setSelected(followsCurrentThread);
|
||||||
updateBorder();
|
updateBorder();
|
||||||
}
|
}
|
||||||
// TODO: actionAutoReadMemory
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -583,6 +588,14 @@ public class DebuggerMemoryBytesProvider extends ProgramByteViewerComponentProvi
|
||||||
locationLabel.goToAddress(currentLocation == null ? null : currentLocation.getAddress());
|
locationLabel.goToAddress(currentLocation == null ? null : currentLocation.getAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionContext getActionContext(MouseEvent event) {
|
||||||
|
if (event == null || event.getSource() != locationLabel) {
|
||||||
|
return super.getActionContext(event);
|
||||||
|
}
|
||||||
|
return locationLabel.getActionContext(this, event);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cloneWindow() {
|
public void cloneWindow() {
|
||||||
final DebuggerMemoryBytesProvider newProvider = myPlugin.createNewDisconnectedProvider();
|
final DebuggerMemoryBytesProvider newProvider = myPlugin.createNewDisconnectedProvider();
|
||||||
|
|
|
@ -15,22 +15,41 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.debug.gui.memory;
|
package ghidra.app.plugin.core.debug.gui.memory;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import docking.ComponentProvider;
|
||||||
import docking.DefaultActionContext;
|
import docking.DefaultActionContext;
|
||||||
import docking.widgets.table.GTable;
|
import docking.widgets.table.GTable;
|
||||||
|
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||||
|
|
||||||
public class DebuggerRegionActionContext extends DefaultActionContext {
|
public class DebuggerRegionActionContext extends DefaultActionContext {
|
||||||
private final Set<RegionRow> selectedRegions;
|
private final Set<TraceMemoryRegion> selectedRegions;
|
||||||
|
private final boolean forcedSingle;
|
||||||
|
|
||||||
|
private static Set<TraceMemoryRegion> toRegions(Collection<RegionRow> rows) {
|
||||||
|
return rows.stream().map(RegionRow::getRegion).collect(Collectors.toUnmodifiableSet());
|
||||||
|
}
|
||||||
|
|
||||||
public DebuggerRegionActionContext(DebuggerRegionsProvider provider,
|
public DebuggerRegionActionContext(DebuggerRegionsProvider provider,
|
||||||
Collection<RegionRow> selected, GTable table) {
|
Collection<RegionRow> rows, GTable table) {
|
||||||
super(provider, selected, table);
|
this(provider, toRegions(rows), table, false);
|
||||||
this.selectedRegions = Set.copyOf(selected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<RegionRow> getSelectedRegions() {
|
public DebuggerRegionActionContext(ComponentProvider provider,
|
||||||
|
Set<TraceMemoryRegion> selected, Component sourceComponent, boolean forcedSingle) {
|
||||||
|
super(provider, selected, sourceComponent);
|
||||||
|
this.selectedRegions = selected;
|
||||||
|
this.forcedSingle = forcedSingle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<TraceMemoryRegion> getSelectedRegions() {
|
||||||
return selectedRegions;
|
return selectedRegions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isForcedSingle() {
|
||||||
|
return forcedSingle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,10 +177,8 @@ public class DebuggerRegionsPanel extends AbstractObjectsTableBasedPanel<TraceOb
|
||||||
return new ModelQuery(schema.searchFor(TargetMemoryRegion.class, path, true));
|
return new ModelQuery(schema.searchFor(TargetMemoryRegion.class, path, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Set<TraceMemoryRegion> getSelectedRegions(DebuggerObjectActionContext ctx) {
|
protected Set<TraceMemoryRegion> getSelectedRegions(DebuggerObjectActionContext ctx) {
|
||||||
return ctx == null ? null
|
return ctx == null ? null : getSelected(ctx).collect(Collectors.toSet());
|
||||||
: AbstractObjectsTableBasedPanel.getSelected(ctx, TraceObjectMemoryRegion.class)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DebuggerRegionsPanel(DebuggerRegionsProvider provider) {
|
public DebuggerRegionsPanel(DebuggerRegionsProvider provider) {
|
||||||
|
|
|
@ -278,20 +278,22 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter {
|
||||||
|
|
||||||
protected void createActions() {
|
protected void createActions() {
|
||||||
actionMapRegions = MapRegionsAction.builder(plugin)
|
actionMapRegions = MapRegionsAction.builder(plugin)
|
||||||
.enabledWhen(this::isContextNonEmpty)
|
.enabledWhen(ctx -> isContextNonEmpty(ctx) && isContextNotForcedSingle(ctx))
|
||||||
.popupWhen(this::isContextNonEmpty)
|
.popupWhen(ctx -> isContextNonEmpty(ctx) && isContextNotForcedSingle(ctx))
|
||||||
.onAction(this::activatedMapRegions)
|
.onAction(this::activatedMapRegions)
|
||||||
.buildAndInstallLocal(this);
|
.buildAndInstall(tool);
|
||||||
actionMapRegionTo = MapRegionToAction.builder(plugin)
|
actionMapRegionTo = MapRegionToAction.builder(plugin)
|
||||||
.enabledWhen(ctx -> currentProgram != null && isContextSingleSelection(ctx))
|
.enabledWhen(ctx -> currentProgram != null && isContextSingleSelection(ctx))
|
||||||
.popupWhen(ctx -> currentProgram != null && isContextSingleSelection(ctx))
|
.popupWhen(ctx -> currentProgram != null && isContextSingleSelection(ctx))
|
||||||
.onAction(this::activatedMapRegionTo)
|
.onAction(this::activatedMapRegionTo)
|
||||||
.buildAndInstallLocal(this);
|
.buildAndInstall(tool);
|
||||||
actionMapRegionsTo = MapRegionsToAction.builder(plugin)
|
actionMapRegionsTo = MapRegionsToAction.builder(plugin)
|
||||||
.enabledWhen(ctx -> currentProgram != null && isContextNonEmpty(ctx))
|
.enabledWhen(ctx -> currentProgram != null && isContextNonEmpty(ctx) &&
|
||||||
.popupWhen(ctx -> currentProgram != null && isContextNonEmpty(ctx))
|
isContextNotForcedSingle(ctx))
|
||||||
|
.popupWhen(ctx -> currentProgram != null && isContextNonEmpty(ctx) &&
|
||||||
|
isContextNotForcedSingle(ctx))
|
||||||
.onAction(this::activatedMapRegionsTo)
|
.onAction(this::activatedMapRegionsTo)
|
||||||
.buildAndInstallLocal(this);
|
.buildAndInstall(tool);
|
||||||
actionSelectAddresses = new SelectAddressesAction();
|
actionSelectAddresses = new SelectAddressesAction();
|
||||||
actionSelectRows = SelectRowsAction.builder(plugin)
|
actionSelectRows = SelectRowsAction.builder(plugin)
|
||||||
.description("Select regions by dynamic selection")
|
.description("Select regions by dynamic selection")
|
||||||
|
@ -329,26 +331,33 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isContextNonEmpty(ActionContext context) {
|
private boolean isContextNonEmpty(ActionContext context) {
|
||||||
if (context instanceof DebuggerRegionActionContext legacyCtx) {
|
if (context instanceof DebuggerRegionActionContext ctx) {
|
||||||
return legacyPanel.isContextNonEmpty(legacyCtx);
|
return legacyPanel.isContextNonEmpty(ctx);
|
||||||
}
|
}
|
||||||
else if (context instanceof DebuggerObjectActionContext ctx) {
|
else if (context instanceof DebuggerObjectActionContext ctx) {
|
||||||
return DebuggerRegionsPanel.isContextNonEmpty(ctx);
|
return panel.isContextNonEmpty(ctx);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isContextNotForcedSingle(ActionContext context) {
|
||||||
|
if (context instanceof DebuggerRegionActionContext ctx) {
|
||||||
|
return !ctx.isForcedSingle();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isContextSingleSelection(ActionContext context) {
|
private boolean isContextSingleSelection(ActionContext context) {
|
||||||
Set<TraceMemoryRegion> sel = getSelectedRegions(context);
|
Set<TraceMemoryRegion> sel = getSelectedRegions(context);
|
||||||
return sel != null && sel.size() == 1;
|
return sel != null && sel.size() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<TraceMemoryRegion> getSelectedRegions(ActionContext context) {
|
private Set<TraceMemoryRegion> getSelectedRegions(ActionContext context) {
|
||||||
if (context instanceof DebuggerRegionActionContext legacyCtx) {
|
if (context instanceof DebuggerRegionActionContext ctx) {
|
||||||
return DebuggerLegacyRegionsPanel.getSelectedRegions(legacyCtx);
|
return DebuggerLegacyRegionsPanel.getSelectedRegions(ctx);
|
||||||
}
|
}
|
||||||
else if (context instanceof DebuggerObjectActionContext ctx) {
|
else if (context instanceof DebuggerObjectActionContext ctx) {
|
||||||
return DebuggerRegionsPanel.getSelectedRegions(ctx);
|
return panel.getSelectedRegions(ctx);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,20 +43,6 @@ import ghidra.trace.model.target.TraceObjectInterface;
|
||||||
public abstract class AbstractObjectsTableBasedPanel<U extends TraceObjectInterface>
|
public abstract class AbstractObjectsTableBasedPanel<U extends TraceObjectInterface>
|
||||||
extends ObjectsTablePanel implements ListSelectionListener, CellActivationListener {
|
extends ObjectsTablePanel implements ListSelectionListener, CellActivationListener {
|
||||||
|
|
||||||
public static boolean isContextNonEmpty(DebuggerObjectActionContext ctx) {
|
|
||||||
return ctx != null && !ctx.getObjectValues().isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T extends TraceObjectInterface> Stream<T> getSelected(
|
|
||||||
DebuggerObjectActionContext ctx, Class<T> iface) {
|
|
||||||
return ctx == null ? null
|
|
||||||
: ctx.getObjectValues()
|
|
||||||
.stream()
|
|
||||||
.filter(v -> v.isObject())
|
|
||||||
.map(v -> v.getChild().queryInterface(iface))
|
|
||||||
.filter(r -> r != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final ComponentProvider provider;
|
private final ComponentProvider provider;
|
||||||
private final Class<U> objType;
|
private final Class<U> objType;
|
||||||
|
|
||||||
|
@ -82,6 +68,19 @@ public abstract class AbstractObjectsTableBasedPanel<U extends TraceObjectInterf
|
||||||
addCellActivationListener(this);
|
addCellActivationListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isContextNonEmpty(DebuggerObjectActionContext ctx) {
|
||||||
|
return getSelected(ctx).findAny().isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream<U> getSelected(DebuggerObjectActionContext ctx) {
|
||||||
|
return ctx == null ? null
|
||||||
|
: ctx.getObjectValues()
|
||||||
|
.stream()
|
||||||
|
.filter(v -> v.isObject())
|
||||||
|
.map(v -> v.getChild().queryInterface(objType))
|
||||||
|
.filter(r -> r != null);
|
||||||
|
}
|
||||||
|
|
||||||
public DebuggerObjectActionContext getActionContext() {
|
public DebuggerObjectActionContext getActionContext() {
|
||||||
return myActionContext;
|
return myActionContext;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,17 +46,14 @@ public class DebuggerLegacyModulesPanel extends JPanel {
|
||||||
|
|
||||||
protected static Set<TraceModule> getSelectedModulesFromContext(
|
protected static Set<TraceModule> getSelectedModulesFromContext(
|
||||||
DebuggerModuleActionContext context) {
|
DebuggerModuleActionContext context) {
|
||||||
return context.getSelectedModules()
|
return context.getSelectedModules();
|
||||||
.stream()
|
|
||||||
.map(r -> r.getModule())
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Set<TraceSection> getSelectedSectionsFromContext(
|
protected static Set<TraceSection> getSelectedSectionsFromContext(
|
||||||
DebuggerModuleActionContext context) {
|
DebuggerModuleActionContext context) {
|
||||||
return context.getSelectedModules()
|
return context.getSelectedModules()
|
||||||
.stream()
|
.stream()
|
||||||
.flatMap(r -> r.getModule().getSections().stream())
|
.flatMap(m -> m.getSections().stream())
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,24 +66,6 @@ public class DebuggerLegacyModulesPanel extends JPanel {
|
||||||
return sel;
|
return sel;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static ModuleRow getSelectedModuleRowFromContext(
|
|
||||||
DebuggerModuleActionContext context) {
|
|
||||||
Set<ModuleRow> modules = context.getSelectedModules();
|
|
||||||
if (modules.size() != 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return modules.iterator().next();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static SectionRow getSelectedSectionRowFromContext(
|
|
||||||
DebuggerSectionActionContext context) {
|
|
||||||
Set<SectionRow> sections = context.getSelectedSections();
|
|
||||||
if (sections.size() != 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return sections.iterator().next();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected enum ModuleTableColumns
|
protected enum ModuleTableColumns
|
||||||
implements EnumeratedTableColumn<ModuleTableColumns, ModuleRow> {
|
implements EnumeratedTableColumn<ModuleTableColumns, ModuleRow> {
|
||||||
BASE("Base Address", Address.class, ModuleRow::getBase),
|
BASE("Base Address", Address.class, ModuleRow::getBase),
|
||||||
|
|
|
@ -48,24 +48,21 @@ public class DebuggerLegacySectionsPanel extends JPanel {
|
||||||
|
|
||||||
protected static Set<TraceModule> getSelectedModulesFromContext(
|
protected static Set<TraceModule> getSelectedModulesFromContext(
|
||||||
DebuggerSectionActionContext context) {
|
DebuggerSectionActionContext context) {
|
||||||
return context.getSelectedSections()
|
return context.getSelectedSections(false)
|
||||||
.stream()
|
.stream()
|
||||||
.map(r -> r.getModule())
|
.map(r -> r.getModule())
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Set<TraceSection> getSelectedSectionsFromContext(
|
protected static Set<TraceSection> getSelectedSectionsFromContext(
|
||||||
DebuggerSectionActionContext context) {
|
DebuggerSectionActionContext context, boolean allowExpansion) {
|
||||||
return context.getSelectedSections()
|
return context.getSelectedSections(allowExpansion);
|
||||||
.stream()
|
|
||||||
.map(r -> r.getSection())
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static AddressSetView getSelectedAddressesFromContext(
|
protected static AddressSetView getSelectedAddressesFromContext(
|
||||||
DebuggerSectionActionContext context) {
|
DebuggerSectionActionContext context) {
|
||||||
AddressSet sel = new AddressSet();
|
AddressSet sel = new AddressSet();
|
||||||
for (TraceSection section : getSelectedSectionsFromContext(context)) {
|
for (TraceSection section : getSelectedSectionsFromContext(context, false)) {
|
||||||
sel.add(section.getRange());
|
sel.add(section.getRange());
|
||||||
}
|
}
|
||||||
return sel;
|
return sel;
|
||||||
|
|
|
@ -15,22 +15,41 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.debug.gui.modules;
|
package ghidra.app.plugin.core.debug.gui.modules;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import docking.ComponentProvider;
|
||||||
import docking.DefaultActionContext;
|
import docking.DefaultActionContext;
|
||||||
import docking.widgets.table.GTable;
|
import docking.widgets.table.GTable;
|
||||||
|
import ghidra.trace.model.modules.TraceModule;
|
||||||
|
|
||||||
public class DebuggerModuleActionContext extends DefaultActionContext {
|
public class DebuggerModuleActionContext extends DefaultActionContext {
|
||||||
private final Set<ModuleRow> selectedModules;
|
private final Set<TraceModule> selectedModules;
|
||||||
|
private final boolean forcedSingle;
|
||||||
|
|
||||||
|
private static Set<TraceModule> toModules(Collection<ModuleRow> rows) {
|
||||||
|
return rows.stream().map(ModuleRow::getModule).collect(Collectors.toUnmodifiableSet());
|
||||||
|
}
|
||||||
|
|
||||||
public DebuggerModuleActionContext(DebuggerModulesProvider provider,
|
public DebuggerModuleActionContext(DebuggerModulesProvider provider,
|
||||||
Collection<ModuleRow> selected, GTable table) {
|
Collection<ModuleRow> rows, GTable table) {
|
||||||
super(provider, selected, table);
|
this(provider, toModules(rows), table, false);
|
||||||
this.selectedModules = Set.copyOf(selected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<ModuleRow> getSelectedModules() {
|
public DebuggerModuleActionContext(ComponentProvider provider, Set<TraceModule> selected,
|
||||||
|
Component sourceComponent, boolean forcedSingle) {
|
||||||
|
super(provider, selected, sourceComponent);
|
||||||
|
this.selectedModules = selected;
|
||||||
|
this.forcedSingle = forcedSingle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<TraceModule> getSelectedModules() {
|
||||||
return selectedModules;
|
return selectedModules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isForcedSingle() {
|
||||||
|
return forcedSingle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,12 +306,13 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
||||||
return Set.of();
|
return Set.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Set<TraceSection> getSelectedSections(ActionContext context) {
|
protected static Set<TraceSection> getSelectedSections(ActionContext context,
|
||||||
|
boolean allowExpansion) {
|
||||||
if (context instanceof DebuggerModuleActionContext ctx) {
|
if (context instanceof DebuggerModuleActionContext ctx) {
|
||||||
return DebuggerLegacyModulesPanel.getSelectedSectionsFromContext(ctx);
|
return DebuggerLegacyModulesPanel.getSelectedSectionsFromContext(ctx);
|
||||||
}
|
}
|
||||||
if (context instanceof DebuggerSectionActionContext ctx) {
|
if (context instanceof DebuggerSectionActionContext ctx) {
|
||||||
return DebuggerLegacySectionsPanel.getSelectedSectionsFromContext(ctx);
|
return DebuggerLegacySectionsPanel.getSelectedSectionsFromContext(ctx, allowExpansion);
|
||||||
}
|
}
|
||||||
if (context instanceof DebuggerObjectActionContext ctx) {
|
if (context instanceof DebuggerObjectActionContext ctx) {
|
||||||
return DebuggerModulesPanel.getSelectedSectionsFromContext(ctx);
|
return DebuggerModulesPanel.getSelectedSectionsFromContext(ctx);
|
||||||
|
@ -372,7 +373,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
||||||
public ImportFromFileSystemAction() {
|
public ImportFromFileSystemAction() {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
setPopupMenuData(new MenuData(new String[] { NAME }, GROUP));
|
setPopupMenuData(new MenuData(new String[] { NAME }, GROUP));
|
||||||
addLocalAction(this);
|
tool.addAction(this);
|
||||||
setEnabled(true);
|
setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,7 +468,6 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
||||||
SelectAddressesAction actionSelectAddresses;
|
SelectAddressesAction actionSelectAddresses;
|
||||||
ImportFromFileSystemAction actionImportFromFileSystem;
|
ImportFromFileSystemAction actionImportFromFileSystem;
|
||||||
ToggleDockingAction actionShowSectionsTable;
|
ToggleDockingAction actionShowSectionsTable;
|
||||||
// TODO: Save the state of this toggle? Not really compelled.
|
|
||||||
ToggleDockingAction actionFilterSectionsByModules;
|
ToggleDockingAction actionFilterSectionsByModules;
|
||||||
DockingAction actionSelectCurrent;
|
DockingAction actionSelectCurrent;
|
||||||
|
|
||||||
|
@ -594,30 +594,32 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
||||||
.onAction(this::activatedMapManually)
|
.onAction(this::activatedMapManually)
|
||||||
.buildAndInstallLocal(this);
|
.buildAndInstallLocal(this);
|
||||||
actionMapModules = MapModulesAction.builder(plugin)
|
actionMapModules = MapModulesAction.builder(plugin)
|
||||||
.enabledWhen(this::isContextNonEmpty)
|
.enabledWhen(ctx -> isContextHasModules(ctx) && isContextNotForcedSingle(ctx))
|
||||||
.popupWhen(this::isContextNonEmpty)
|
.popupWhen(ctx -> isContextHasModules(ctx) && isContextNotForcedSingle(ctx))
|
||||||
.onAction(this::activatedMapModules)
|
.onAction(this::activatedMapModules)
|
||||||
.buildAndInstallLocal(this);
|
.buildAndInstall(tool);
|
||||||
actionMapModuleTo = MapModuleToAction.builder(plugin)
|
actionMapModuleTo = MapModuleToAction.builder(plugin)
|
||||||
.enabledWhen(ctx -> currentProgram != null && getSelectedModules(ctx).size() == 1)
|
.enabledWhen(ctx -> currentProgram != null && getSelectedModules(ctx).size() == 1)
|
||||||
.popupWhen(ctx -> currentProgram != null && getSelectedModules(ctx).size() == 1)
|
.popupWhen(ctx -> currentProgram != null && getSelectedModules(ctx).size() == 1)
|
||||||
.onAction(this::activatedMapModuleTo)
|
.onAction(this::activatedMapModuleTo)
|
||||||
.buildAndInstallLocal(this);
|
.buildAndInstall(tool);
|
||||||
actionMapSections = MapSectionsAction.builder(plugin)
|
actionMapSections = MapSectionsAction.builder(plugin)
|
||||||
.enabledWhen(this::isContextNonEmpty)
|
.enabledWhen(ctx -> isContextHasSections(ctx) && isContextNotForcedSingle(ctx))
|
||||||
.popupWhen(this::isContextNonEmpty)
|
.popupWhen(ctx -> isContextHasSections(ctx) && isContextNotForcedSingle(ctx))
|
||||||
.onAction(this::activatedMapSections)
|
.onAction(this::activatedMapSections)
|
||||||
.buildAndInstallLocal(this);
|
.buildAndInstall(tool);
|
||||||
actionMapSectionTo = MapSectionToAction.builder(plugin)
|
actionMapSectionTo = MapSectionToAction.builder(plugin)
|
||||||
.enabledWhen(ctx -> currentProgram != null && getSelectedSections(ctx).size() == 1)
|
.enabledWhen(
|
||||||
.popupWhen(ctx -> currentProgram != null && getSelectedSections(ctx).size() == 1)
|
ctx -> currentProgram != null && getSelectedSections(ctx, false).size() == 1)
|
||||||
|
.popupWhen(
|
||||||
|
ctx -> currentProgram != null && getSelectedSections(ctx, false).size() == 1)
|
||||||
.onAction(this::activatedMapSectionTo)
|
.onAction(this::activatedMapSectionTo)
|
||||||
.buildAndInstallLocal(this);
|
.buildAndInstall(tool);
|
||||||
actionMapSectionsTo = MapSectionsToAction.builder(plugin)
|
actionMapSectionsTo = MapSectionsToAction.builder(plugin)
|
||||||
.enabledWhen(ctx -> currentProgram != null && isContextSectionsOfOneModule(ctx))
|
.enabledWhen(ctx -> currentProgram != null && isContextSectionsOfOneModule(ctx))
|
||||||
.popupWhen(ctx -> currentProgram != null && isContextSectionsOfOneModule(ctx))
|
.popupWhen(ctx -> currentProgram != null && isContextSectionsOfOneModule(ctx))
|
||||||
.onAction(this::activatedMapSectionsTo)
|
.onAction(this::activatedMapSectionsTo)
|
||||||
.buildAndInstallLocal(this);
|
.buildAndInstall(tool);
|
||||||
|
|
||||||
actionAutoMap = AutoMapAction.builder(plugin)
|
actionAutoMap = AutoMapAction.builder(plugin)
|
||||||
.onActionStateChanged(this::changedAutoMapSpec)
|
.onActionStateChanged(this::changedAutoMapSpec)
|
||||||
|
@ -653,12 +655,20 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
||||||
contextChanged();
|
contextChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isContextHasModules(ActionContext context) {
|
||||||
|
return !getSelectedModules(context).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isContextHasSections(ActionContext context) {
|
||||||
|
return !getSelectedSections(context, false).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isContextNonEmpty(ActionContext context) {
|
private boolean isContextNonEmpty(ActionContext context) {
|
||||||
if (context instanceof DebuggerModuleActionContext ctx) {
|
if (context instanceof DebuggerModuleActionContext ctx) {
|
||||||
return !ctx.getSelectedModules().isEmpty();
|
return !ctx.getSelectedModules().isEmpty();
|
||||||
}
|
}
|
||||||
if (context instanceof DebuggerSectionActionContext ctx) {
|
if (context instanceof DebuggerSectionActionContext ctx) {
|
||||||
return !ctx.getSelectedSections().isEmpty();
|
return !ctx.getSelectedSections(false).isEmpty();
|
||||||
}
|
}
|
||||||
if (context instanceof DebuggerObjectActionContext ctx) {
|
if (context instanceof DebuggerObjectActionContext ctx) {
|
||||||
return !ctx.getObjectValues().isEmpty();
|
return !ctx.getObjectValues().isEmpty();
|
||||||
|
@ -666,8 +676,18 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isContextSectionsOfOneModule(ActionContext ignored) {
|
private boolean isContextNotForcedSingle(ActionContext context) {
|
||||||
Set<TraceSection> sel = getSelectedSections(myActionContext);
|
if (context instanceof DebuggerModuleActionContext ctx) {
|
||||||
|
return !ctx.isForcedSingle();
|
||||||
|
}
|
||||||
|
if (context instanceof DebuggerSectionActionContext ctx) {
|
||||||
|
return !ctx.isForcedSingle();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isContextSectionsOfOneModule(ActionContext context) {
|
||||||
|
Set<TraceSection> sel = getSelectedSections(context, false);
|
||||||
if (sel == null || sel.isEmpty()) {
|
if (sel == null || sel.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -713,40 +733,40 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
||||||
tool.showComponentProvider(provider, true);
|
tool.showComponentProvider(provider, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void activatedMapModules(ActionContext ignored) {
|
private void activatedMapModules(ActionContext context) {
|
||||||
Set<TraceModule> sel = getSelectedModules(myActionContext);
|
Set<TraceModule> sel = getSelectedModules(context);
|
||||||
if (sel == null || sel.isEmpty()) {
|
if (sel == null || sel.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mapModules(sel);
|
mapModules(sel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void activatedMapModuleTo(ActionContext ignored) {
|
private void activatedMapModuleTo(ActionContext context) {
|
||||||
Set<TraceModule> sel = getSelectedModules(myActionContext);
|
Set<TraceModule> sel = getSelectedModules(context);
|
||||||
if (sel == null || sel.size() != 1) {
|
if (sel == null || sel.size() != 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mapModuleTo(sel.iterator().next());
|
mapModuleTo(sel.iterator().next());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void activatedMapSections(ActionContext ignored) {
|
private void activatedMapSections(ActionContext context) {
|
||||||
Set<TraceSection> sel = getSelectedSections(myActionContext);
|
Set<TraceSection> sel = getSelectedSections(context, true);
|
||||||
if (sel == null || sel.isEmpty()) {
|
if (sel == null || sel.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mapSections(sel);
|
mapSections(sel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void activatedMapSectionsTo(ActionContext ignored) {
|
private void activatedMapSectionsTo(ActionContext context) {
|
||||||
Set<TraceSection> sel = getSelectedSections(myActionContext);
|
Set<TraceSection> sel = getSelectedSections(context, true);
|
||||||
if (sel == null || sel.isEmpty()) {
|
if (sel == null || sel.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mapSectionsTo(sel);
|
mapSectionsTo(sel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void activatedMapSectionTo(ActionContext ignored) {
|
private void activatedMapSectionTo(ActionContext context) {
|
||||||
Set<TraceSection> sel = getSelectedSections(myActionContext);
|
Set<TraceSection> sel = getSelectedSections(context, false);
|
||||||
if (sel == null || sel.size() != 1) {
|
if (sel == null || sel.size() != 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,32 +15,46 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.debug.gui.modules;
|
package ghidra.app.plugin.core.debug.gui.modules;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import docking.ComponentProvider;
|
||||||
import docking.DefaultActionContext;
|
import docking.DefaultActionContext;
|
||||||
import docking.widgets.table.GTable;
|
import docking.widgets.table.GTable;
|
||||||
|
import ghidra.trace.model.modules.TraceSection;
|
||||||
|
|
||||||
public class DebuggerSectionActionContext extends DefaultActionContext {
|
public class DebuggerSectionActionContext extends DefaultActionContext {
|
||||||
private final Set<SectionRow> selectedSections;
|
private final Set<TraceSection> selectedSections;
|
||||||
//private final Set<ModuleRecord> involvedModules;
|
private final boolean forcedSingle;
|
||||||
|
|
||||||
public DebuggerSectionActionContext(DebuggerModulesProvider provider,
|
private static Set<TraceSection> toSections(Collection<SectionRow> rows) {
|
||||||
Collection<SectionRow> selected, GTable table) {
|
return rows.stream().map(SectionRow::getSection).collect(Collectors.toUnmodifiableSet());
|
||||||
super(provider, selected, table);
|
|
||||||
this.selectedSections = Set.copyOf(selected);
|
|
||||||
/*
|
|
||||||
* this.involvedModules = Collections.unmodifiableSet(
|
|
||||||
* selected.stream().map(SectionRecord::getModule).collect(Collectors.toSet()));
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<SectionRow> getSelectedSections() {
|
public DebuggerSectionActionContext(DebuggerModulesProvider provider,
|
||||||
|
Collection<SectionRow> rows, GTable table) {
|
||||||
|
this(provider, toSections(rows), table, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DebuggerSectionActionContext(ComponentProvider provider,
|
||||||
|
Set<TraceSection> selected, Component sourceComponent, boolean forcedSingle) {
|
||||||
|
super(provider, selected, sourceComponent);
|
||||||
|
this.selectedSections = selected;
|
||||||
|
this.forcedSingle = forcedSingle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<TraceSection> getSelectedSections(boolean allowExpansion) {
|
||||||
|
if (forcedSingle && allowExpansion) {
|
||||||
|
return selectedSections.stream()
|
||||||
|
.flatMap(s -> s.getModule().getSections().stream())
|
||||||
|
.collect(Collectors.toUnmodifiableSet());
|
||||||
|
}
|
||||||
return selectedSections;
|
return selectedSections;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
public boolean isForcedSingle() {
|
||||||
* // TODO: Do I need this? public Set<ModuleRecord> getInvolvedModules() { return
|
return forcedSingle;
|
||||||
* involvedModules; }
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue