Add support for symbol table in .com files

This change fixes minor bugs and adds a feature, which lets us store the
ELF symbol table, inside the ZIP directory. We use the path /zip/.symtab
which can be safely removed using a zip editing tool, to make the binary
smaller after compilation. This supplements the existing method of using
a separate .com.dbg file, which is still supported. The intent is people
don't always know that it's a good idea to download the debug file. It's
not great having someone's first experience be a crash report, that only
has numbers rather than symbols. This will help fix that!
This commit is contained in:
Justine Tunney 2022-03-23 06:31:55 -07:00
parent 393ca4be40
commit 23b72eb617
61 changed files with 963 additions and 510 deletions

View file

@ -41,8 +41,8 @@ textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
if ((who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)(
(who == RUSAGE_SELF ? GetCurrentProcess : GetCurrentThread)(),
&CreationFileTime, &ExitFileTime, &KernelFileTime, &UserFileTime)) {
usage->ru_utime = FileTimeToTimeVal(UserFileTime);
usage->ru_stime = FileTimeToTimeVal(KernelFileTime);
usage->ru_utime = WindowsDurationToTimeVal(ReadFileTime(UserFileTime));
usage->ru_stime = WindowsDurationToTimeVal(ReadFileTime(KernelFileTime));
} else {
return __winerr();
}

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sysv/errfuns.h"
@ -29,11 +30,16 @@
* @return 0 on success, or -1 w/ errno
*/
int getrusage(int who, struct rusage *usage) {
if (who == 99) return einval();
if (IsAsan() && !__asan_is_valid(usage, sizeof(*usage))) return efault();
if (!IsWindows()) {
return sys_getrusage(who, usage);
int rc;
if (who == 99) {
rc = einval();
} else if (IsAsan() && !__asan_is_valid(usage, sizeof(*usage))) {
rc = efault();
} else if (!IsWindows()) {
rc = sys_getrusage(who, usage);
} else {
return sys_getrusage_nt(who, usage);
rc = sys_getrusage_nt(who, usage);
}
STRACE("getrusage(%d, %p) → %d% m", who, usage, rc);
return rc;
}

View file

@ -31,41 +31,47 @@
#include "libc/sysv/errfuns.h"
textwindows int ioctl_tiocgwinsz_nt(struct Fd *fd, struct winsize *ws) {
int i;
int i, e;
uint32_t mode;
struct Fd *fds[3];
struct NtStartupInfo startinfo;
struct NtConsoleScreenBufferInfoEx sbinfo;
if (!ws) return efault();
fds[0] = fd, fds[1] = g_fds.p + 1, fds[2] = g_fds.p + 0;
GetStartupInfo(&startinfo);
for (i = 0; i < ARRAYLEN(fds); ++i) {
if (fds[i]->kind == kFdFile || fds[i]->kind == kFdConsole) {
if (GetConsoleMode(fds[i]->handle, &mode)) {
bzero(&sbinfo, sizeof(sbinfo));
sbinfo.cbSize = sizeof(sbinfo);
if (GetConsoleScreenBufferInfoEx(fds[i]->handle, &sbinfo)) {
ws->ws_col = sbinfo.srWindow.Right - sbinfo.srWindow.Left + 1;
ws->ws_row = sbinfo.srWindow.Bottom - sbinfo.srWindow.Top + 1;
ws->ws_xpixel = 0;
ws->ws_ypixel = 0;
return 0;
} else if (startinfo.dwFlags & kNtStartfUsecountchars) {
ws->ws_col = startinfo.dwXCountChars;
ws->ws_row = startinfo.dwYCountChars;
ws->ws_xpixel = 0;
ws->ws_ypixel = 0;
return 0;
e = errno;
if (ws) {
fds[0] = fd, fds[1] = g_fds.p + 1, fds[2] = g_fds.p + 0;
GetStartupInfo(&startinfo);
for (i = 0; i < ARRAYLEN(fds); ++i) {
if (fds[i]->kind == kFdFile || fds[i]->kind == kFdConsole) {
if (GetConsoleMode(fds[i]->handle, &mode)) {
bzero(&sbinfo, sizeof(sbinfo));
sbinfo.cbSize = sizeof(sbinfo);
if (GetConsoleScreenBufferInfoEx(fds[i]->handle, &sbinfo)) {
ws->ws_col = sbinfo.srWindow.Right - sbinfo.srWindow.Left + 1;
ws->ws_row = sbinfo.srWindow.Bottom - sbinfo.srWindow.Top + 1;
ws->ws_xpixel = 0;
ws->ws_ypixel = 0;
errno = e;
return 0;
} else if (startinfo.dwFlags & kNtStartfUsecountchars) {
ws->ws_col = startinfo.dwXCountChars;
ws->ws_row = startinfo.dwYCountChars;
ws->ws_xpixel = 0;
ws->ws_ypixel = 0;
errno = e;
return 0;
} else {
__winerr();
}
} else {
__winerr();
STRACE("%s() failed %m", "GetConsoleMode");
enotty();
}
} else {
STRACE("%s() failed %m", "GetConsoleMode");
enotty();
ebadf();
}
} else {
ebadf();
}
} else {
efault();
}
return -1;
}

View file

@ -23,6 +23,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/mem/alloca.h"
@ -42,22 +43,6 @@
#define KERN_PROC_PATHNAME_FREEBSD 12
#define KERN_PROC_PATHNAME_NETBSD 5
/**
* Absolute path of executable.
*
* This variable is initialized automatically at startup. The path is
* basically `argv[0]` except some extra vetting is done to provide
* stronger assurance that the path can be counted upon to exist.
*
* For example, if your program is executed as a relative path and then
* your program calls `chdir()`, then `argv[0]` will be incorrect; but
* `program_executable_name` will work, because it prefixed `getcwd()`
* early in the initialization phase.
*
* @see GetInterpreterExecutableName()
* @see program_invocation_short_name
* @see program_invocation_name
*/
char program_executable_name[SIZE];
static textwindows bool GetNtExePath(char executable[SIZE]) {
@ -88,13 +73,15 @@ static textwindows bool GetNtExePath(char executable[SIZE]) {
return true;
}
static textstartup void GetProgramExecutableName(char executable[SIZE],
char *argv0, intptr_t *auxv) {
static void ReadProgramExecutableName(char executable[SIZE], char *argv0,
uintptr_t *auxv) {
size_t m;
ssize_t n;
int cmd[4];
char *p, *t;
if (IsWindows() && GetNtExePath(executable)) return;
if (IsWindows() && GetNtExePath(executable)) {
return;
}
for (p = 0; *auxv; auxv += 2) {
if (*auxv == AT_EXECFN) {
p = (char *)auxv[1];
@ -119,19 +106,37 @@ static textstartup void GetProgramExecutableName(char executable[SIZE],
executable[n] = 0;
}
textstartup void program_executable_name_init(int argc, char **argv,
char **envp, intptr_t *auxv) {
/**
* Returns absolute path of executable.
*
* This variable is initialized automatically at startup. The path is
* basically `argv[0]` except some extra vetting is done to provide
* stronger assurance that the path can be counted upon to exist.
*
* For example, if your program is executed as a relative path and then
* your program calls `chdir()`, then `argv[0]` will be incorrect; but
* `program_executable_name` will work, because it prefixed `getcwd()`
* early in the initialization phase.
*
* @see GetInterpreterExecutableName()
* @see program_invocation_short_name
* @see program_invocation_name
*/
char *GetProgramExecutableName(void) {
int e;
static bool once;
char executable[SIZE];
if (!cmpxchg(&once, 0, 1)) return;
e = errno;
GetProgramExecutableName(executable, argv[0], auxv);
errno = e;
__stpcpy(program_executable_name, executable);
STRACE("program_executable_name → %#s", program_executable_name);
if (!once) {
e = errno;
ReadProgramExecutableName(executable, __argv[0], __auxv);
errno = e;
__stpcpy(program_executable_name, executable);
once = true;
}
return program_executable_name;
}
// try our best to memoize it before a chdir() happens
const void *const program_executable_name_init_ctor[] initarray = {
program_executable_name_init,
GetProgramExecutableName,
};

View file

@ -19,6 +19,7 @@
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
@ -39,22 +40,26 @@
* @asyncsignalsafe
*/
ssize_t read(int fd, void *buf, size_t size) {
ssize_t rc;
if (fd >= 0) {
if (IsAsan() && !__asan_is_valid(buf, size)) return efault();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return weaken(__zipos_read)(
if (IsAsan() && !__asan_is_valid(buf, size)) {
rc = efault();
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = weaken(__zipos_read)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle,
&(struct iovec){buf, size}, 1, -1);
} else if (!IsWindows() && !IsMetal()) {
return sys_read(fd, buf, size);
rc = sys_read(fd, buf, size);
} else if (fd >= g_fds.n) {
return ebadf();
rc = ebadf();
} else if (IsMetal()) {
return sys_readv_metal(g_fds.p + fd, &(struct iovec){buf, size}, 1);
rc = sys_readv_metal(g_fds.p + fd, &(struct iovec){buf, size}, 1);
} else {
return sys_readv_nt(g_fds.p + fd, &(struct iovec){buf, size}, 1);
rc = sys_readv_nt(g_fds.p + fd, &(struct iovec){buf, size}, 1);
}
} else {
return einval();
rc = einval();
}
STRACE("read(%d, %p, %'zu) → %'zd% m", fd, buf, size, rc);
return rc;
}

View file

@ -19,6 +19,7 @@
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sock/internal.h"
@ -32,21 +33,25 @@
* @asyncsignalsafe
*/
ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
ssize_t rc;
if (fd >= 0 && iovlen >= 0) {
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) return efault();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return weaken(__zipos_read)(
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) {
rc = efault();
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = weaken(__zipos_read)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
} else if (!IsWindows() && !IsMetal()) {
return sys_readv(fd, iov, iovlen);
rc = sys_readv(fd, iov, iovlen);
} else if (fd >= g_fds.n) {
return ebadf();
rc = ebadf();
} else if (IsMetal()) {
return sys_readv_metal(g_fds.p + fd, iov, iovlen);
rc = sys_readv_metal(g_fds.p + fd, iov, iovlen);
} else {
return sys_readv_nt(g_fds.p + fd, iov, iovlen);
rc = sys_readv_nt(g_fds.p + fd, iov, iovlen);
}
} else {
return einval();
rc = einval();
}
STRACE("readv(%d, %p, %d) → %'zd% m", fd, iov, iovlen, rc);
return rc;
}

View file

@ -18,6 +18,7 @@
*/
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
@ -37,22 +38,26 @@
* @asyncsignalsafe
*/
ssize_t write(int fd, const void *buf, size_t size) {
ssize_t rc;
if (fd >= 0) {
if (IsAsan() && !__asan_is_valid(buf, size)) return efault();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return weaken(__zipos_write)(
if (IsAsan() && !__asan_is_valid(buf, size)) {
rc = efault();
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = weaken(__zipos_write)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle,
&(struct iovec){buf, size}, 1, -1);
} else if (!IsWindows() && !IsMetal()) {
return sys_write(fd, buf, size);
rc = sys_write(fd, buf, size);
} else if (fd >= g_fds.n) {
return ebadf();
rc = ebadf();
} else if (IsMetal()) {
return sys_writev_metal(g_fds.p + fd, &(struct iovec){buf, size}, 1);
rc = sys_writev_metal(g_fds.p + fd, &(struct iovec){buf, size}, 1);
} else {
return sys_writev_nt(fd, &(struct iovec){buf, size}, 1);
rc = sys_writev_nt(fd, &(struct iovec){buf, size}, 1);
}
} else {
return einval();
rc = einval();
}
STRACE("write(%d, %p, %'zu) → %'zd% m", fd, buf, size, rc);
return rc;
}

View file

@ -19,6 +19,7 @@
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/intrin/asan.internal.h"
#include "libc/sock/internal.h"
#include "libc/sysv/errfuns.h"
@ -35,21 +36,25 @@
* @return number of bytes actually handed off, or -1 w/ errno
*/
ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
ssize_t rc;
if (fd >= 0 && iovlen >= 0) {
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) return efault();
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return weaken(__zipos_write)(
if (IsAsan() && !__asan_is_valid_iov(iov, iovlen)) {
rc = efault();
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = weaken(__zipos_write)(
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
} else if (!IsWindows() && !IsMetal()) {
return sys_writev(fd, iov, iovlen);
rc = sys_writev(fd, iov, iovlen);
} else if (fd >= g_fds.n) {
return ebadf();
rc = ebadf();
} else if (IsMetal()) {
return sys_writev_metal(g_fds.p + fd, iov, iovlen);
rc = sys_writev_metal(g_fds.p + fd, iov, iovlen);
} else {
return sys_writev_nt(fd, iov, iovlen);
rc = sys_writev_nt(fd, iov, iovlen);
}
} else {
return einval();
rc = einval();
}
STRACE("writev(%d, %p, %d) → %'zd% m", fd, iov, iovlen, rc);
return rc;
}