mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-26 14:12:17 +00:00
GP-840: Punting when GDB asks for follow-on input, to avoid hang.
This commit is contained in:
parent
2891486a2a
commit
75f950880e
@ -77,7 +77,7 @@ public class GdbManagerImpl implements GdbManager {
|
||||
static {
|
||||
if (LOG_IO) {
|
||||
try {
|
||||
DBG_LOG = new PrintWriter(new FileOutputStream(new File("DBG.log")));
|
||||
DBG_LOG = new PrintWriter(new FileOutputStream(new File("GDB.log")));
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
throw new AssertionError(e);
|
||||
@ -810,6 +810,7 @@ public class GdbManagerImpl implements GdbManager {
|
||||
/**
|
||||
* Schedule a line of GDB output for processing
|
||||
*
|
||||
* <p>
|
||||
* Before the implementation started using a PTY, the channel was used to distinguish whether
|
||||
* the line was read from stdout or stderr. Now, all output is assumed to be from stdout.
|
||||
*
|
||||
@ -1487,6 +1488,18 @@ public class GdbManagerImpl implements GdbManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Internal
|
||||
public void injectInput(Interpreter interpreter, String input) {
|
||||
PrintWriter writer = getWriter(interpreter);
|
||||
writer.print(input);
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
@Internal
|
||||
public void synthesizeConsoleOut(Channel channel, String line) {
|
||||
listenersConsoleOutput.fire.output(channel, line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized GdbState getState() {
|
||||
return state.get();
|
||||
|
@ -18,9 +18,11 @@ package agent.gdb.manager.impl.cmd;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
|
||||
import agent.gdb.manager.GdbManager;
|
||||
import agent.gdb.manager.GdbManager.Channel;
|
||||
import agent.gdb.manager.evt.AbstractGdbCompletedCommandEvent;
|
||||
import agent.gdb.manager.evt.GdbConsoleOutputEvent;
|
||||
import agent.gdb.manager.impl.*;
|
||||
import agent.gdb.manager.impl.GdbManagerImpl.Interpreter;
|
||||
|
||||
/**
|
||||
* Implementation of {@link GdbManager#console(String)} and similar
|
||||
@ -40,22 +42,62 @@ public class GdbConsoleExecCommand extends AbstractGdbCommandWithThreadAndFrameI
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: I think there should be a separate command for arbitrary CLI input. I'm not sure yet
|
||||
* whether it should wait in the queue or just be sent immediately.
|
||||
*/
|
||||
@Override
|
||||
public Interpreter getInterpreter() {
|
||||
/*if (to == Output.CONSOLE && manager.hasCli() && threadId == null && frameId == null) {
|
||||
return Interpreter.CLI;
|
||||
}*/
|
||||
return Interpreter.MI2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encode(String threadPart, String framePart) {
|
||||
return "-interpreter-exec" + threadPart + framePart + " console \"" +
|
||||
StringEscapeUtils.escapeJava(command) + "\"";
|
||||
switch (getInterpreter()) {
|
||||
case CLI:
|
||||
return command;
|
||||
case MI2:
|
||||
return "-interpreter-exec" + threadPart + framePart + " console \"" +
|
||||
StringEscapeUtils.escapeJava(command) + "\"";
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(GdbEvent<?> evt, GdbPendingCommand<?> pending) {
|
||||
if (getInterpreter() == Interpreter.CLI) {
|
||||
// At the very least, I should expect to see the (gdb) prompt.
|
||||
if (evt instanceof GdbConsoleOutputEvent) {
|
||||
GdbConsoleOutputEvent out = (GdbConsoleOutputEvent) evt;
|
||||
if (out.getInterpreter() == Interpreter.CLI) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// MI2
|
||||
if (evt instanceof AbstractGdbCompletedCommandEvent) {
|
||||
pending.claim(evt);
|
||||
return true;
|
||||
}
|
||||
else if (evt instanceof GdbConsoleOutputEvent && to == Output.CAPTURE) {
|
||||
else if (evt instanceof GdbConsoleOutputEvent) {
|
||||
GdbConsoleOutputEvent out = (GdbConsoleOutputEvent) evt;
|
||||
if (out.getInterpreter() == getInterpreter()) {
|
||||
pending.steal(evt);
|
||||
// This is not a great check...
|
||||
if (out.getInterpreter() == Interpreter.MI2 && ">".equals(out.getOutput().trim()) &&
|
||||
!command.trim().startsWith("ec")) {
|
||||
manager.injectInput(Interpreter.MI2, "end\n");
|
||||
manager.synthesizeConsoleOut(Channel.STDERR,
|
||||
"Ghidra GDB Agent: Multi-line / follow-up input is not currently supported. " +
|
||||
"I just typed 'end' for you.\n");
|
||||
}
|
||||
if (to == Output.CAPTURE) {
|
||||
if (out.getInterpreter() == getInterpreter()) {
|
||||
pending.steal(evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -63,6 +105,10 @@ public class GdbConsoleExecCommand extends AbstractGdbCommandWithThreadAndFrameI
|
||||
|
||||
@Override
|
||||
public String complete(GdbPendingCommand<?> pending) {
|
||||
if (getInterpreter() == Interpreter.CLI) {
|
||||
return null;
|
||||
}
|
||||
// MI2
|
||||
pending.checkCompletion(AbstractGdbCompletedCommandEvent.class);
|
||||
|
||||
if (to == Output.CONSOLE) {
|
||||
|
@ -32,6 +32,14 @@ import ghidra.dbg.target.schema.*;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
* TODO: We should probably expose the raw CLI (if available) via TargetConsole, and perhaps re-work
|
||||
* the UI to use it when available. This could more generally solve the multi-line input thing, and
|
||||
* provide a distinction between API access (where {@link TargetInterpreter} makes more sense), and
|
||||
* I/O access (where {@link TargetConsole}) makes more sense. I'm hoping this will also allow the
|
||||
* CLI to prompt the user when appropriate, e.g., on {@code quit} when an inferior is active. NOTE:
|
||||
* Probably should not expose raw MI2 via TargetConsole
|
||||
*/
|
||||
@TargetObjectSchemaInfo(
|
||||
name = "Session",
|
||||
elements = {
|
||||
|
Loading…
Reference in New Issue
Block a user