mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
GP-5425: Encapsulate object-discovery policy, sort REFRESH, incorporate schema into specificity
This commit is contained in:
parent
136a944796
commit
a94b0493c9
12 changed files with 205 additions and 206 deletions
|
@ -46,6 +46,7 @@ import ghidra.debug.api.control.ControlMode;
|
|||
import ghidra.debug.api.target.ActionName;
|
||||
import ghidra.debug.api.target.Target;
|
||||
import ghidra.debug.api.target.Target.ActionEntry;
|
||||
import ghidra.debug.api.target.Target.ObjectArgumentPolicy;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.model.DomainObjectEvent;
|
||||
import ghidra.framework.plugintool.*;
|
||||
|
@ -327,7 +328,9 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||
return stub;
|
||||
}
|
||||
List<DockingActionIf> result = new ArrayList<>();
|
||||
for (ActionEntry entry : target.collectActions(ActionName.BREAK_EXT, context)
|
||||
for (ActionEntry entry : target
|
||||
.collectActions(ActionName.BREAK_EXT, context,
|
||||
ObjectArgumentPolicy.CURRENT_AND_RELATED)
|
||||
.values()) {
|
||||
result.add(new GenericSetBreakpointAction(entry));
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ import ghidra.debug.api.model.DebuggerObjectActionContext;
|
|||
import ghidra.debug.api.target.ActionName;
|
||||
import ghidra.debug.api.target.Target;
|
||||
import ghidra.debug.api.target.Target.ActionEntry;
|
||||
import ghidra.debug.api.target.Target.ObjectArgumentPolicy;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
|
||||
|
@ -282,7 +283,10 @@ public class DebuggerControlPlugin extends AbstractDebuggerPlugin
|
|||
}
|
||||
|
||||
protected void addTargetStepExtActions(Target target) {
|
||||
for (ActionEntry entry : target.collectActions(ActionName.STEP_EXT, context).values()) {
|
||||
for (ActionEntry entry : target
|
||||
.collectActions(ActionName.STEP_EXT, context,
|
||||
ObjectArgumentPolicy.CURRENT_AND_RELATED)
|
||||
.values()) {
|
||||
if (entry.requiresPrompt()) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import ghidra.debug.api.control.ControlMode;
|
|||
import ghidra.debug.api.model.DebuggerObjectActionContext;
|
||||
import ghidra.debug.api.target.Target;
|
||||
import ghidra.debug.api.target.Target.ActionEntry;
|
||||
import ghidra.debug.api.target.Target.ObjectArgumentPolicy;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.plugintool.*;
|
||||
import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
|
||||
|
@ -119,7 +120,9 @@ public class DebuggerMethodActionsPlugin extends Plugin implements PopupActionPr
|
|||
}
|
||||
|
||||
List<DockingActionIf> result = new ArrayList<>();
|
||||
for (ActionEntry entry : target.collectActions(null, context).values()) {
|
||||
for (ActionEntry entry : target
|
||||
.collectActions(null, context, ObjectArgumentPolicy.CONTEXT_ONLY)
|
||||
.values()) {
|
||||
//if (entry.requiresPrompt() || entry.builtIn()) {
|
||||
if (!entry.isEnabled() || !entry.getShow().isShowing(context)) {
|
||||
continue;
|
||||
|
|
|
@ -24,6 +24,7 @@ import ghidra.app.services.DebuggerTraceManagerService;
|
|||
import ghidra.debug.api.target.ActionName;
|
||||
import ghidra.debug.api.target.Target;
|
||||
import ghidra.debug.api.target.Target.ActionEntry;
|
||||
import ghidra.debug.api.target.Target.ObjectArgumentPolicy;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
|
||||
class TargetDockingAction extends DockingAction {
|
||||
|
@ -51,7 +52,7 @@ class TargetDockingAction extends DockingAction {
|
|||
if (target == null) {
|
||||
return null;
|
||||
}
|
||||
return target.collectActions(action, context)
|
||||
return target.collectActions(action, context, ObjectArgumentPolicy.CURRENT_AND_RELATED)
|
||||
.values()
|
||||
.stream()
|
||||
.filter(e -> !e.requiresPrompt())
|
||||
|
|
|
@ -55,6 +55,7 @@ import ghidra.debug.api.model.DebuggerObjectActionContext;
|
|||
import ghidra.debug.api.target.ActionName;
|
||||
import ghidra.debug.api.target.Target;
|
||||
import ghidra.debug.api.target.Target.ActionEntry;
|
||||
import ghidra.debug.api.target.Target.ObjectArgumentPolicy;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.*;
|
||||
|
@ -767,30 +768,34 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable
|
|||
if (target == null) {
|
||||
return;
|
||||
}
|
||||
Map<String, ActionEntry> actions = target.collectActions(ActionName.REFRESH,
|
||||
ActionEntry ent = target.collectActions(ActionName.REFRESH,
|
||||
new DebuggerObjectActionContext(List.of(value), this, objectsTreePanel,
|
||||
current.getSnap()));
|
||||
for (ActionEntry ent : actions.values()) {
|
||||
if (ent.requiresPrompt()) {
|
||||
continue;
|
||||
}
|
||||
if (path.getLastPathComponent() instanceof AbstractNode node) {
|
||||
/**
|
||||
* This pending node does not duplicate what the lazy node already does. For all
|
||||
* it's concerned, once it has loaded the entries from the database, it is done.
|
||||
* This task asks the target to update that database, so it needs its own indicator.
|
||||
*/
|
||||
PendingNode pending = new PendingNode();
|
||||
node.addNode(0, pending);
|
||||
CompletableFuture<Void> future =
|
||||
TargetActionTask.runAction(plugin.getTool(), ent.display(), ent);
|
||||
future.handle((__, ex) -> {
|
||||
node.removeNode(pending);
|
||||
return null;
|
||||
});
|
||||
return;
|
||||
}
|
||||
current.getSnap()),
|
||||
ObjectArgumentPolicy.CONTEXT_ONLY)
|
||||
.values()
|
||||
.stream()
|
||||
.filter(e -> !e.requiresPrompt())
|
||||
.sorted(Comparator.comparing(e -> -e.specificity()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (ent == null) {
|
||||
// Fail silently. It's common for nodes to not have a refresh action.
|
||||
return;
|
||||
}
|
||||
AbstractNode node = (AbstractNode) path.getLastPathComponent();
|
||||
/**
|
||||
* This pending node does not duplicate what the lazy node already does. For all it's
|
||||
* concerned, once it has loaded the entries from the database, it is done. This task asks
|
||||
* the target to update that database, so it needs its own indicator.
|
||||
*/
|
||||
PendingNode pending = new PendingNode();
|
||||
node.addNode(0, pending);
|
||||
CompletableFuture<Void> future =
|
||||
TargetActionTask.runAction(plugin.getTool(), ent.display(), ent);
|
||||
future.handle((__, ex) -> {
|
||||
node.removeNode(pending);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -28,13 +28,15 @@ import ghidra.debug.api.model.DebuggerSingleObjectPathActionContext;
|
|||
import ghidra.debug.api.target.ActionName;
|
||||
import ghidra.debug.api.target.Target;
|
||||
import ghidra.debug.api.target.Target.ActionEntry;
|
||||
import ghidra.debug.api.target.Target.ObjectArgumentPolicy;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.trace.model.target.*;
|
||||
import ghidra.trace.model.target.TraceObject;
|
||||
import ghidra.trace.model.target.TraceObjectValue;
|
||||
import ghidra.trace.model.target.iface.*;
|
||||
import ghidra.trace.model.target.path.KeyPath;
|
||||
import ghidra.util.Msg;
|
||||
|
@ -53,7 +55,8 @@ public interface ObjectDefaultActionsMixin {
|
|||
}
|
||||
Target target = getCurrent().getTarget();
|
||||
Map<String, ActionEntry> actions = target.collectActions(ActionName.TOGGLE,
|
||||
new DebuggerSingleObjectPathActionContext(object.getCanonicalPath()));
|
||||
new DebuggerSingleObjectPathActionContext(object.getCanonicalPath()),
|
||||
ObjectArgumentPolicy.CONTEXT_ONLY);
|
||||
ActionEntry action = actions.values()
|
||||
.stream()
|
||||
.filter(e -> !e.requiresPrompt())
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -19,17 +19,13 @@ import java.util.*;
|
|||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import docking.ActionContext;
|
||||
import ghidra.app.context.NavigatableActionContext;
|
||||
import ghidra.app.context.ProgramLocationActionContext;
|
||||
import ghidra.app.nav.Navigatable;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.services.DebuggerStaticMappingService.MappedAddressRange;
|
||||
import ghidra.async.AsyncUtils;
|
||||
import ghidra.debug.api.target.ActionName;
|
||||
import ghidra.debug.api.target.Target;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
|
@ -46,7 +42,6 @@ import ghidra.trace.model.guest.TracePlatform;
|
|||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.TraceRegisterUtils;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.Swing;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -186,81 +181,6 @@ public abstract class AbstractTarget implements Target {
|
|||
return null;
|
||||
}
|
||||
|
||||
protected abstract Map<String, ActionEntry> collectAddressActions(
|
||||
ProgramLocationActionContext context);
|
||||
|
||||
protected Map<String, ActionEntry> collectAllActions(ActionContext context) {
|
||||
return Stream.of(
|
||||
collectResumeActions(context),
|
||||
collectInterruptActions(context),
|
||||
collectKillActions(context),
|
||||
collectStepIntoActions(context),
|
||||
collectStepOverActions(context),
|
||||
collectStepOutActions(context),
|
||||
collectStepExtActions(context),
|
||||
collectRefreshActions(context),
|
||||
collectToggleActions(context))
|
||||
.flatMap(m -> m.entrySet().stream())
|
||||
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
|
||||
}
|
||||
|
||||
protected abstract Map<String, ActionEntry> collectResumeActions(ActionContext context);
|
||||
|
||||
protected abstract Map<String, ActionEntry> collectInterruptActions(ActionContext context);
|
||||
|
||||
protected abstract Map<String, ActionEntry> collectKillActions(ActionContext context);
|
||||
|
||||
protected abstract Map<String, ActionEntry> collectStepIntoActions(ActionContext context);
|
||||
|
||||
protected abstract Map<String, ActionEntry> collectStepOverActions(ActionContext context);
|
||||
|
||||
protected abstract Map<String, ActionEntry> collectStepOutActions(ActionContext context);
|
||||
|
||||
protected abstract Map<String, ActionEntry> collectStepExtActions(ActionContext context);
|
||||
|
||||
protected abstract Map<String, ActionEntry> collectRefreshActions(ActionContext context);
|
||||
|
||||
protected abstract Map<String, ActionEntry> collectToggleActions(ActionContext context);
|
||||
|
||||
@Override
|
||||
public Map<String, ActionEntry> collectActions(ActionName name, ActionContext context) {
|
||||
if (name == null) {
|
||||
if (context instanceof ProgramLocationActionContext ctx) {
|
||||
return collectAddressActions(ctx);
|
||||
}
|
||||
return collectAllActions(context);
|
||||
}
|
||||
else if (ActionName.RESUME.equals(name)) {
|
||||
return collectResumeActions(context);
|
||||
}
|
||||
else if (ActionName.INTERRUPT.equals(name)) {
|
||||
return collectInterruptActions(context);
|
||||
}
|
||||
else if (ActionName.KILL.equals(name)) {
|
||||
return collectKillActions(context);
|
||||
}
|
||||
else if (ActionName.STEP_INTO.equals(name)) {
|
||||
return collectStepIntoActions(context);
|
||||
}
|
||||
else if (ActionName.STEP_OVER.equals(name)) {
|
||||
return collectStepOverActions(context);
|
||||
}
|
||||
else if (ActionName.STEP_OUT.equals(name)) {
|
||||
return collectStepOutActions(context);
|
||||
}
|
||||
else if (ActionName.STEP_EXT.equals(name)) {
|
||||
return collectStepExtActions(context);
|
||||
}
|
||||
else if (ActionName.REFRESH.equals(name)) {
|
||||
return collectRefreshActions(context);
|
||||
}
|
||||
else if (ActionName.TOGGLE.equals(name)) {
|
||||
return collectToggleActions(context);
|
||||
}
|
||||
Msg.warn(this, "Unrecognized action name: " + name);
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
protected static <T> T doSync(String name, Supplier<CompletableFuture<T>> supplier)
|
||||
throws InterruptedException, ExecutionException {
|
||||
if (Swing.isSwingThread()) {
|
||||
|
|
|
@ -27,8 +27,8 @@ import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
|||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
import ghidra.trace.model.TraceExecutionState;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.TraceExecutionState;
|
||||
import ghidra.trace.model.breakpoint.TraceBreakpoint;
|
||||
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
|
||||
import ghidra.trace.model.guest.TracePlatform;
|
||||
|
@ -71,7 +71,8 @@ public class MockTarget implements Target {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ActionEntry> collectActions(ActionName name, ActionContext context) {
|
||||
public Map<String, ActionEntry> collectActions(ActionName name, ActionContext context,
|
||||
ObjectArgumentPolicy policy) {
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue