From 866b21a151d83b55874ccdc354d9d467ba8aac7b Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Sat, 16 Jul 2022 11:51:26 -0700 Subject: [PATCH] Get redbean -X running in blinkenlights again This change improves the loading of APE executables in Blinkenlights and adds some system call wrappers that were previous missing. --- libc/log/backtrace2.c | 11 +++++-- tool/build/lib/loader.c | 50 +++++++++++++++++++++++++++++++ tool/build/lib/syscall.c | 64 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 120 insertions(+), 5 deletions(-) diff --git a/libc/log/backtrace2.c b/libc/log/backtrace2.c index aab207fc9..1b8b13a90 100644 --- a/libc/log/backtrace2.c +++ b/libc/log/backtrace2.c @@ -115,8 +115,15 @@ static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) { j += uint64toarray_radix16(addr - 1, buf + j) + 1; } argv[i++] = NULL; - if (sys_pipe(pipefds) == -1) return -1; - if (!(pid = vfork())) { + if (sys_pipe(pipefds) == -1) { + return -1; + } + if ((pid = vfork()) == -1) { + sys_close(pipefds[0]); + sys_close(pipefds[1]); + return -1; + } + if (!pid) { sys_dup2(pipefds[1], 1); if (pipefds[0] != 1) sys_close(pipefds[0]); if (pipefds[1] != 1) sys_close(pipefds[1]); diff --git a/tool/build/lib/loader.c b/tool/build/lib/loader.c index ac204c7c5..55021743d 100644 --- a/tool/build/lib/loader.c +++ b/tool/build/lib/loader.c @@ -16,6 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/bits/bits.h" #include "libc/bits/popcnt.h" #include "libc/calls/calls.h" #include "libc/calls/struct/stat.h" @@ -28,6 +29,7 @@ #include "libc/runtime/pc.internal.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" +#include "libc/str/str.h" #include "libc/sysv/consts/fileno.h" #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/o.h" @@ -135,11 +137,53 @@ static void BootProgram(struct Machine *m, struct Elf *elf, size_t codesize) { } } +static int GetElfHeader(char ehdr[hasatleast 64], const char *prog, + const char *image) { + char *p; + int c, i; + for (p = image; p < image + 4096; ++p) { + if (READ64LE(p) != READ64LE("printf '")) continue; + for (i = 0, p += 8; p + 3 < image + 4096 && (c = *p++) != '\'';) { + if (c == '\\') { + if ('0' <= *p && *p <= '7') { + c = *p++ - '0'; + if ('0' <= *p && *p <= '7') { + c *= 8; + c += *p++ - '0'; + if ('0' <= *p && *p <= '7') { + c *= 8; + c += *p++ - '0'; + } + } + } + } + if (i < 64) { + ehdr[i++] = c; + } else { + WARNF("%s: ape printf elf header too long\n", prog); + return -1; + } + } + if (i != 64) { + WARNF("%s: ape printf elf header too short\n", prog); + return -1; + } + if (READ32LE(ehdr) != READ32LE("\177ELF")) { + WARNF("%s: ape printf elf header didn't have elf magic\n", prog); + return -1; + } + return 0; + } + WARNF("%s: printf statement not found in first 4096 bytes\n", prog); + return -1; +} + void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars, struct Elf *elf) { int fd; ssize_t rc; int64_t sp; + char ehdr[64]; struct stat st; size_t i, mappedsize; DCHECK_NOTNULL(prog); @@ -169,6 +213,12 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars, elf->ehdr = (void *)elf->map; elf->size = elf->mapsize; LoadElf(m, elf); + } else if (READ64LE(elf->map) == READ64LE("MZqFpD='") && + !GetElfHeader(ehdr, prog, elf->map)) { + memcpy(elf->map, ehdr, 64); + elf->ehdr = (void *)elf->map; + elf->size = elf->mapsize; + LoadElf(m, elf); } else { elf->base = IMAGE_BASE_VIRTUAL; elf->ehdr = NULL; diff --git a/tool/build/lib/syscall.c b/tool/build/lib/syscall.c index 50ce1f1c7..225b225c9 100644 --- a/tool/build/lib/syscall.c +++ b/tool/build/lib/syscall.c @@ -212,7 +212,11 @@ static int XlatSocketOptname(int x) { XLAT(5, SO_DONTROUTE); XLAT(7, SO_SNDBUF); XLAT(8, SO_RCVBUF); + XLAT(1, TCP_NODELAY); + XLAT(12, TCP_QUICKACK); XLAT(13, SO_LINGER); + XLAT(23, TCP_FASTOPEN); + XLAT(30, TCP_FASTOPEN_CONNECT); default: return einval(); } @@ -764,6 +768,60 @@ static int OpSetsockopt(struct Machine *m, int fd, int level, int optname, return rc; } +static int OpGetsockopt(struct Machine *m, int fd, int level, int optname, + int64_t optvaladdr, int64_t optsizeaddr) { + int rc; + void *optval; + uint32_t optsize; + if ((level = XlatSocketLevel(level)) == -1) return -1; + if ((optname = XlatSocketOptname(optname)) == -1) return -1; + if ((fd = XlatFd(m, fd)) == -1) return -1; + if (!optvaladdr) { + rc = getsockopt(fd, level, optname, 0, 0); + } else { + VirtualSendRead(m, &optsize, optsizeaddr, sizeof(optsize)); + if (!(optval = malloc(optsize))) return -1; + if ((rc = getsockopt(fd, level, optname, optval, &optsize)) != -1) { + VirtualRecvWrite(m, optvaladdr, optval, optsize); + VirtualRecvWrite(m, optsizeaddr, &optsize, sizeof(optsize)); + } + free(optval); + } + return rc; +} + +static int OpGetsockname(struct Machine *m, int fd, int64_t addraddr, + int64_t addrlenaddr) { + int rc; + void *addr; + uint32_t addrlen; + if ((fd = XlatFd(m, fd)) == -1) return -1; + VirtualSendRead(m, &addrlen, addrlenaddr, sizeof(addrlen)); + if (!(addr = malloc(addrlen))) return -1; + if ((rc = getsockname(fd, addr, &addrlen)) != -1) { + VirtualRecvWrite(m, addraddr, addr, addrlen); + VirtualRecvWrite(m, addrlenaddr, &addrlen, sizeof(addrlen)); + } + free(addr); + return rc; +} + +static int OpGetpeername(struct Machine *m, int fd, int64_t addraddr, + int64_t addrlenaddr) { + int rc; + void *addr; + uint32_t addrlen; + if ((fd = XlatFd(m, fd)) == -1) return -1; + VirtualSendRead(m, &addrlen, addrlenaddr, sizeof(addrlen)); + if (!(addr = malloc(addrlen))) return -1; + if ((rc = getpeername(fd, addr, &addrlen)) != -1) { + VirtualRecvWrite(m, addraddr, addr, addrlen); + VirtualRecvWrite(m, addrlenaddr, &addrlen, sizeof(addrlen)); + } + free(addr); + return rc; +} + static ssize_t OpRead(struct Machine *m, int fd, int64_t addr, size_t size) { ssize_t rc; struct Iovs iv; @@ -1402,10 +1460,10 @@ void OpSyscall(struct Machine *m, uint32_t rde) { SYSCALL(0x030, OpShutdown(m, di, si)); SYSCALL(0x031, OpBind(m, di, si, dx)); SYSCALL(0x032, OpListen(m, di, si)); - SYSCALL(0x033, getsockname(di, PNN(si), PNN(dx))); - SYSCALL(0x034, getpeername(di, PNN(si), PNN(dx))); + SYSCALL(0x033, OpGetsockname(m, di, si, dx)); + SYSCALL(0x034, OpGetpeername(m, di, si, dx)); SYSCALL(0x036, OpSetsockopt(m, di, si, dx, r0, r8)); - SYSCALL(0x037, getsockopt(di, si, dx, PNN(r0), PNN(r8))); + SYSCALL(0x037, OpGetsockopt(m, di, si, dx, r0, r8)); SYSCALL(0x039, OpFork(m)); SYSCALL(0x03B, OpExecve(m, di, si, dx)); SYSCALL(0x03D, OpWait4(m, di, si, dx, r0));