diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugInputCallbacks.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugInputCallbacks.java
index 6ab40c88a7..d6f1507a0f 100644
--- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugInputCallbacks.java
+++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/dbgeng/DebugInputCallbacks.java
@@ -15,17 +15,15 @@
*/
package agent.dbgeng.dbgeng;
-import java.util.concurrent.CompletableFuture;
-
/**
* The interface for receiving input callbacks via {@code IDebugInputCallbacks} or a newer variant.
*
- *
* Note: The wrapper implementation will select the appropriate native interface version.
*/
@FunctionalInterface
public interface DebugInputCallbacks {
- CompletableFuture startInput();
+
+ public void startInput(long bufferSize);
default void endInput() {
// Optional implementation
diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/io/WrapCallbackIDebugInputCallbacks.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/io/WrapCallbackIDebugInputCallbacks.java
index b5bead36fe..6a8aa21230 100644
--- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/io/WrapCallbackIDebugInputCallbacks.java
+++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/impl/dbgeng/io/WrapCallbackIDebugInputCallbacks.java
@@ -15,10 +15,6 @@
*/
package agent.dbgeng.impl.dbgeng.io;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Guid.REFIID;
import com.sun.jna.platform.win32.WinDef.ULONG;
@@ -30,15 +26,12 @@ import com.sun.jna.ptr.PointerByReference;
import agent.dbgeng.dbgeng.DebugInputCallbacks;
import agent.dbgeng.impl.dbgeng.client.DebugClientImpl1;
import agent.dbgeng.jna.dbgeng.io.*;
-import ghidra.util.exception.CancelledException;
public class WrapCallbackIDebugInputCallbacks implements CallbackIDebugInputCallbacks {
private final DebugClientImpl1 client;
private final DebugInputCallbacks cb;
private ListenerIDebugInputCallbacks listener;
- private final Set> futures = new HashSet<>(); // TODO: Just one?
-
public WrapCallbackIDebugInputCallbacks(DebugClientImpl1 client, DebugInputCallbacks cb) {
this.client = client;
this.cb = cb;
@@ -82,23 +75,7 @@ public class WrapCallbackIDebugInputCallbacks implements CallbackIDebugInputCall
@Override
public HRESULT StartInput(ULONG BufferSize) {
try {
- CompletableFuture future = cb.startInput();
- if (future == null) {
- return WinError.S_OK;
- }
- future.handle((input, exc) -> {
- if (exc == null) {
- client.getControl().returnInput(input);
- }
- else if (exc instanceof CancelledException) {
- // Normal if another client provides input
- }
- else {
- client.getControl().errln("ERROR getting input: " + exc.getMessage());
- }
- futures.remove(future);
- return null;
- });
+ cb.startInput(BufferSize.longValue());
return WinError.S_OK;
}
catch (Throwable e) {
@@ -109,9 +86,6 @@ public class WrapCallbackIDebugInputCallbacks implements CallbackIDebugInputCall
@Override
public HRESULT EndInput() {
try {
- for (CompletableFuture future : futures) {
- future.cancel(true);
- }
cb.endInput();
return WinError.S_OK;
}
diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListener.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListener.java
index 690750736d..de3d2595c5 100644
--- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListener.java
+++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListener.java
@@ -244,4 +244,10 @@ public interface DbgEventsListener {
* @param mask class of output
*/
void consoleOutput(String output, int mask);
+
+ /**
+ * @param prompt for console output
+ */
+ void promptChanged(String prompt);
+
}
diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListenerAdapter.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListenerAdapter.java
index 17e9343b34..80781c35db 100644
--- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListenerAdapter.java
+++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/DbgEventsListenerAdapter.java
@@ -142,4 +142,10 @@ public interface DbgEventsListenerAdapter extends DbgEventsListener {
public default void consoleOutput(String output, int mask) {
// Extension point
}
+
+ @Override
+ public default void promptChanged(String prompt) {
+ // Extension point
+ }
+
}
diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgDebugInputCallbacks.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgDebugInputCallbacks.java
new file mode 100644
index 0000000000..96e8c8f4ad
--- /dev/null
+++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/manager/impl/DbgDebugInputCallbacks.java
@@ -0,0 +1,43 @@
+/* ###
+ * 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 agent.dbgeng.manager.impl;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+import agent.dbgeng.dbgeng.DebugInputCallbacks;
+
+public class DbgDebugInputCallbacks implements DebugInputCallbacks {
+ private DbgManagerImpl manager;
+
+ public DbgDebugInputCallbacks(DbgManagerImpl manager) {
+ this.manager = manager;
+ }
+
+ @Override
+ public void startInput(long bufsize) {
+ manager.getEventListeners().fire.promptChanged(">>>");
+ CompletableFuture cf = new CompletableFuture();
+ try {
+ manager.setContinuation(cf);
+ manager.getControl().returnInput(cf.get());
+ }
+ catch (InterruptedException | ExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
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 ed87f0ba38..c90d5e21f0 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
@@ -43,6 +43,7 @@ import agent.dbgeng.manager.cmd.*;
import agent.dbgeng.manager.evt.*;
import agent.dbgeng.model.iface1.DbgModelTargetActiveScope;
import agent.dbgeng.model.iface1.DbgModelTargetFocusScope;
+import agent.dbgeng.model.iface1.DbgModelTargetInterpreter;
import ghidra.async.*;
import ghidra.comm.util.BitmaskSet;
import ghidra.dbg.target.TargetObject;
@@ -110,6 +111,7 @@ public class DbgManagerImpl implements DbgManager {
private DbgThread eventThread;
private volatile boolean waiting = false;
private boolean kernelMode = false;
+ private CompletableFuture continuation;
/**
* Instantiate a new manager
@@ -370,6 +372,7 @@ public class DbgManagerImpl implements DbgManager {
status = dbgeng.getControl().getExecutionStatus();
dbgeng.setOutputCallbacks(new DbgDebugOutputCallbacks(this));
dbgeng.setEventCallbacks(new DbgDebugEventCallbacksAdapter(this));
+ dbgeng.setInputCallbacks(new DbgDebugInputCallbacks(this));
dbgeng.flushCallbacks();
if (!create) {
@@ -1429,6 +1432,13 @@ public class DbgManagerImpl implements DbgManager {
@Override
public CompletableFuture console(String command) {
+ if (continuation != null) {
+ String prompt = command.equals("") ? DbgModelTargetInterpreter.DBG_PROMPT : ">>>";
+ getEventListeners().fire.promptChanged(prompt);
+ continuation.complete(command);
+ setContinuation(null);
+ return AsyncUtils.NIL;
+ }
return execute(
new DbgConsoleExecCommand(this, command, DbgConsoleExecCommand.Output.CONSOLE))
.thenApply(e -> null);
@@ -1498,4 +1508,7 @@ public class DbgManagerImpl implements DbgManager {
this.kernelMode = kernelMode;
}
+ public void setContinuation(CompletableFuture continuation) {
+ this.continuation = continuation;
+ }
}
diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetInterpreter.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetInterpreter.java
index 4553a1f355..353db9862c 100644
--- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetInterpreter.java
+++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface1/DbgModelTargetInterpreter.java
@@ -29,6 +29,8 @@ import ghidra.dbg.target.TargetInterpreter;
*/
public interface DbgModelTargetInterpreter extends DbgModelTargetObject, TargetInterpreter {
+ public static final String DBG_PROMPT = "(kd)";
+
@Override
public default CompletableFuture execute(String cmd) {
return getModel().gateFuture(getManager().console(cmd));
diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetSession.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetSession.java
index 9845313a78..39ef012538 100644
--- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetSession.java
+++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/iface2/DbgModelTargetSession.java
@@ -15,6 +15,8 @@
*/
package agent.dbgeng.model.iface2;
+import java.util.List;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
import agent.dbgeng.dbgeng.DebugClient.DebugOutputFlags;
@@ -70,6 +72,13 @@ public interface DbgModelTargetSession extends //
getListeners().fire.consoleOutput(getProxy(), chan, output);
}
+ @Override
+ public default void promptChanged(String prompt) {
+ changeAttributes(List.of(), Map.of( //
+ PROMPT_ATTRIBUTE_NAME, prompt //
+ ), "Refreshed");
+ }
+
@Override
public default CompletableFuture setActive() {
DbgManagerImpl manager = getManager();
diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetSessionImpl.java b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetSessionImpl.java
index e6ae22671e..c1ef8d19c0 100644
--- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetSessionImpl.java
+++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/java/agent/dbgeng/model/impl/DbgModelTargetSessionImpl.java
@@ -22,15 +22,26 @@ import java.util.concurrent.CompletableFuture;
import agent.dbgeng.dbgeng.DebugSessionId;
import agent.dbgeng.manager.*;
import agent.dbgeng.model.iface1.DbgModelSelectableObject;
+import agent.dbgeng.model.iface1.DbgModelTargetInterpreter;
import agent.dbgeng.model.iface2.DbgModelTargetProcessContainer;
import agent.dbgeng.model.iface2.DbgModelTargetSession;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.util.PathUtils;
-@TargetObjectSchemaInfo(name = "Session", elements = {
- @TargetElementType(type = Void.class) }, attributes = {
- @TargetAttributeType(name = "Attributes", type = DbgModelTargetSessionAttributesImpl.class, fixed = true),
- @TargetAttributeType(name = "Processes", type = DbgModelTargetProcessContainerImpl.class, required = true, fixed = true),
+@TargetObjectSchemaInfo(
+ name = "Session",
+ elements = {
+ @TargetElementType(type = Void.class) },
+ attributes = {
+ @TargetAttributeType(
+ name = "Attributes",
+ type = DbgModelTargetSessionAttributesImpl.class,
+ fixed = true),
+ @TargetAttributeType(
+ name = "Processes",
+ type = DbgModelTargetProcessContainerImpl.class,
+ required = true,
+ fixed = true),
@TargetAttributeType(type = Void.class) })
public class DbgModelTargetSessionImpl extends DbgModelTargetObjectImpl
implements DbgModelTargetSession {
@@ -71,7 +82,7 @@ public class DbgModelTargetSessionImpl extends DbgModelTargetObjectImpl
processes //
), Map.of( //
ACCESSIBLE_ATTRIBUTE_NAME, accessible, //
- PROMPT_ATTRIBUTE_NAME, DBG_PROMPT, //
+ PROMPT_ATTRIBUTE_NAME, DbgModelTargetInterpreter.DBG_PROMPT, //
STATE_ATTRIBUTE_NAME, TargetExecutionState.ALIVE //
), "Initialized");