diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/linux/Err.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/linux/Err.java new file mode 100644 index 0000000000..a52d24f1e5 --- /dev/null +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/linux/Err.java @@ -0,0 +1,31 @@ +/* ### + * 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.LastErrorException; +import com.sun.jna.Native; + +public interface Err { + PosixC BARE_POSIX = PosixC.BARE; + + static int checkLt0(int result) { + if (result < 0) { + int errno = Native.getLastError(); + throw new LastErrorException("[" + errno + "] " + BARE_POSIX.strerror(errno)); + } + return result; + } +} diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/linux/LinuxPty.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/linux/LinuxPty.java index fd920a1d4f..45b701e597 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/linux/LinuxPty.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/linux/LinuxPty.java @@ -27,13 +27,6 @@ public class LinuxPty implements Pty { static final PosixC LIB_POSIX = PosixC.INSTANCE; - static void checkErr(int result) { - if (result < 0) { - int errno = Native.getLastError(); - throw new LastErrorException("[" + errno + "] " + LIB_POSIX.strerror(errno)); - } - } - private final int aparent; private final int achild; //private final String name; @@ -47,7 +40,7 @@ public class LinuxPty implements Pty { IntByReference p = new IntByReference(); IntByReference c = new IntByReference(); Memory n = new Memory(1024); - checkErr(Util.INSTANCE.openpty(p, c, n, null, null)); + Util.INSTANCE.openpty(p, c, n, null, null); return new LinuxPty(p.getValue(), c.getValue(), n.getString(0)); } diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/linux/PosixC.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/linux/PosixC.java index 32890a55d7..f2baf01b9f 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/linux/PosixC.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/linux/PosixC.java @@ -16,7 +16,6 @@ package agent.gdb.pty.linux; import com.sun.jna.*; -import com.sun.jna.platform.linux.LibC; /** * Interface for POSIX functions in libc @@ -24,22 +23,69 @@ import com.sun.jna.platform.linux.LibC; *
* The functions are not documented here. Instead see the POSIX manual pages. */ -public interface PosixC extends LibC { - PosixC INSTANCE = Native.load("c", PosixC.class); +public interface PosixC extends Library { + /** + * The bare library without error handling + * + * @see Util#BARE + */ + PosixC BARE = Native.load("c", PosixC.class); + + PosixC INSTANCE = new PosixC() { + @Override + public String strerror(int errnum) { + return BARE.strerror(errnum); + } + + @Override + public int close(int fd) { + return Err.checkLt0(BARE.close(fd)); + } + + @Override + public int read(int fd, Pointer buf, int len) { + return Err.checkLt0(BARE.read(fd, buf, len)); + } + + @Override + public int write(int fd, Pointer buf, int i) { + return Err.checkLt0(BARE.write(fd, buf, i)); + } + + @Override + public int setsid() { + return Err.checkLt0(BARE.setsid()); + } + + @Override + public int open(String path, int mode, int flags) { + return Err.checkLt0(BARE.open(path, mode, flags)); + } + + @Override + public int dup2(int oldfd, int newfd) { + return Err.checkLt0(BARE.dup2(oldfd, newfd)); + } + + @Override + public int execv(String path, String[] argv) { + return Err.checkLt0(BARE.execv(path, argv)); + } + }; String strerror(int errnum); - int close(int fd) throws LastErrorException; + int close(int fd); - int read(int fd, Pointer buf, int len) throws LastErrorException; + int read(int fd, Pointer buf, int len); - int write(int fd, Pointer buf, int i) throws LastErrorException; + int write(int fd, Pointer buf, int i); - int setsid() throws LastErrorException; + int setsid(); - int open(String path, int mode, int flags) throws LastErrorException; + int open(String path, int mode, int flags); - int dup2(int oldfd, int newfd) throws LastErrorException; + int dup2(int oldfd, int newfd); - int execv(String path, String[] argv) throws LastErrorException; + int execv(String path, String[] argv); } diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/linux/Util.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/linux/Util.java index c8f0b44d29..ef2bf9f290 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/linux/Util.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/linux/Util.java @@ -25,22 +25,38 @@ import com.sun.jna.ptr.IntByReference; * See the UNIX manual pages */ public interface Util extends Library { - Util INSTANCE = Native.load("util", Util.class); /** - * NOTE: We cannot use {@link LastErrorException} here, because the idiom it applies is not - * correct for errno on UNIX. See https://man7.org/linux/man-pages/man3/errno.3.html, in - * particular: + * The bare library without error handling + * + *
+ * For error handling, use {@link #INSTANCE}, or check for errors manually, perhaps using + * {@link Err}. + * + *
+ * We cannot just use {@code throws }{@link LastErrorException} to handle errors, because the + * idiom it applies is not correct for errno on UNIX. See + * https://man7.org/linux/man-pages/man3/errno.3.html, in particular: * *
The value in errno is significant only when the return value of the call * indicated an error (i.e., -1 from most system calls; -1 or NULL from most library functions); * a function that succeeds is allowed to change errno.* + *
* This actually happens on our test setup when invoking the native {@code openpty} from a * Docker container. It returns 0, but sets errno. JNA will incorrectly interpret this as - * failure. Thus, callers to this function must check the return value and handle the error - * manually. + * failure. */ + Util BARE = Native.load("util", Util.class); + + Util INSTANCE = new Util() { + @Override + public int openpty(IntByReference amaster, IntByReference aslave, Pointer name, + Pointer termp, Pointer winp) { + return Err.checkLt0(BARE.openpty(amaster, aslave, name, termp, winp)); + } + }; + int openpty(IntByReference amaster, IntByReference aslave, Pointer name, Pointer termp, Pointer winp); }