Merge remote-tracking branch 'origin/GP-2619_Dan_linuxPtyPort2Jna--SQUASHED'

This commit is contained in:
Ryan Kurtz 2022-09-28 01:23:13 -04:00
commit f2d3b7dfaa
9 changed files with 113 additions and 139 deletions

View file

@ -26,7 +26,6 @@ dependencies {
api project(':Framework-AsyncComm')
api project(':Framework-Debugging')
api project(':Debugger-gadp')
api project(':Python')
api 'com.jcraft:jsch:0.1.55'
testImplementation project(path: ':Framework-AsyncComm', configuration: 'testArtifacts')

View file

@ -16,6 +16,7 @@
package agent.gdb.manager.impl;
import java.io.*;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
@ -25,9 +26,6 @@ import javax.swing.JDialog;
import javax.swing.JOptionPane;
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.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
*/
@ -1636,28 +1612,15 @@ public class GdbManagerImpl implements GdbManager {
System.out.println("quit");
return;
}
if (">>>".equals(cmd.trim())) {
try {
JythonConsole.interact(this);
console(cmd).exceptionally((e) -> {
Throwable realExc = AsyncUtils.unwrapThrowable(e);
if (realExc instanceof GdbCommandError) {
return null; // Gdb will have already printed it
}
catch (NoClassDefFoundError e) {
Msg.error(this, "Jython is not in the classpath");
}
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;
});
}
e.printStackTrace();
//System.out.print(PROMPT_GDB + " ");
return null;
});
}
}
finally {

View file

@ -17,10 +17,8 @@ package agent.gdb.pty.linux;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import jnr.posix.POSIX;
import jnr.posix.POSIXFactory;
import com.sun.jna.Memory;
/**
* An input stream that wraps a native POSIX file descriptor
@ -31,7 +29,7 @@ import jnr.posix.POSIXFactory;
* behavior.
*/
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 boolean closed = false;
@ -67,11 +65,9 @@ public class FdInputStream extends InputStream {
if (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);
if (ret < 0) {
throw new IOException(LIB_POSIX.strerror(LIB_POSIX.errno()));
}
buf.read(0, b, off, ret);
return ret;
}

View file

@ -17,10 +17,8 @@ package agent.gdb.pty.linux;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import jnr.posix.POSIX;
import jnr.posix.POSIXFactory;
import com.sun.jna.Memory;
/**
* An output stream that wraps a native POSIX file descriptor
@ -31,7 +29,7 @@ import jnr.posix.POSIXFactory;
* behavior.
*/
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 boolean closed = false;
@ -60,14 +58,11 @@ public class FdOutputStream extends OutputStream {
if (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;
do {
int ret = LIB_POSIX.write(fd, buf, len - total);
if (ret < 0) {
throw new IOException(LIB_POSIX.strerror(LIB_POSIX.errno()));
}
total += ret;
}
while (total < len);

View file

@ -16,17 +16,16 @@
package agent.gdb.pty.linux;
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 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 {
static final POSIX LIB_POSIX = POSIXFactory.getNativePOSIX();
static final PosixC LIB_POSIX = PosixC.INSTANCE;
private final int aparent;
private final int achild;
@ -40,12 +39,9 @@ public class LinuxPty implements Pty {
// TODO: Support termp and winp?
IntByReference p = new IntByReference();
IntByReference c = new IntByReference();
Pointer n = Pointer.wrap(jnr.ffi.Runtime.getSystemRuntime(), ByteBuffer.allocate(1024));
if (Util.INSTANCE.openpty(p, c, n, null, null) < 0) {
int errno = LIB_POSIX.errno();
throw new IOException(errno + ": " + LIB_POSIX.strerror(errno));
}
return new LinuxPty(p.intValue(), c.intValue(), n.getString(0));
Memory n = new Memory(1024);
Util.INSTANCE.openpty(p, c, n, null, null);
return new LinuxPty(p.getValue(), c.getValue(), n.getString(0));
}
LinuxPty(int aparent, int achild, String name) {
@ -73,15 +69,8 @@ public class LinuxPty implements Pty {
if (closed) {
return;
}
int result;
result = LIB_POSIX.close(achild);
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()));
}
LIB_POSIX.close(achild);
LIB_POSIX.close(aparent);
closed = true;
}
}

View file

@ -16,14 +16,9 @@
package agent.gdb.pty.linux;
import java.util.List;
import java.util.concurrent.Callable;
import ghidra.util.Msg;
import jnr.posix.POSIX;
import jnr.posix.POSIXFactory;
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
public static void main(String[] args) throws Exception {
@ -40,54 +35,50 @@ public class LinuxPtySessionLeader {
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 {
/** 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
* session's controlling TTY. Other platforms, e.g., BSD may require an explicit IOCTL.
*/
int fd = checkErr(() -> LIB_POSIX.open(ptyPath, O_RDWR, 0));
/** 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.
*/
int bk = -1;
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) {
Msg.error(this, "Could not execv with args " + subArgs, t);
try {
checkErr(() -> LIB_POSIX.dup2(bk, 2));
}
catch (Throwable t2) {
// Catastrophic
System.exit(-1);
System.err.println("Error with ptyPath = '" + ptyPath + "', and subArgs = " + subArgs);
t.printStackTrace();
if (bk != -1) {
try {
int bkt = bk;
LIB_POSIX.dup2(bkt, 2);
}
catch (Throwable t2) {
// Catastrophic
System.exit(-1);
}
}
throw t;
}

View file

@ -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;
}

View file

@ -15,16 +15,14 @@
*/
package agent.gdb.pty.linux;
import jnr.ffi.LibraryLoader;
import jnr.ffi.Pointer;
import jnr.ffi.annotations.Out;
import jnr.ffi.byref.IntByReference;
import com.sun.jna.*;
import com.sun.jna.ptr.IntByReference;
/**
* The interface for linking to {@code openpty} via jnr-ffi
* The interface for linking to {@code openpty} via jna
*/
public interface Util {
Util INSTANCE = LibraryLoader.create(Util.class).load("util");
public interface Util extends Library {
Util INSTANCE = Native.load("util", Util.class);
/**
* See the Linux manual pages
@ -36,6 +34,6 @@ public interface Util {
* @param winp (purposefully undocumented here)
* @return (purposefully undocumented here)
*/
int openpty(@Out IntByReference amaster, @Out IntByReference aslave, @Out Pointer name,
@Out Pointer termp, @Out Pointer winp);
int openpty(IntByReference amaster, IntByReference aslave, Pointer name,
Pointer termp, Pointer winp) throws LastErrorException;
}

View file

@ -681,7 +681,7 @@ public class DebuggerCoordinates {
catch (Exception e) {
Msg.error(DebuggerCoordinates.class,
"Could not restore invalid time specification: " + timeSpec);
time = null;
time = TraceSchedule.ZERO;
}
Integer frame = null;
if (coordState.hasValue(KEY_FRAME)) {