GP-1076: Adding diagnostic messages, esp., "new session" to GDB connector.

This commit is contained in:
Dan 2021-08-20 13:30:45 -04:00
parent 901f888510
commit 18f3075201
7 changed files with 39 additions and 11 deletions

View file

@ -48,7 +48,7 @@ public class GdbInJvmDebuggerModelFactory implements DebuggerModelFactory {
public CompletableFuture<? extends DebuggerObjectModel> build() { public CompletableFuture<? extends DebuggerObjectModel> build() {
// TODO: Choose Linux or Windows pty based on host OS // TODO: Choose Linux or Windows pty based on host OS
GdbModelImpl model = new GdbModelImpl(new LinuxPtyFactory()); GdbModelImpl model = new GdbModelImpl(new LinuxPtyFactory());
return model.startGDB(gdbCmd, new String[] {}).thenApply(__ -> model); return model.startGDB(existing ? null : gdbCmd, new String[] {}).thenApply(__ -> model);
} }
@Override @Override

View file

@ -22,7 +22,6 @@ import agent.gdb.pty.ssh.GhidraSshPtyFactory;
import ghidra.dbg.DebuggerModelFactory; import ghidra.dbg.DebuggerModelFactory;
import ghidra.dbg.DebuggerObjectModel; import ghidra.dbg.DebuggerObjectModel;
import ghidra.dbg.util.ConfigurableFactory.FactoryDescription; import ghidra.dbg.util.ConfigurableFactory.FactoryDescription;
import ghidra.dbg.util.ConfigurableFactory.FactoryOption;
@FactoryDescription( @FactoryDescription(
brief = "GNU gdb via SSH", brief = "GNU gdb via SSH",
@ -69,7 +68,7 @@ public class GdbOverSshDebuggerModelFactory implements DebuggerModelFactory {
factory.setUsername(username); factory.setUsername(username);
return new GdbModelImpl(factory); return new GdbModelImpl(factory);
}).thenCompose(model -> { }).thenCompose(model -> {
return model.startGDB(gdbCmd, new String[] {}).thenApply(__ -> model); return model.startGDB(existing ? null : gdbCmd, new String[] {}).thenApply(__ -> model);
}); });
} }

View file

@ -15,13 +15,15 @@
*/ */
package agent.gdb.manager.impl; package agent.gdb.manager.impl;
import static ghidra.async.AsyncUtils.*; import static ghidra.async.AsyncUtils.loop;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.atomic.*; import java.util.concurrent.atomic.*;
import javax.swing.JOptionPane;
import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.python.core.PyDictionary; import org.python.core.PyDictionary;
import org.python.util.InteractiveConsole; import org.python.util.InteractiveConsole;
@ -612,12 +614,20 @@ public class GdbManagerImpl implements GdbManager {
} }
else { else {
Pty mi2Pty = ptyFactory.openpty(); Pty mi2Pty = ptyFactory.openpty();
Msg.info(this, "Agent is waiting for GDB/MI v2 interpreter at " + String mi2PtyName = mi2Pty.getChild().nullSession();
mi2Pty.getChild().nullSession()); Msg.info(this, "Agent is waiting for GDB/MI v2 interpreter at " + mi2PtyName);
mi2Thread = new PtyThread(mi2Pty, Channel.STDOUT, Interpreter.MI2); mi2Thread = new PtyThread(mi2Pty, Channel.STDOUT, Interpreter.MI2);
mi2Thread.setName("GDB Read MI2"); mi2Thread.setName("GDB Read MI2");
mi2Thread.start(); mi2Thread.start();
int choice = JOptionPane.showConfirmDialog(null,
"Please enter \"new-ui mi2 " + mi2PtyName + "\" in an existing gdb session. " +
"Alternatively, disable 'use existing session' to launch a new session.",
"Waiting for GDB/MI session", JOptionPane.OK_CANCEL_OPTION);
if (choice == JOptionPane.CANCEL_OPTION) {
terminate();
}
} }
} }

View file

