diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgManager.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgManager.java index 743ee3ef06..7567a1db49 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgManager.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgManager.java @@ -372,8 +372,6 @@ public interface DbgManager extends AutoCloseable, DbgBreakpointInsertions { */ CompletableFuture deleteBreakpoints(long... numbers); - CompletableFuture launch(List args); - CompletableFuture launch(Map args); /********** NEEDED FOR TESTING ************/ diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgLaunchProcessCommand.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgLaunchProcessCommand.java index 66289d9687..e14cf08e77 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgLaunchProcessCommand.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/cmd/DbgLaunchProcessCommand.java @@ -15,14 +15,17 @@ */ package agent.dbgeng.manager.cmd; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; - -import agent.dbgeng.dbgeng.*; -import agent.dbgeng.dbgeng.DebugClient.*; -import agent.dbgeng.manager.*; +import agent.dbgeng.dbgeng.DebugClient; +import agent.dbgeng.dbgeng.DebugClient.DebugCreateFlags; +import agent.dbgeng.dbgeng.DebugClient.DebugEngCreateFlags; +import agent.dbgeng.dbgeng.DebugClient.DebugVerifierFlags; +import agent.dbgeng.dbgeng.DebugProcessInfo; +import agent.dbgeng.dbgeng.DebugSystemObjects; +import agent.dbgeng.dbgeng.DebugThreadId; +import agent.dbgeng.dbgeng.DebugThreadInfo; +import agent.dbgeng.manager.DbgEvent; +import agent.dbgeng.manager.DbgProcess; +import agent.dbgeng.manager.DbgThread; import agent.dbgeng.manager.evt.AbstractDbgCompletedCommandEvent; import agent.dbgeng.manager.evt.DbgProcessCreatedEvent; import agent.dbgeng.manager.impl.DbgManagerImpl; @@ -35,14 +38,14 @@ public class DbgLaunchProcessCommand extends AbstractDbgCommand { private DbgProcessCreatedEvent created = null; private boolean completed = false; - private List args; + private String args; private String initialDirectory; private String environment; private BitmaskSet createFlags; private BitmaskSet engCreateFlags; private BitmaskSet verifierFlags; - public DbgLaunchProcessCommand(DbgManagerImpl manager, List args, + public DbgLaunchProcessCommand(DbgManagerImpl manager, String args, String initialDirectory, String environment, BitmaskSet createFlags, BitmaskSet engCreateFlags, @@ -81,11 +84,6 @@ public class DbgLaunchProcessCommand extends AbstractDbgCommand { DebugClient dbgeng = manager.getClient(); //DebugControl control = dbgeng.getControl(); - List newArgs = new ArrayList<>(); - for (String arg : args) { - newArgs.add(fixPath(arg)); - } - initialDirectory = fixPath(initialDirectory); environment = fixPath(environment); // NB: The intent here is to enable multi-line input via a single dialog field @@ -93,7 +91,7 @@ public class DbgLaunchProcessCommand extends AbstractDbgCommand { environment = environment.replace("\\0", "\0"); } - dbgeng.createProcess(dbgeng.getLocalServer(), StringUtils.join(newArgs, " "), + dbgeng.createProcess(dbgeng.getLocalServer(), args, initialDirectory, environment, createFlags, engCreateFlags, verifierFlags); manager.waitForEventEx(); } 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 57c21dff3a..a0cf23b1a8 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 @@ -148,8 +148,6 @@ import ghidra.async.AsyncReference; import ghidra.async.AsyncUtils; import ghidra.async.TypeSpec; import ghidra.comm.util.BitmaskSet; -import ghidra.dbg.target.TargetLauncher.CmdLineParser; -import ghidra.dbg.target.TargetLauncher.TargetCmdLineLauncher; import ghidra.dbg.target.TargetObject; import ghidra.dbg.util.HandlerMap; import ghidra.lifecycle.Internal; @@ -1414,21 +1412,9 @@ public class DbgManagerImpl implements DbgManager { return AsyncUtils.NIL; } - @Override - public CompletableFuture launch(List args) { - BitmaskSet cf = BitmaskSet.of(DebugCreateFlags.DEBUG_PROCESS); - BitmaskSet ef = - BitmaskSet.of(DebugEngCreateFlags.DEBUG_ECREATE_PROCESS_DEFAULT); - BitmaskSet vf = - BitmaskSet.of(DebugVerifierFlags.DEBUG_VERIFIER_DEFAULT); - return execute(new DbgLaunchProcessCommand(this, args, - null, null, cf, ef, vf)); - } - @Override public CompletableFuture launch(Map map) { - List args = - CmdLineParser.tokenize(TargetCmdLineLauncher.PARAMETER_CMDLINE_ARGS.get(map)); + String args = (String) map.get("args"); String initDir = (String) map.get("dir"); String env = (String) map.get("env"); diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetLauncher.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetLauncher.java index a8718feb2b..0487fb2698 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetLauncher.java +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetLauncher.java @@ -15,12 +15,12 @@ */ package agent.dbgeng.model.iface1; -import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import agent.dbgeng.model.iface2.DbgModelTargetObject; import ghidra.dbg.error.DebuggerUserException; -import ghidra.dbg.target.TargetLauncher.TargetCmdLineLauncher; +import ghidra.dbg.target.TargetCmdLineLauncherEx; /** * An interface which indicates this object is capable of launching targets. @@ -30,10 +30,10 @@ import ghidra.dbg.target.TargetLauncher.TargetCmdLineLauncher; * * @param type for this */ -public interface DbgModelTargetLauncher extends DbgModelTargetObject, TargetCmdLineLauncher { +public interface DbgModelTargetLauncher extends DbgModelTargetObject, TargetCmdLineLauncherEx { @Override - public default CompletableFuture launch(List args) { + public default CompletableFuture launch(Map args) { return getModel().gateFuture(getManager().launch(args)).exceptionally((exc) -> { throw new DebuggerUserException("Launch failed for " + args); }).thenApply(__ -> null); diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetCmdLineLauncherEx.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetCmdLineLauncherEx.java new file mode 100644 index 0000000000..38ce9a060f --- /dev/null +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/TargetCmdLineLauncherEx.java @@ -0,0 +1,79 @@ +/* ### + * IP: GHIDRA + * + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.dbg.target; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import ghidra.dbg.target.TargetMethod.ParameterDescription; +import ghidra.dbg.target.TargetMethod.TargetParameterMap; + +public interface TargetCmdLineLauncherEx extends TargetLauncher { + String CMDLINE_ARGS_NAME = "args"; + + /** + * The {@code args} parameter + */ + ParameterDescription PARAMETER_CMDLINE_ARGS = ParameterDescription.create( + String.class, + CMDLINE_ARGS_NAME, true, "", "Command Line", "space-separated command-line arguments"); + + /** + * A map of parameters suitable for invoking {@link #launch(List)} + */ + TargetParameterMap PARAMETERS = TargetMethod.makeParameters(PARAMETER_CMDLINE_ARGS); + + /** + * Check if the given image path contains spaces, and surround it in double quotes + * ({@code "}) if necessary. + * + *

+ * Without the quotes the launcher will likely confuse the spaces for separating arguments. + * When constructing the command-line to launch a program, this method must be used, even if + * the image is the only "argument." + * + * @param imagePath the path to the image on the target platform. + * @return the path, possibly surrounded in quotes. + */ + static String quoteImagePathIfSpaces(String imagePath) { + if (imagePath.contains(" ")) { + return '"' + imagePath + '"'; + } + return imagePath; + } + + @Override + default public TargetParameterMap getParameters() { + return PARAMETERS; + } + + /** + * Launch a target using the given arguments + * + *

+ * This is mostly applicable to user-space contexts, in which case, this usually means to + * launch a new process with the given arguments, where the first argument is the path to + * the executable image on the target host's file system. + * + * @param args the arguments + * @return a future which completes when the command has been processed + */ + @Override + public default CompletableFuture launch(Map args) { + return launch(args); + } +}