GP-1309: Making GDB manager's line separator configurable

.
This commit is contained in:
Dan 2021-09-20 10:28:11 -04:00
parent 0655f76e91
commit 6cc519f2aa
6 changed files with 80 additions and 5 deletions

View file

@ -44,6 +44,8 @@ public class GdbInJvmDebuggerModelFactory implements DebuggerModelFactory {
public final Property<Boolean> useExistingOption =
Property.fromAccessors(boolean.class, this::isUseExisting, this::setUseExisting);
// TODO: newLine option?
@Override
public CompletableFuture<? extends DebuggerObjectModel> build() {
// TODO: Choose Linux or Windows pty based on host OS

View file

@ -58,6 +58,12 @@ public class GdbOverSshDebuggerModelFactory implements DebuggerModelFactory {
public final Property<String> keyFileOption =
Property.fromAccessors(String.class, this::getKeyFile, this::setKeyFile);
// Always default to false, despite local system, because remote is likely Linux.
private boolean useCrlf = false;
@FactoryOption("Use DOS line endings (unchecked for UNIX)")
public final Property<Boolean> crlfNewLineOption =
Property.fromAccessors(Boolean.class, this::isUseCrlf, this::setUseCrlf);
@Override
public CompletableFuture<? extends DebuggerObjectModel> build() {
return CompletableFuture.supplyAsync(() -> {
@ -68,6 +74,12 @@ public class GdbOverSshDebuggerModelFactory implements DebuggerModelFactory {
factory.setUsername(username);
return new GdbModelImpl(factory);
}).thenCompose(model -> {
if (useCrlf) {
model.setDosNewLine();
}
else {
model.setUnixNewLine();
}
return model.startGDB(existing ? null : gdbCmd, new String[] {}).thenApply(__ -> model);
});
}
@ -125,4 +137,12 @@ public class GdbOverSshDebuggerModelFactory implements DebuggerModelFactory {
public void setKeyFile(String keyFile) {
this.keyFile = keyFile;
}
public boolean isUseCrlf() {
return useCrlf;
}
public void setUseCrlf(boolean useCrlf) {
this.useCrlf = useCrlf;
}
}

View file

@ -41,6 +41,8 @@ public class GdbLocalDebuggerModelFactory extends AbstractGadpLocalDebuggerModel
public final Property<Boolean> useExistingOption =
Property.fromAccessors(boolean.class, this::isUseExisting, this::setUseExisting);
// TODO: newLine option?
@Override
public boolean isCompatible() {
// TODO: Could potentially support GDB on Windows, but the pty thing would need porting.

View file

@ -107,6 +107,37 @@ public interface GdbManager extends AutoCloseable, GdbBreakpointInsertions {
return new GdbManagerImpl(ptyFactory);
}
/**
* Set the line terminator (separator) used to serialize commands to GDB
*
* <p>
* Because the manager may be communicating to GDB running remotely, possibly on another
* platform, it may be necessary to customize the line terminator. The manager will default to
* the line terminator used by the local system, i.e., {@link System#lineSeparator()}.
*
* <p>
* While permitted, it is not advisable to modify this parameter while the manager is running.
* Chances are, if this was mis-configured, the manager and session are hopelessly out of sync.
* Start a new properly configured session instead.
*
* @param newLine the line separator to use
*/
public void setNewLine(String newLine);
/**
* Set to UNIX-style (CR) line terminator
*/
default void setUnixNewLine() {
setNewLine("\n");
}
/**
* Set to DOS-style (CRLF) line terminator
*/
default void setDosNewLine() {
setNewLine("\r\n");
}
/**
* Launch GDB
*

View file

@ -45,6 +45,7 @@ import ghidra.dbg.util.PrefixMap;
import ghidra.framework.Application;
import ghidra.lifecycle.Internal;
import ghidra.util.Msg;
import ghidra.util.SystemUtilities;
import ghidra.util.datastruct.ListenerSet;
import sun.misc.Signal;
import sun.misc.SignalHandler;
@ -75,7 +76,7 @@ public class GdbManagerImpl implements GdbManager {
}
private static final boolean LOG_IO =
Boolean.getBoolean("agent.gdb.manager.log");
Boolean.getBoolean("agent.gdb.manager.log") || SystemUtilities.isInDevelopmentMode();
private static PrintWriter DBG_LOG = null;
private static final String PROMPT_GDB = "(gdb)";
public static final int INTERRUPT_MAX_RETRIES = 3;
@ -158,6 +159,8 @@ public class GdbManagerImpl implements GdbManager {
private PtyThread cliThread;
private PtyThread mi2Thread;
private String newLine = System.lineSeparator();
private final AsyncLock cmdLock = new AsyncLock();
private final AtomicReference<AsyncLock.Hold> cmdLockHold = new AtomicReference<>(null);
private ExecutorService executor;
@ -205,8 +208,11 @@ public class GdbManagerImpl implements GdbManager {
try {
File userSettings = Application.getUserSettingsDirectory();
File logFile = new File(userSettings, "GDB.log");
if (!logFile.canWrite()) {
throw new AssertionError(logFile.getPath() + " appears to be unwritable");
try {
logFile.createNewFile();
}
catch (Exception e) {
throw new AssertionError(logFile.getPath() + " appears to be unwritable", e);
}
DBG_LOG = new PrintWriter(new FileOutputStream(logFile));
}
@ -559,6 +565,11 @@ public class GdbManagerImpl implements GdbManager {
});
}
@Override
public void setNewLine(String newLine) {
this.newLine = newLine;
}
@Override
public void start(String gdbCmd, String... args) throws IOException {
List<String> fullargs = new ArrayList<>();
@ -592,7 +603,8 @@ public class GdbManagerImpl implements GdbManager {
cliThread = iniThread;
cliThread.setName("GDB Read CLI");
cliThread.writer.println("new-ui mi2 " + mi2Pty.getChild().nullSession());
cliThread.writer
.print("new-ui mi2 " + mi2Pty.getChild().nullSession() + newLine);
cliThread.writer.flush();
mi2Thread = new PtyThread(mi2Pty, Channel.STDOUT, Interpreter.MI2);
@ -743,7 +755,7 @@ public class GdbManagerImpl implements GdbManager {
Interpreter interpreter = cmd.getInterpreter();
PrintWriter wr = getWriter(interpreter);
//Msg.debug(this, "STDIN: " + text);
wr.println(text);
wr.print(text + newLine);
wr.flush();
if (LOG_IO) {
DBG_LOG.println(">" + interpreter + ": " + text);

View file

@ -131,6 +131,14 @@ public class GdbModelImpl extends AbstractDebuggerObjectModel {
}
}
public void setUnixNewLine() {
gdb.setUnixNewLine();
}
public void setDosNewLine() {
gdb.setDosNewLine();
}
public CompletableFuture<Void> startGDB(String gdbCmd, String[] args) {
try {
gdb.start(gdbCmd, args);