diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgManagerImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgManagerImpl.java index 2016dd95cd..17d57b9f41 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgManagerImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgManagerImpl.java @@ -1382,9 +1382,8 @@ public class DbgManagerImpl implements DbgManager { BitmaskSet vf = new BitmaskSet(DebugVerifierFlags.class, vfVal == null ? 0 : vfVal); - execute(new DbgLaunchProcessCommand(this, args, - initDir, env, cf, ef, vf)); - return AsyncUtils.NIL; + return execute(new DbgLaunchProcessCommand(this, args, + initDir, env, cf, ef, vf)).thenApply(__ -> null); } public CompletableFuture openFile(Map args) { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetContinuationOptionImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetContinuationOptionImpl.java index 80b8c49e37..a1f0747698 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetContinuationOptionImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetContinuationOptionImpl.java @@ -82,7 +82,7 @@ public class DbgModelTargetContinuationOptionImpl extends DbgModelTargetObjectIm public void setAttributes() { changeAttributes(List.of(), List.of(), Map.of( // DISPLAY_ATTRIBUTE_NAME, getName() + " : " + optionCont.description, // - VALUE_ATTRIBUTE_NAME, optionCont, // + VALUE_ATTRIBUTE_NAME, optionCont.val, // ENABLED_ATTRIBUTE_NAME, optionCont.equals(DebugFilterContinuationOption.DEBUG_FILTER_GO_HANDLED)), "Refreshed"); diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetExecutionOptionImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetExecutionOptionImpl.java index 014962d10c..95c8963b79 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetExecutionOptionImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetExecutionOptionImpl.java @@ -83,7 +83,7 @@ public class DbgModelTargetExecutionOptionImpl extends DbgModelTargetObjectImpl public void setAttributes() { changeAttributes(List.of(), List.of(), Map.of( // DISPLAY_ATTRIBUTE_NAME, getName() + " : " + optionExc.description, // - VALUE_ATTRIBUTE_NAME, optionExc, // + VALUE_ATTRIBUTE_NAME, optionExc.val, // ENABLED_ATTRIBUTE_NAME, optionExc.equals(DebugFilterExecutionOption.DEBUG_FILTER_BREAK)), "Refreshed"); } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessLaunchConnectorImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessLaunchConnectorImpl.java index 904be42e9b..c63686f001 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessLaunchConnectorImpl.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetProcessLaunchConnectorImpl.java @@ -78,6 +78,7 @@ public class DbgModelTargetProcessLaunchConnectorImpl extends DbgModelTargetObje map.put("cf", cf); map.put("ef", ef); map.put("vf", vf); + // Innocuous comment: up-up-down-down-left-right-left-right-B-A return map; } @@ -91,11 +92,4 @@ public class DbgModelTargetProcessLaunchConnectorImpl extends DbgModelTargetObje return getManager().launch(args); } -// public CompletableFuture launch(List args) { -// return AsyncUtils.sequence(TypeSpec.VOID).then(seq -> { -// getManager().launch(args).handle(seq::nextIgnore); -// }).finish().exceptionally((exc) -> { -// throw new DebuggerUserException("Launch failed for " + args); -// }); -// } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java index e618bb83d5..94c0b95d99 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/DebuggerObjectsProvider.java @@ -59,7 +59,6 @@ import ghidra.dbg.error.DebuggerMemoryAccessException; import ghidra.dbg.target.*; import ghidra.dbg.target.TargetConsole.Channel; import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState; -import ghidra.dbg.target.TargetLauncher.TargetCmdLineLauncher; import ghidra.dbg.target.TargetMethod.ParameterDescription; import ghidra.dbg.target.TargetSteppable.TargetStepKind; import ghidra.dbg.util.DebuggerCallbackReorderer; @@ -1335,38 +1334,32 @@ public class DebuggerObjectsProvider extends ComponentProviderAdapter if (currentProgram == null) { return; } - performAction(context, true, TargetLauncher.class, launcher -> { - // TODO: A generic or pluggable way of deriving the launch arguments - return launcher.launch(Map.of( - TargetCmdLineLauncher.CMDLINE_ARGS_NAME, currentProgram.getExecutablePath())); - }, "Couldn't launch"); + performLaunchAction(context, false); } public void performLaunch(ActionContext context) { - performAction(context, true, TargetLauncher.class, launcher -> { + performLaunchAction(context, true); + } - Map args = launchOffer.getLauncherArgs(launcher, true); - if (args == null) { - // Cancelled - return AsyncUtils.NIL; - } - return launcher.launch(args); - /* - String argsKey = TargetCmdLineLauncher.CMDLINE_ARGS_NAME; - String path = (currentProgram != null) ? currentProgram.getExecutablePath() : null; - launchDialog.setCurrentContext(path); - String cmdlineArgs = launchDialog.getMemorizedArgument(argsKey, String.class); - if (cmdlineArgs == null) { - cmdlineArgs = path; - launchDialog.setMemorizedArgument(argsKey, String.class, - cmdlineArgs); - } - Map args = launchDialog.promptArguments(launcher.getParameters()); - if (args == null) { - return AsyncUtils.NIL; - } - return launcher.launch(args); - */ + private void performLaunchAction(ActionContext context, boolean p) { + performAction(context, true, TargetLauncher.class, launcher -> { + var locals = new Object() { + boolean prompt = p; + }; + return AsyncUtils.loop(TypeSpec.VOID, (loop) -> { + Map args = launchOffer.getLauncherArgs(launcher, locals.prompt); + if (args == null) { + // Cancelled + loop.exit(); + } + else { + launcher.launch(args).thenAccept(loop::exit).exceptionally(ex -> { + loop.repeat(); + return null; + }); + } + locals.prompt = true; + }); }, "Couldn't launch"); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/DebuggerMethodInvocationDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/DebuggerMethodInvocationDialog.java index 660d2c6e86..483eca06b3 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/DebuggerMethodInvocationDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/objects/components/DebuggerMethodInvocationDialog.java @@ -19,9 +19,7 @@ import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.beans.*; -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Collectors; +import java.util.*; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -32,6 +30,7 @@ import org.apache.commons.lang3.tuple.MutablePair; import org.jdom.Element; import docking.DialogComponentProvider; +import ghidra.app.plugin.core.debug.gui.DebuggerResources; import ghidra.app.plugin.core.debug.utils.MiscellaneousUtils; import ghidra.dbg.target.TargetMethod; import ghidra.dbg.target.TargetMethod.ParameterDescription; @@ -92,6 +91,8 @@ public class DebuggerMethodInvocationDialog extends DialogComponentProvider private PairLayout layout; protected JButton invokeButton; + protected JButton resetButton; + protected boolean resetRequested; private final PluginTool tool; private Map> parameters; @@ -105,7 +106,7 @@ public class DebuggerMethodInvocationDialog extends DialogComponentProvider super(title, true, false, true, false); this.tool = tool; - populateComponents(buttonText, buttonIcon); + populateComponents(buttonText, buttonIcon, "Reset", DebuggerResources.ICON_REFRESH); setRememberSize(false); } @@ -126,7 +127,8 @@ public class DebuggerMethodInvocationDialog extends DialogComponentProvider populateOptions(); } - private void populateComponents(String buttonText, Icon buttonIcon) { + private void populateComponents(String buttonText, Icon buttonIcon, + String resetText, Icon resetIcon) { panel = new JPanel(new BorderLayout()); panel.setBorder(new EmptyBorder(10, 10, 10, 10)); @@ -144,19 +146,31 @@ public class DebuggerMethodInvocationDialog extends DialogComponentProvider invokeButton = new JButton(buttonText, buttonIcon); addButton(invokeButton); + resetButton = new JButton(resetText, resetIcon); + addButton(resetButton); addCancelButton(); invokeButton.addActionListener(this::invoke); + resetButton.addActionListener(this::reset); + resetRequested = false; } @Override protected void cancelCallback() { this.arguments = null; + this.resetRequested = false; close(); } private void invoke(ActionEvent evt) { this.arguments = TargetMethod.validateArguments(parameters, collectArguments(), false); + this.resetRequested = false; + close(); + } + + private void reset(ActionEvent evt) { + this.arguments = new LinkedHashMap<>(); + this.resetRequested = true; close(); } @@ -175,7 +189,8 @@ public class DebuggerMethodInvocationDialog extends DialogComponentProvider Msg.warn(this, "No editor for " + type + "? Trying String instead"); editor = PropertyEditorManager.findEditor(String.class); } - editor.setValue(computeMemorizedValue(param)); + Object val = computeMemorizedValue(param); + editor.setValue(val); editor.addPropertyChangeListener(this); pairPanel.add(MiscellaneousUtils.getEditorComponent(editor)); // TODO: How to handle parameter with choices? @@ -184,10 +199,14 @@ public class DebuggerMethodInvocationDialog extends DialogComponentProvider } protected Map collectArguments() { - return paramEditors.keySet() - .stream() - .collect(Collectors.toMap(param -> param.name, - param -> memorized.get(NameTypePair.fromParameter(param)))); + Map map = new LinkedHashMap<>(); + for (ParameterDescription param : paramEditors.keySet()) { + Object val = memorized.get(NameTypePair.fromParameter(param)); + if (val != null) { + map.put(param.name, val); + } + } + return map; } public Map getArguments() { @@ -196,6 +215,9 @@ public class DebuggerMethodInvocationDialog extends DialogComponentProvider public void setMemorizedArgument(String name, Class type, T value) { //name = addContext(name, currentContext); + if (value == null) { + return; + } memorized.put(new NameTypePair(name, type), value); } @@ -239,4 +261,8 @@ public class DebuggerMethodInvocationDialog extends DialogComponentProvider } } + public boolean isResetRequested() { + return resetRequested; + } + } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServicePlugin.java index 62922cf1c3..45451c2cfc 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServicePlugin.java @@ -61,8 +61,15 @@ import ghidra.util.classfinder.ClassSearcher; import ghidra.util.datastruct.CollectionChangeListener; import ghidra.util.datastruct.ListenerSet; -@PluginInfo(shortDescription = "Debugger models manager service", description = "Manage debug sessions, connections, and trace recording", category = PluginCategoryNames.DEBUGGER, packageName = DebuggerPluginPackage.NAME, status = PluginStatus.HIDDEN, servicesRequired = {}, servicesProvided = { - DebuggerModelService.class, }) +@PluginInfo( + shortDescription = "Debugger models manager service", + description = "Manage debug sessions, connections, and trace recording", + category = PluginCategoryNames.DEBUGGER, + packageName = DebuggerPluginPackage.NAME, + status = PluginStatus.HIDDEN, + servicesRequired = {}, + servicesProvided = { + DebuggerModelService.class, }) public class DebuggerModelServicePlugin extends Plugin implements DebuggerModelServiceInternal, ApplicationLevelOnlyPlugin { @@ -239,7 +246,10 @@ public class DebuggerModelServicePlugin extends Plugin } model.addModelListener(forRemovalAndFocusListener); TargetObject root = model.getModelRoot(); - if (!root.isValid()) { + // root == null, probably means we're between model construction + // and root construction, but the model was not closed, so no need + // to invalidate + if (root != null && !root.isValid()) { forRemovalAndFocusListener.invalidated(root, root, "Invalidated before or during add to service"); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServiceProxyPlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServiceProxyPlugin.java index 8bf3dd7256..d0e21222be 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServiceProxyPlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServiceProxyPlugin.java @@ -39,6 +39,7 @@ import ghidra.app.plugin.core.debug.gui.DebuggerResources.DebugProgramAction; import ghidra.app.plugin.core.debug.gui.DebuggerResources.DisconnectAllAction; import ghidra.app.plugin.core.debug.mapping.DebuggerTargetTraceMapper; import ghidra.app.plugin.core.debug.service.model.launch.DebuggerProgramLaunchOffer; +import ghidra.app.plugin.core.debug.service.model.launch.DebuggerProgramLaunchOffer.PromptMode; import ghidra.app.plugin.core.debug.utils.BackgroundUtils; import ghidra.app.services.*; import ghidra.async.AsyncUtils; @@ -88,7 +89,7 @@ public class DebuggerModelServiceProxyPlugin extends Plugin new DebuggerProgramLaunchOffer() { @Override public CompletableFuture launchProgram(TaskMonitor monitor, - boolean prompt, LaunchConfigurator configurator) { + PromptMode prompt, LaunchConfigurator configurator) { throw new AssertionError("Who clicked me?"); } @@ -330,7 +331,8 @@ public class DebuggerModelServiceProxyPlugin extends Plugin return offers.sorted(Comparator.comparingInt(o -> -mrl.indexOf(o.getConfigName()))); } - private void debugProgram(DebuggerProgramLaunchOffer offer, Program program, boolean prompt) { + private void debugProgram(DebuggerProgramLaunchOffer offer, Program program, + PromptMode prompt) { BackgroundUtils.asyncModal(tool, offer.getButtonTitle(), true, true, m -> { List recent = new ArrayList<>(readMostRecentLaunches(program)); recent.remove(offer.getConfigName()); @@ -360,7 +362,7 @@ public class DebuggerModelServiceProxyPlugin extends Plugin if (offer == null || program == null) { return; } - debugProgram(offer, program, false); + debugProgram(offer, program, PromptMode.ON_ERROR); } private void debugProgramStateActivated(ActionState offer, @@ -375,7 +377,7 @@ public class DebuggerModelServiceProxyPlugin extends Plugin if (program == null) { return; } - debugProgram(offer, program, true); + debugProgram(offer, program, PromptMode.ALWAYS); } private void updateActionDebugProgram() { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/AbstractDebuggerProgramLaunchOffer.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/AbstractDebuggerProgramLaunchOffer.java index 0e72a46596..86ab4a6fd5 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/AbstractDebuggerProgramLaunchOffer.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/AbstractDebuggerProgramLaunchOffer.java @@ -15,8 +15,11 @@ */ package ghidra.app.plugin.core.debug.service.model.launch; +import static ghidra.async.AsyncUtils.*; + import java.io.IOException; import java.util.*; +import java.util.Map.Entry; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -267,7 +270,12 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg if (program == null) { return Map.of(); } - return Map.of(TargetCmdLineLauncher.CMDLINE_ARGS_NAME, program.getExecutablePath()); + Map map = new LinkedHashMap(); + for (Entry> entry : params.entrySet()) { + map.put(entry.getKey(), entry.getValue().defaultValue); + } + map.put(TargetCmdLineLauncher.CMDLINE_ARGS_NAME, program.getExecutablePath()); + return map; } /** @@ -282,20 +290,30 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg DebuggerMethodInvocationDialog dialog = new DebuggerMethodInvocationDialog(tool, getButtonTitle(), "Launch", getIcon()); // NB. Do not invoke read/writeConfigState - Map args = configurator.configureLauncher(launcher, - loadLastLauncherArgs(launcher, true), RelPrompt.BEFORE); - for (ParameterDescription param : params.values()) { - Object val = args.get(param.name); - if (val != null) { - dialog.setMemorizedArgument(param.name, param.type.asSubclass(Object.class), val); + Map args; + boolean reset = false; + do { + args = configurator.configureLauncher(launcher, + loadLastLauncherArgs(launcher, true), RelPrompt.BEFORE); + for (ParameterDescription param : params.values()) { + Object val = args.get(param.name); + if (val != null) { + dialog.setMemorizedArgument(param.name, param.type.asSubclass(Object.class), + val); + } } + args = dialog.promptArguments(params); + if (args == null) { + // Cancelled + return null; + } + reset = dialog.isResetRequested(); + if (reset) { + args = generateDefaultLauncherArgs(params); + } + saveLauncherArgs(args, params); } - args = dialog.promptArguments(params); - if (args == null) { - // Cancelled - return null; - } - saveLauncherArgs(args, params); + while (reset); return args; } @@ -328,12 +346,15 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg try { Element element = XmlUtilities.fromString(property); SaveState state = new SaveState(element); + List names = List.of(state.getNames()); Map args = new LinkedHashMap<>(); for (ParameterDescription param : params.values()) { - Object configState = - ConfigStateField.getState(state, param.type, param.name); - if (configState != null) { - args.put(param.name, configState); + if (names.contains(param.name)) { + Object configState = + ConfigStateField.getState(state, param.type, param.name); + if (configState != null) { + args.put(param.name, configState); + } } } if (!args.isEmpty()) { @@ -347,7 +368,7 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg e); } Msg.error(this, - "Saved launcher args are corrup, or launcher parameters changed. Defaulting.", + "Saved launcher args are corrupt, or launcher parameters changed. Defaulting.", e); } } @@ -463,12 +484,14 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg // Eww. protected CompletableFuture launch(TargetLauncher launcher, - boolean prompt, LaunchConfigurator configurator) { + boolean prompt, LaunchConfigurator configurator, TaskMonitor monitor) { Map args = getLauncherArgs(launcher, prompt, configurator); if (args == null) { throw new CancellationException(); } - return launcher.launch(args); + return AsyncTimer.DEFAULT_TIMER.mark() + .timeOut( + launcher.launch(args), getTimeoutMillis(), () -> onTimedOutLaunch(monitor)); } protected void checkCancelled(TaskMonitor monitor) { @@ -560,7 +583,7 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg } @Override - public CompletableFuture launchProgram(TaskMonitor monitor, boolean prompt, + public CompletableFuture launchProgram(TaskMonitor monitor, PromptMode mode, LaunchConfigurator configurator) { DebuggerModelService service = tool.getService(DebuggerModelService.class); DebuggerStaticMappingService mappingService = @@ -573,12 +596,13 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg TargetObject target; TraceRecorder recorder; Throwable exception; + boolean prompt = mode == PromptMode.ALWAYS; LaunchResult getResult() { return new LaunchResult(model, target, recorder, exception); } }; - return connect(service, prompt, configurator).thenCompose(m -> { + return connect(service, locals.prompt, configurator).thenCompose(m -> { checkCancelled(monitor); locals.model = m; monitor.incrementProgress(1); @@ -591,12 +615,14 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg monitor.incrementProgress(1); monitor.setMessage("Launching"); locals.futureTarget = listenForTarget(l.getModel()); - if (prompt) { - return launch(l, true, configurator); - } - return AsyncTimer.DEFAULT_TIMER.mark() - .timeOut(launch(l, false, configurator), getTimeoutMillis(), - () -> onTimedOutLaunch(monitor)); + return loop(TypeSpec.VOID, (loop) -> { + launch(l, locals.prompt, configurator, monitor).thenAccept(loop::exit) + .exceptionally(ex -> { + loop.repeat(); + return null; + }); + locals.prompt = mode != PromptMode.NEVER; + }); }).thenCompose(__ -> { checkCancelled(monitor); monitor.incrementProgress(1); @@ -636,4 +662,5 @@ public abstract class AbstractDebuggerProgramLaunchOffer implements DebuggerProg return locals.getResult(); }); } + } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/DebuggerProgramLaunchOffer.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/DebuggerProgramLaunchOffer.java index e979139796..fa408d9027 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/DebuggerProgramLaunchOffer.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/launch/DebuggerProgramLaunchOffer.java @@ -82,6 +82,21 @@ public interface DebuggerProgramLaunchOffer { AFTER; } + public enum PromptMode { + /** + * The user is always prompted for parameters. + */ + ALWAYS, + /** + * The user is never prompted for parameters. + */ + NEVER, + /** + * The user is prompted after an error. + */ + ON_ERROR; + } + /** * Callbacks for custom configuration when launching a program */ @@ -118,7 +133,7 @@ public interface DebuggerProgramLaunchOffer { * @param configurator the configuration callbacks * @return a future which completes when the program is launched */ - CompletableFuture launchProgram(TaskMonitor monitor, boolean prompt, + CompletableFuture launchProgram(TaskMonitor monitor, PromptMode prompt, LaunchConfigurator configurator); /** @@ -128,7 +143,7 @@ public interface DebuggerProgramLaunchOffer { * @param prompt if the user should be prompted to confirm launch parameters * @return a future which completes when the program is launched */ - default CompletableFuture launchProgram(TaskMonitor monitor, boolean prompt) { + default CompletableFuture launchProgram(TaskMonitor monitor, PromptMode prompt) { return launchProgram(monitor, prompt, LaunchConfigurator.NOP); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/debug/flatapi/FlatDebuggerAPI.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/debug/flatapi/FlatDebuggerAPI.java index c6ffd181c6..2a3ba7bb04 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/debug/flatapi/FlatDebuggerAPI.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/debug/flatapi/FlatDebuggerAPI.java @@ -1491,7 +1491,7 @@ public interface FlatDebuggerAPI { default LaunchResult launch(DebuggerProgramLaunchOffer offer, String commandLine, TaskMonitor monitor) { try { - return waitOn(offer.launchProgram(monitor, false, new LaunchConfigurator() { + return waitOn(offer.launchProgram(monitor, PromptMode.NEVER, new LaunchConfigurator() { @Override public Map configureLauncher(TargetLauncher launcher, Map arguments, RelPrompt relPrompt) { @@ -1514,7 +1514,7 @@ public interface FlatDebuggerAPI { */ default LaunchResult launch(DebuggerProgramLaunchOffer offer, TaskMonitor monitor) { try { - return waitOn(offer.launchProgram(monitor, false)); + return waitOn(offer.launchProgram(monitor, PromptMode.NEVER)); } catch (InterruptedException | ExecutionException | TimeoutException e) { // TODO: This is not ideal, since it's likely partially completed diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/TestDebuggerProgramLaunchOpinion.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/TestDebuggerProgramLaunchOpinion.java index 9be7cd3a34..0f20ba8a8a 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/TestDebuggerProgramLaunchOpinion.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/TestDebuggerProgramLaunchOpinion.java @@ -15,7 +15,7 @@ */ package ghidra.app.plugin.core.debug.service.model; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import java.util.Collection; import java.util.List; @@ -35,7 +35,7 @@ public class TestDebuggerProgramLaunchOpinion implements DebuggerProgramLaunchOp public static class TestDebuggerProgramLaunchOffer implements DebuggerProgramLaunchOffer { @Override - public CompletableFuture launchProgram(TaskMonitor monitor, boolean prompt, + public CompletableFuture launchProgram(TaskMonitor monitor, PromptMode prompt, LaunchConfigurator configurator) { return CompletableFuture .completedFuture(LaunchResult.totalFailure(new AssertionError())); diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetLauncher.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetLauncher.java index a6219e422f..262811ad0a 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetLauncher.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetLauncher.java @@ -139,4 +139,5 @@ public interface TargetLauncher extends TargetObject { * @return a future which completes when the command is completed */ public CompletableFuture launch(Map args); + }