@ -24,6 +24,7 @@ import java.util.*;
import agent.gdb.pty.PtyChild; import agent.gdb.pty.PtyChild;
import agent.gdb.pty.PtySession; import agent.gdb.pty.PtySession;
import agent.gdb.pty.local.LocalProcessPtySession; import agent.gdb.pty.local.LocalProcessPtySession;
import ghidra.util.Msg;
public class LinuxPtyChild extends LinuxPtyEndpoint implements PtyChild { public class LinuxPtyChild extends LinuxPtyEndpoint implements PtyChild {
private final String name; private final String name;
@ -81,8 +82,14 @@ public class LinuxPtyChild extends LinuxPtyEndpoint implements PtyChild {
} }
builder.inheritIO(); builder.inheritIO();
try {
return new LocalProcessPtySession(builder.start()); return new LocalProcessPtySession(builder.start());
} }
catch (Exception e) {
Msg.error(this, "Could not start process with args " + args, e);
throw e;
}
}
protected PtySession sessionUsingPythonLeader(String[] args, Map<String, String> env) protected PtySession sessionUsingPythonLeader(String[] args, Map<String, String> env)
throws IOException { throws IOException {

View file

@ -18,6 +18,7 @@ package agent.gdb.pty.linux;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import ghidra.util.Msg;
import jnr.posix.POSIX; import jnr.posix.POSIX;
import jnr.posix.POSIXFactory; import jnr.posix.POSIXFactory;
@ -80,6 +81,7 @@ public class LinuxPtySessionLeader {
checkErr(() -> LIB_POSIX.execv(subArgs.get(0), subArgs.toArray(new String[0]))); checkErr(() -> LIB_POSIX.execv(subArgs.get(0), subArgs.toArray(new String[0])));
} }
catch (Throwable t) { catch (Throwable t) {
Msg.error(this, "Could not execv with args " + subArgs, t);
try { try {
checkErr(() -> LIB_POSIX.dup2(bk, 2)); checkErr(() -> LIB_POSIX.dup2(bk, 2));
} }

View file

@ -24,6 +24,7 @@ import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.KnownHosts; import ch.ethz.ssh2.KnownHosts;
import docking.DockingWindowManager; import docking.DockingWindowManager;
import docking.widgets.PasswordDialog; import docking.widgets.PasswordDialog;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
public class GhidraSshPtyFactory implements PtyFactory { public class GhidraSshPtyFactory implements PtyFactory {
@ -97,7 +98,8 @@ public class GhidraSshPtyFactory implements PtyFactory {
// TODO: Find an API that uses char[] so I can clear it! // TODO: Find an API that uses char[] so I can clear it!
String password = new String(promptPassword(hostname, "Password for " + username)); String password = new String(promptPassword(hostname, "Password for " + username));
if (!sshConn.authenticateWithPassword(username, password)) { if (!sshConn.authenticateWithPassword(username, password)) {
throw new IOException("Authentication failed"); Msg.error(this, "SSH password authentication failed");
throw new IOException("SSH password authentication failed");
} }
} }
else { else {
@ -108,14 +110,16 @@ public class GhidraSshPtyFactory implements PtyFactory {
} }
String password = new String(promptPassword(hostname, "Password for " + pemFile)); String password = new String(promptPassword(hostname, "Password for " + pemFile));
if (!sshConn.authenticateWithPublicKey(username, pemFile, password)) { if (!sshConn.authenticateWithPublicKey(username, pemFile, password)) {
throw new IOException("Authentication failed"); Msg.error(this, "SSH pukey authentication failed");
throw new IOException("SSH pukey authentication failed");
} }
} }
success = true; success = true;
return sshConn; return sshConn;
} }
catch (CancelledException e) { catch (CancelledException e) {
throw new IOException("User cancelled", e); Msg.error(this, "SSH connection/authentication cancelled by user");
throw new IOException("SSH connection/authentication cancelled by user", e);
} }
finally { finally {
if (!success) { if (!success) {

View file

@ -49,7 +49,13 @@ public class SshPtyChild extends SshPtyEndpoint implements PtyChild {
.collect(Collectors.joining(" ")) + .collect(Collectors.joining(" ")) +
" "; " ";
String cmdStr = Stream.of(args).collect(Collectors.joining(" ")); String cmdStr = Stream.of(args).collect(Collectors.joining(" "));
try {
session.execCommand(envStr + cmdStr); session.execCommand(envStr + cmdStr);
}
catch (Throwable t) {
Msg.error(this, "Could not execute remote command: " + envStr + cmdStr, t);
throw t;
}
return new SshPtySession(session); return new SshPtySession(session);
} }