mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-08-28 05:20:21 +00:00
Merge remote-tracking branch 'origin/GP-2619_Dan_linuxPtyPort2Jna--SQUASHED'
This commit is contained in:
commit
f2d3b7dfaa
|
@ -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')
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
Loading…
Reference in a new issue