mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
GP-2619: Ported gdb connector to use JNA instead of piggybacking Jython's JNR
This commit is contained in:
@@ -26,7 +26,6 @@ dependencies {
|
|||||||
api project(':Framework-AsyncComm')
|
api project(':Framework-AsyncComm')
|
||||||
api project(':Framework-Debugging')
|
api project(':Framework-Debugging')
|
||||||
api project(':Debugger-gadp')
|
api project(':Debugger-gadp')
|
||||||
api project(':Python')
|
|
||||||
api 'com.jcraft:jsch:0.1.55'
|
api 'com.jcraft:jsch:0.1.55'
|
||||||
|
|
||||||
testImplementation project(path: ':Framework-AsyncComm', configuration: 'testArtifacts')
|
testImplementation project(path: ':Framework-AsyncComm', configuration: 'testArtifacts')
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package agent.gdb.manager.impl;
|
package agent.gdb.manager.impl;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.text.MessageFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@@ -25,9 +26,6 @@ import javax.swing.JDialog;
|
|||||||
import javax.swing.JOptionPane;
|
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.icu.text.MessageFormat;
|
|
||||||
import org.python.util.InteractiveConsole;
|
|
||||||
|
|
||||||
import agent.gdb.manager.*;
|
import agent.gdb.manager.*;
|
||||||
import agent.gdb.manager.GdbCause.Causes;
|
import agent.gdb.manager.GdbCause.Causes;
|
||||||
@@ -1564,28 +1562,6 @@ public class GdbManagerImpl implements GdbManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link lazily to Jython
|
|
||||||
private static class JythonConsole {
|
|
||||||
/**
|
|
||||||
* Launch a Jython interpreter
|
|
||||||
*
|
|
||||||
* The interpreter the variable "{@code mgr}" bound to the manager. This method does not
|
|
||||||
* return until the user exits the interpreter.
|
|
||||||
*
|
|
||||||
* @param manager the manager
|
|
||||||
*/
|
|
||||||
static void interact(GdbManagerImpl manager) {
|
|
||||||
PyDictionary dict = new PyDictionary();
|
|
||||||
dict.put("mgr", manager);
|
|
||||||
try (InteractiveConsole jyConsole = new InteractiveConsole(dict);) {
|
|
||||||
jyConsole.interact();
|
|
||||||
}
|
|
||||||
catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for taking lines of input
|
* An interface for taking lines of input
|
||||||
*/
|
*/
|
||||||
@@ -1636,28 +1612,15 @@ public class GdbManagerImpl implements GdbManager {
|
|||||||
System.out.println("quit");
|
System.out.println("quit");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (">>>".equals(cmd.trim())) {
|
console(cmd).exceptionally((e) -> {
|
||||||
try {
|
Throwable realExc = AsyncUtils.unwrapThrowable(e);
|
||||||
JythonConsole.interact(this);
|
if (realExc instanceof GdbCommandError) {
|
||||||
|
return null; // Gdb will have already printed it
|
||||||
}
|
}
|
||||||
catch (NoClassDefFoundError e) {
|
e.printStackTrace();
|
||||||
Msg.error(this, "Jython is not in the classpath");
|
//System.out.print(PROMPT_GDB + " ");
|
||||||
}
|
return null;
|
||||||
catch (Throwable e) {
|
});
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console(cmd).exceptionally((e) -> {
|
|
||||||
Throwable realExc = AsyncUtils.unwrapThrowable(e);
|
|
||||||
if (realExc instanceof GdbCommandError) {
|
|
||||||
return null; // Gdb will have already printed it
|
|
||||||
}
|
|
||||||
e.printStackTrace();
|
|
||||||
//System.out.print(PROMPT_GDB + " ");
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
|||||||
@@ -17,10 +17,8 @@ package agent.gdb.pty.linux;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
import jnr.posix.POSIX;
|
import com.sun.jna.Memory;
|
||||||
import jnr.posix.POSIXFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An input stream that wraps a native POSIX file descriptor
|
* An input stream that wraps a native POSIX file descriptor
|
||||||
@@ -31,7 +29,7 @@ import jnr.posix.POSIXFactory;
|
|||||||
* behavior.
|
* behavior.
|
||||||
*/
|
*/
|
||||||
public class FdInputStream extends InputStream {
|
public class FdInputStream extends InputStream {
|
||||||
private static final POSIX LIB_POSIX = POSIXFactory.getNativePOSIX();
|
private static final PosixC LIB_POSIX = PosixC.INSTANCE;
|
||||||
|
|
||||||
private final int fd;
|
private final int fd;
|
||||||
private boolean closed = false;
|
private boolean closed = false;
|
||||||
@@ -67,11 +65,9 @@ public class FdInputStream extends InputStream {
|
|||||||
if (closed) {
|
if (closed) {
|
||||||
throw new IOException("Stream closed");
|
throw new IOException("Stream closed");
|
||||||
}
|
}
|
||||||
ByteBuffer buf = ByteBuffer.wrap(b, off, len);
|
Memory buf = new Memory(len);
|
||||||
int ret = LIB_POSIX.read(fd, buf, len);
|
int ret = LIB_POSIX.read(fd, buf, len);
|
||||||
if (ret < 0) {
|
buf.read(0, b, off, ret);
|
||||||
throw new IOException(LIB_POSIX.strerror(LIB_POSIX.errno()));
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,8 @@ package agent.gdb.pty.linux;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
import jnr.posix.POSIX;
|
import com.sun.jna.Memory;
|
||||||
import jnr.posix.POSIXFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An output stream that wraps a native POSIX file descriptor
|
* An output stream that wraps a native POSIX file descriptor
|
||||||
@@ -31,7 +29,7 @@ import jnr.posix.POSIXFactory;
|
|||||||
* behavior.
|
* behavior.
|
||||||
*/
|
*/
|
||||||
public class FdOutputStream extends OutputStream {
|
public class FdOutputStream extends OutputStream {
|
||||||
private static final POSIX LIB_POSIX = POSIXFactory.getNativePOSIX();
|
private static final PosixC LIB_POSIX = PosixC.INSTANCE;
|
||||||
|
|
||||||
private final int fd;
|
private final int fd;
|
||||||
private boolean closed = false;
|
private boolean closed = false;
|
||||||
@@ -60,14 +58,11 @@ public class FdOutputStream extends OutputStream {
|
|||||||
if (closed) {
|
if (closed) {
|
||||||
throw new IOException("Stream closed");
|
throw new IOException("Stream closed");
|
||||||
}
|
}
|
||||||
ByteBuffer buf = ByteBuffer.wrap(b, off, len);
|
Memory buf = new Memory(len);
|
||||||
|
buf.write(0, b, off, len);
|
||||||
int total = 0;
|
int total = 0;
|
||||||
do {
|
do {
|
||||||
int ret = LIB_POSIX.write(fd, buf, len - total);
|
int ret = LIB_POSIX.write(fd, buf, len - total);
|
||||||
if (ret < 0) {
|
|
||||||
throw new IOException(LIB_POSIX.strerror(LIB_POSIX.errno()));
|
|
||||||
}
|
|
||||||
total += ret;
|
total += ret;
|
||||||
}
|
}
|
||||||
while (total < len);
|
while (total < len);
|
||||||
|
|||||||
@@ -16,17 +16,16 @@
|
|||||||
package agent.gdb.pty.linux;
|
package agent.gdb.pty.linux;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
import com.sun.jna.Memory;
|
||||||
|
import com.sun.jna.ptr.IntByReference;
|
||||||
|
|
||||||
import agent.gdb.pty.Pty;
|
import agent.gdb.pty.Pty;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import jnr.ffi.Pointer;
|
|
||||||
import jnr.ffi.byref.IntByReference;
|
|
||||||
import jnr.posix.POSIX;
|
|
||||||
import jnr.posix.POSIXFactory;
|
|
||||||
|
|
||||||
public class LinuxPty implements Pty {
|
public class LinuxPty implements Pty {
|
||||||
static final POSIX LIB_POSIX = POSIXFactory.getNativePOSIX();
|
|
||||||
|
static final PosixC LIB_POSIX = PosixC.INSTANCE;
|
||||||
|
|
||||||
private final int aparent;
|
private final int aparent;
|
||||||
private final int achild;
|
private final int achild;
|
||||||
@@ -40,12 +39,9 @@ public class LinuxPty implements Pty {
|
|||||||
// TODO: Support termp and winp?
|
// TODO: Support termp and winp?
|
||||||
IntByReference p = new IntByReference();
|
IntByReference p = new IntByReference();
|
||||||
IntByReference c = new IntByReference();
|
IntByReference c = new IntByReference();
|
||||||
Pointer n = Pointer.wrap(jnr.ffi.Runtime.getSystemRuntime(), ByteBuffer.allocate(1024));
|
Memory n = new Memory(1024);
|
||||||
if (Util.INSTANCE.openpty(p, c, n, null, null) < 0) {
|
Util.INSTANCE.openpty(p, c, n, null, null);
|
||||||
int errno = LIB_POSIX.errno();
|
return new LinuxPty(p.getValue(), c.getValue(), n.getString(0));
|
||||||
throw new IOException(errno + ": " + LIB_POSIX.strerror(errno));
|
|
||||||
}
|
|
||||||
return new LinuxPty(p.intValue(), c.intValue(), n.getString(0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LinuxPty(int aparent, int achild, String name) {
|
LinuxPty(int aparent, int achild, String name) {
|
||||||
@@ -73,15 +69,8 @@ public class LinuxPty implements Pty {
|
|||||||
if (closed) {
|
if (closed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int result;
|
LIB_POSIX.close(achild);
|
||||||
result = LIB_POSIX.close(achild);
|
LIB_POSIX.close(aparent);
|
||||||
if (result < 0) {
|
|
||||||
throw new IOException(LIB_POSIX.strerror(LIB_POSIX.errno()));
|
|
||||||
}
|
|
||||||
result = LIB_POSIX.close(aparent);
|
|
||||||
if (result < 0) {
|
|
||||||
throw new IOException(LIB_POSIX.strerror(LIB_POSIX.errno()));
|
|
||||||
}
|
|
||||||
closed = true;
|
closed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,14 +16,9 @@
|
|||||||
package agent.gdb.pty.linux;
|
package agent.gdb.pty.linux;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
|
|
||||||
import ghidra.util.Msg;
|
|
||||||
import jnr.posix.POSIX;
|
|
||||||
import jnr.posix.POSIXFactory;
|
|
||||||
|
|
||||||
public class LinuxPtySessionLeader {
|
public class LinuxPtySessionLeader {
|
||||||
private static final POSIX LIB_POSIX = POSIXFactory.getNativePOSIX();
|
private static final PosixC LIB_POSIX = PosixC.INSTANCE;
|
||||||
private static final int O_RDWR = 2; // TODO: Find this in libs
|
private static final int O_RDWR = 2; // TODO: Find this in libs
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
@@ -40,54 +35,50 @@ public class LinuxPtySessionLeader {
|
|||||||
subArgs = List.of(args).subList(1, args.length);
|
subArgs = List.of(args).subList(1, args.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <T> T checkErr(Callable<T> r) throws Exception {
|
|
||||||
LIB_POSIX.errno(0);
|
|
||||||
T result = r.call();
|
|
||||||
int errno = LIB_POSIX.errno();
|
|
||||||
if (errno != 0) {
|
|
||||||
throw new RuntimeException("errno=" + errno + ": " + LIB_POSIX.strerror(errno));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void run() throws Exception {
|
protected void run() throws Exception {
|
||||||
/** This tells Linux to make this process the leader of a new session. */
|
/** This tells Linux to make this process the leader of a new session. */
|
||||||
checkErr(() -> LIB_POSIX.setsid());
|
LIB_POSIX.setsid();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open the TTY. On Linux, the first TTY opened since becoming a session leader becomes the
|
* Open the TTY. On Linux, the first TTY opened since becoming a session leader becomes the
|
||||||
* session's controlling TTY. Other platforms, e.g., BSD may require an explicit IOCTL.
|
* session's controlling TTY. Other platforms, e.g., BSD may require an explicit IOCTL.
|
||||||
*/
|
*/
|
||||||
int fd = checkErr(() -> LIB_POSIX.open(ptyPath, O_RDWR, 0));
|
int bk = -1;
|
||||||
|
|
||||||
/** Copy stderr to a backup descriptor, in case something goes wrong. */
|
|
||||||
int bk = fd + 1;
|
|
||||||
checkErr(() -> LIB_POSIX.dup2(2, bk));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy the TTY fd over all standard streams. This effectively redirects the leader's
|
|
||||||
* standard streams to the TTY.
|
|
||||||
*/
|
|
||||||
checkErr(() -> LIB_POSIX.dup2(fd, 0));
|
|
||||||
checkErr(() -> LIB_POSIX.dup2(fd, 1));
|
|
||||||
checkErr(() -> LIB_POSIX.dup2(fd, 2));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* At this point, we are the session leader and the named TTY is the controlling PTY. Now,
|
|
||||||
* exec the specified image with arguments as the session leader. Recall, this replaces the
|
|
||||||
* image of this process.
|
|
||||||
*/
|
|
||||||
try {
|
try {
|
||||||
checkErr(() -> LIB_POSIX.execv(subArgs.get(0), subArgs.toArray(new String[0])));
|
int fd = LIB_POSIX.open(ptyPath, O_RDWR, 0);
|
||||||
|
|
||||||
|
/** Copy stderr to a backup descriptor, in case something goes wrong. */
|
||||||
|
int bkt = fd + 1;
|
||||||
|
LIB_POSIX.dup2(2, bkt);
|
||||||
|
bk = bkt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the TTY fd over all standard streams. This effectively redirects the leader's
|
||||||
|
* standard streams to the TTY.
|
||||||
|
*/
|
||||||
|
LIB_POSIX.dup2(fd, 0);
|
||||||
|
LIB_POSIX.dup2(fd, 1);
|
||||||
|
LIB_POSIX.dup2(fd, 2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* At this point, we are the session leader and the named TTY is the controlling PTY.
|
||||||
|
* Now, exec the specified image with arguments as the session leader. Recall, this
|
||||||
|
* replaces the image of this process.
|
||||||
|
*/
|
||||||
|
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);
|
System.err.println("Error with ptyPath = '" + ptyPath + "', and subArgs = " + subArgs);
|
||||||
try {
|
t.printStackTrace();
|
||||||
checkErr(() -> LIB_POSIX.dup2(bk, 2));
|
if (bk != -1) {
|
||||||
}
|
try {
|
||||||
catch (Throwable t2) {
|
int bkt = bk;
|
||||||
// Catastrophic
|
LIB_POSIX.dup2(bkt, 2);
|
||||||
System.exit(-1);
|
}
|
||||||
|
catch (Throwable t2) {
|
||||||
|
// Catastrophic
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw t;
|
throw t;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.gdb.pty.linux;
|
||||||
|
|
||||||
|
import com.sun.jna.*;
|
||||||
|
import com.sun.jna.platform.linux.LibC;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for POSIX functions in libc
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The functions are not documented here. Instead see the POSIX manual pages.
|
||||||
|
*/
|
||||||
|
public interface PosixC extends LibC {
|
||||||
|
PosixC INSTANCE = Native.load("c", PosixC.class);
|
||||||
|
|
||||||
|
int close(int fd) throws LastErrorException;
|
||||||
|
|
||||||
|
int read(int fd, Pointer buf, int len) throws LastErrorException;
|
||||||
|
|
||||||
|
int write(int fd, Pointer buf, int i) throws LastErrorException;
|
||||||
|
|
||||||
|
int setsid() throws LastErrorException;
|
||||||
|
|
||||||
|
int open(String path, int mode, int flags) throws LastErrorException;
|
||||||
|
|
||||||
|
int dup2(int oldfd, int newfd) throws LastErrorException;
|
||||||
|
|
||||||
|
int execv(String path, String[] argv) throws LastErrorException;
|
||||||
|
}
|
||||||
@@ -15,16 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package agent.gdb.pty.linux;
|
package agent.gdb.pty.linux;
|
||||||
|
|
||||||
import jnr.ffi.LibraryLoader;
|
import com.sun.jna.*;
|
||||||
import jnr.ffi.Pointer;
|
import com.sun.jna.ptr.IntByReference;
|
||||||
import jnr.ffi.annotations.Out;
|
|
||||||
import jnr.ffi.byref.IntByReference;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The interface for linking to {@code openpty} via jnr-ffi
|
* The interface for linking to {@code openpty} via jna
|
||||||
*/
|
*/
|
||||||
public interface Util {
|
public interface Util extends Library {
|
||||||
Util INSTANCE = LibraryLoader.create(Util.class).load("util");
|
Util INSTANCE = Native.load("util", Util.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See the Linux manual pages
|
* See the Linux manual pages
|
||||||
@@ -36,6 +34,6 @@ public interface Util {
|
|||||||
* @param winp (purposefully undocumented here)
|
* @param winp (purposefully undocumented here)
|
||||||
* @return (purposefully undocumented here)
|
* @return (purposefully undocumented here)
|
||||||
*/
|
*/
|
||||||
int openpty(@Out IntByReference amaster, @Out IntByReference aslave, @Out Pointer name,
|
int openpty(IntByReference amaster, IntByReference aslave, Pointer name,
|
||||||
@Out Pointer termp, @Out Pointer winp);
|
Pointer termp, Pointer winp) throws LastErrorException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -681,7 +681,7 @@ public class DebuggerCoordinates {
|
|||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
Msg.error(DebuggerCoordinates.class,
|
Msg.error(DebuggerCoordinates.class,
|
||||||
"Could not restore invalid time specification: " + timeSpec);
|
"Could not restore invalid time specification: " + timeSpec);
|
||||||
time = null;
|
time = TraceSchedule.ZERO;
|
||||||
}
|
}
|
||||||
Integer frame = null;
|
Integer frame = null;
|
||||||
if (coordState.hasValue(KEY_FRAME)) {
|
if (coordState.hasValue(KEY_FRAME)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user