Make improvements

- Fix build flakes
- Polyfill SIGWINCH on Windows
- Fix an execve issue on Windows
- Make strerror show more information
- Improve cmd.exe setup/teardown on Windows
- Support bracketed paste mode in Blinkenlights
- Show keyboard shortcuts in Blinkenlights status bar
- Fixed copy_file_range() and copyfile() w/ zip filesystem
- Size optimize GetDosArgv() to keep life.com 12kb in size
- Improve Blinkenlights ability to load weird ELF executables
- Fix program_executable_name and add GetInterpreterExecutableName
- Make Python in tiny mode fail better if docstrings are requested
- Update Python test exclusions in tiny* modes such as tinylinux
- Add bulletproof unbreakable kprintf() troubleshooting function
- Remove "oldskool" keyword from ape.S for virus scanners
- Fix issue that caused backtraces to not print sometimes
- Improve Blinkenlights serial uart character i/o
- Make clock_gettime() not clobber errno on xnu
- Improve sha256 cpuid check for old computers
- Integrate some bestline linenoise fixes
- Show runit process names better in htop
- Remove SIGPIPE from ShowCrashReports()
- Make realpath() not clobber errno
- Avoid attaching GDB on non-Linux
- Improve img.com example
This commit is contained in:
Justine Tunney 2022-03-16 13:33:13 -07:00
parent 2a938b3eaa
commit b45d50b690
194 changed files with 4881 additions and 2966 deletions

View file

@ -14,7 +14,7 @@ forceinline void *bisect(const void *k, const void *data, size_t n, size_t size,
r = n - 1;
p = data;
while (l <= r) {
m = (l + r) >> 1;
m = (l & r) + ((l ^ r) >> 1);
c = cmp(k, p + m * size, arg);
if (c > 0) {
l = m + 1;

View file

@ -19,7 +19,7 @@
#include "libc/calls/math.h"
/**
* Adds two microsecond timestamps.
* Adds two nanosecond timestamps.
*/
struct timespec AddTimespec(struct timespec x, struct timespec y) {
x.tv_sec += y.tv_sec;

View file

@ -40,13 +40,18 @@
* @asyncsignalsafe
*/
int clock_gettime(int clockid, struct timespec *ts) {
int rc;
int rc, e;
axdx_t ad;
if (!ts) return efault();
if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) return efault();
if (clockid == -1) return einval();
if (!IsWindows()) {
if ((rc = sys_clock_gettime(clockid, ts)) == -1 && errno == ENOSYS) {
if (!ts) {
rc = efault();
} else if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) {
rc = efault();
} else if (clockid == -1) {
rc = einval();
} else if (!IsWindows()) {
e = errno;
if ((rc = sys_clock_gettime(clockid, ts))) {
errno = e;
ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL);
assert(ad.ax != -1);
if (SupportsXnu() && ad.ax) {
@ -56,8 +61,9 @@ int clock_gettime(int clockid, struct timespec *ts) {
ts->tv_nsec *= 1000;
rc = 0;
}
return rc;
} else {
return sys_clock_gettime_nt(clockid, ts);
rc = sys_clock_gettime_nt(clockid, ts);
}
/* TODO(jart): Add get_clock_gettime() so we can STRACE() */
return rc;
}

View file

@ -16,60 +16,69 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/errfuns.h"
static noasan bool EndsWithIgnoreCase(const char *p, size_t n, const char *s) {
size_t i, m;
m = __strlen(s);
if (n >= m) {
for (i = n - m; i < n; ++i) {
if (kToLower[p[i] & 255] != (*s++ & 255)) {
return false;
}
}
return true;
} else {
return false;
}
static noasan bool IsExePath(const char *s, size_t n) {
return n >= 4 && (READ32LE(s + n - 4) == READ32LE(".exe") ||
READ32LE(s + n - 4) == READ32LE(".EXE"));
}
static noasan bool IsComPath(const char *s, size_t n) {
return n >= 4 && (READ32LE(s + n - 4) == READ32LE(".com") ||
READ32LE(s + n - 4) == READ32LE(".COM"));
}
static noasan bool IsComDbgPath(const char *s, size_t n) {
return n >= 8 && (READ64LE(s + n - 8) == READ64LE(".com.dbg") ||
READ64LE(s + n - 8) == READ64LE(".COM.DBG"));
}
static noasan bool AccessCommand(const char *name,
char path[hasatleast PATH_MAX], size_t namelen,
const char *suffix, size_t pathlen) {
int *err, const char *suffix, size_t pathlen) {
size_t suffixlen;
suffixlen = __strlen(suffix);
if (pathlen + 1 + namelen + suffixlen + 1 > PATH_MAX) return -1;
suffixlen = strlen(suffix);
if (pathlen + 1 + namelen + suffixlen + 1 > PATH_MAX) return false;
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) {
path[pathlen] = !IsWindows() ? '/'
: __memchr(path, '\\', pathlen) ? '\\'
: '/';
path[pathlen] = !IsWindows() ? '/'
: memchr(path, '\\', pathlen) ? '\\'
: '/';
pathlen++;
}
__repmovsb(path + pathlen, name, namelen);
__repmovsb(path + pathlen + namelen, suffix, suffixlen + 1);
return isexecutable(path);
memcpy(path + pathlen, name, namelen);
memcpy(path + pathlen + namelen, suffix, suffixlen + 1);
if (!access(path, X_OK)) return true;
if (errno == EACCES || *err != EACCES) *err = errno;
return false;
}
static noasan bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
size_t namelen, const char *suffix) {
size_t namelen, int *err, const char *suffix) {
char sep;
size_t i;
const char *p;
p = firstnonnull(emptytonull(getenv("PATH")), "/bin:/usr/local/bin:/usr/bin");
if (!(p = getenv("PATH"))) p = "/bin:/usr/local/bin:/usr/bin";
sep = IsWindows() && strchr(p, ';') ? ';' : ':';
for (;;) {
for (i = 0; p[i] && p[i] != ':' && p[i] != ';'; ++i) {
for (i = 0; p[i] && p[i] != sep; ++i) {
if (i < PATH_MAX) {
path[i] = p[i];
}
}
if (AccessCommand(name, path, namelen, suffix, i)) {
if (AccessCommand(name, path, namelen, err, suffix, i)) {
return true;
}
if (p[i] == ':' || p[i] == ';') {
if (p[i] == sep) {
p += i + 1;
} else {
break;
@ -80,19 +89,37 @@ static noasan bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
static noasan bool FindCommand(const char *name,
char pathbuf[hasatleast PATH_MAX],
size_t namelen, const char *suffix) {
if (memchr(name, '/', namelen) || memchr(name, '\\', namelen)) {
size_t namelen, bool priorityonly,
const char *suffix, int *err) {
if (priorityonly &&
(memchr(name, '/', namelen) || memchr(name, '\\', namelen))) {
pathbuf[0] = 0;
return AccessCommand(name, pathbuf, namelen, suffix, 0);
return AccessCommand(name, pathbuf, namelen, err, suffix, 0);
}
return ((IsWindows() &&
(AccessCommand(name, pathbuf, namelen, suffix,
stpcpy(pathbuf, kNtSystemDirectory) - pathbuf) ||
AccessCommand(name, pathbuf, namelen, suffix,
stpcpy(pathbuf, kNtWindowsDirectory) - pathbuf) ||
AccessCommand(name, pathbuf, namelen, suffix,
stpcpy(pathbuf, ".") - pathbuf))) ||
SearchPath(name, pathbuf, namelen, suffix));
if (IsWindows() && priorityonly) {
return AccessCommand(name, pathbuf, namelen, err, suffix,
stpcpy(pathbuf, kNtSystemDirectory) - pathbuf) ||
AccessCommand(name, pathbuf, namelen, err, suffix,
stpcpy(pathbuf, kNtWindowsDirectory) - pathbuf);
}
return (IsWindows() && AccessCommand(name, pathbuf, namelen, err, suffix,
stpcpy(pathbuf, ".") - pathbuf)) ||
SearchPath(name, pathbuf, namelen, err, suffix);
}
static noasan bool FindVerbatim(const char *name,
char pathbuf[hasatleast PATH_MAX],
size_t namelen, bool priorityonly, int *err) {
return FindCommand(name, pathbuf, namelen, priorityonly, "", err);
}
static noasan bool FindSuffixed(const char *name,
char pathbuf[hasatleast PATH_MAX],
size_t namelen, bool priorityonly, int *err) {
return !IsExePath(name, namelen) && !IsComPath(name, namelen) &&
!IsComDbgPath(name, namelen) &&
(FindCommand(name, pathbuf, namelen, priorityonly, ".com", err) ||
FindCommand(name, pathbuf, namelen, priorityonly, ".exe", err));
}
/**
@ -105,28 +132,33 @@ static noasan bool FindCommand(const char *name,
* @vforksafe
*/
noasan char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
int olderr;
int e, f;
char *res;
size_t namelen;
res = 0;
if (!name) {
efault();
return 0;
}
if (!(namelen = __strlen(name))) {
} else if (!(namelen = strlen(name))) {
enoent();
return 0;
}
if (namelen + 1 > PATH_MAX) {
} else if (namelen + 1 > PATH_MAX) {
enametoolong();
return 0;
}
if (FindCommand(name, pathbuf, namelen, "") ||
(!EndsWithIgnoreCase(name, namelen, ".exe") &&
!EndsWithIgnoreCase(name, namelen, ".com") &&
!EndsWithIgnoreCase(name, namelen, ".com.dbg") &&
(FindCommand(name, pathbuf, namelen, ".com") ||
FindCommand(name, pathbuf, namelen, ".exe")))) {
return pathbuf;
} else {
return 0;
e = errno;
f = ENOENT;
if ((IsWindows() && (FindSuffixed(name, pathbuf, namelen, true, &f) ||
FindSuffixed(name, pathbuf, namelen, true, &f) ||
FindVerbatim(name, pathbuf, namelen, false, &f) ||
FindVerbatim(name, pathbuf, namelen, false, &f))) ||
(!IsWindows() && (FindVerbatim(name, pathbuf, namelen, true, &f) ||
FindSuffixed(name, pathbuf, namelen, true, &f) ||
FindVerbatim(name, pathbuf, namelen, false, &f) ||
FindSuffixed(name, pathbuf, namelen, false, &f)))) {
errno = e;
res = pathbuf;
} else {
errno = f;
}
}
SYSDEBUG("commandv(%#s, %p) → %#s% m", name, pathbuf, res);
return res;
}

View file

@ -20,6 +20,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
@ -66,12 +67,12 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
int64_t inoffset, outoffset;
int rc, srcfd, dstfd, oflags, omode;
rc = -1;
if ((srcfd = sys_openat(AT_FDCWD, src, O_RDONLY, 0)) != -1) {
if (sys_fstat(srcfd, &st) != -1) {
if ((srcfd = openat(AT_FDCWD, src, O_RDONLY, 0)) != -1) {
if (fstat(srcfd, &st) != -1) {
omode = st.st_mode & 0777;
oflags = O_WRONLY | O_CREAT;
if (flags & COPYFILE_NOCLOBBER) oflags |= O_EXCL;
if ((dstfd = sys_openat(AT_FDCWD, dst, oflags, omode)) != -1) {
if ((dstfd = openat(AT_FDCWD, dst, oflags, omode)) != -1) {
remaining = st.st_size;
ftruncate(dstfd, remaining);
inoffset = 0;
@ -86,13 +87,13 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
if (flags & COPYFILE_PRESERVE_TIMESTAMPS) {
amtime[0] = st.st_atim;
amtime[1] = st.st_mtim;
sys_utimensat(dstfd, NULL, amtime, 0);
utimensat(dstfd, NULL, amtime, 0);
}
}
rc |= sys_close(dstfd);
rc |= close(dstfd);
}
}
rc |= sys_close(srcfd);
rc |= close(srcfd);
}
return rc;
}
@ -108,7 +109,7 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
* @return 0 on success, or -1 w/ errno
*/
int copyfile(const char *src, const char *dst, int flags) {
if (!IsWindows()) {
if (!IsWindows() || startswith(src, "/zip/") || startswith(dst, "/zip/")) {
return sys_copyfile(src, dst, flags);
} else {
return sys_copyfile_nt(src, dst, flags);

View file

@ -21,6 +21,7 @@
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/libfatal.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
@ -47,17 +48,17 @@ int execve(const char *program, char *const argv[], char *const envp[]) {
return efault();
}
if (DEBUGSYS) {
__printf("SYS: execve(%s, {", program);
kprintf("SYS: execve(%s, {", program);
for (i = 0; argv[i]; ++i) {
if (i) __printf(", ");
__printf("%s", argv[i]);
if (i) kprintf(", ");
kprintf("%s", argv[i]);
}
__printf("}, {");
kprintf("}, {");
for (i = 0; envp[i]; ++i) {
if (i) __printf(", ");
__printf("%s", envp[i]);
if (i) kprintf(", ");
kprintf("%s", envp[i]);
}
__printf("})\n");
kprintf("})\n");
}
for (i = 3; i < g_fds.n; ++i) {
if (g_fds.p[i].kind != kFdEmpty && (g_fds.p[i].flags & O_CLOEXEC)) {

View file

@ -16,27 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/nt/process.h"
#include "libc/runtime/runtime.h"
static int __pid;
static int __getpid(void) {
if (!IsWindows()) {
return sys_getpid().ax;
} else {
return GetCurrentProcessId();
}
}
static void __updatepid(void) {
__pid = __getpid();
}
extern int __pid;
/**
* Returns process id.
@ -44,15 +27,11 @@ static void __updatepid(void) {
* @vforksafe
*/
int getpid(void) {
static bool once;
if (__vforked) {
return sys_getpid().ax;
int rc;
if (!__vforked) {
rc = __pid;
} else {
rc = sys_getpid().ax;
}
if (!once) {
__updatepid();
if (cmpxchg(&once, false, true)) {
atfork(__updatepid, NULL);
}
}
return __pid;
return rc;
}

View file

@ -12,6 +12,7 @@
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/winsize.h"
#include "libc/calls/ucontext.h"
#include "libc/dce.h"
#include "libc/limits.h"
@ -299,6 +300,7 @@ ssize_t sys_open_nt(int, const char *, u32, i32) nodiscard hidden;
ssize_t sys_read_nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
ssize_t sys_readlinkat_nt(int, const char *, char *, size_t) hidden;
ssize_t sys_write_nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
int ioctl_tiocgwinsz_nt(struct Fd *, struct winsize *) hidden;
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § syscalls » windows nt » support

View file

@ -25,6 +25,8 @@
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
extern bool __nomultics;
int ioctl_tcsets_nt(int, uint64_t, const struct termios *);
static int ioctl_tcsets_metal(int fd, uint64_t request,
@ -35,7 +37,7 @@ static int ioctl_tcsets_metal(int fd, uint64_t request,
static inline void *__termios2host(union metatermios *mt,
const struct termios *lt) {
if (!IsXnu() && !IsFreebsd() && !IsOpenbsd() && !IsNetbsd()) {
return lt;
return (/*unconst*/ void *)lt;
} else if (IsXnu()) {
COPY_TERMIOS(&mt->xnu, lt);
return &mt->xnu;
@ -60,23 +62,29 @@ static int ioctl_tcsets_sysv(int fd, uint64_t request,
* @see ioctl(fd, TIOCGETA{,W,F}, tio) dispatches here
*/
int ioctl_tcsets(int fd, uint64_t request, ...) {
int rc;
va_list va;
const struct termios *tio;
va_start(va, request);
tio = va_arg(va, const struct termios *);
va_end(va);
if (!tio) return efault();
if (fd >= 0) {
if (!tio) {
rc = efault();
} else if (fd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return enotty();
rc = enotty();
} else if (IsMetal()) {
return ioctl_tcsets_metal(fd, request, tio);
rc = ioctl_tcsets_metal(fd, request, tio);
} else if (!IsWindows()) {
return ioctl_tcsets_sysv(fd, request, tio);
rc = ioctl_tcsets_sysv(fd, request, tio);
} else {
return ioctl_tcsets_nt(fd, request, tio);
rc = ioctl_tcsets_nt(fd, request, tio);
}
} else {
return einval();
rc = einval();
}
if (rc != -1) {
__nomultics = !(tio->c_oflag & OPOST);
}
return rc;
}

View file

@ -27,20 +27,21 @@
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
textwindows int ioctl_tiocgwinsz_nt(int fd, struct winsize *ws) {
int i, fds[3];
textwindows int ioctl_tiocgwinsz_nt(struct Fd *fd, struct winsize *ws) {
int i;
uint32_t mode;
struct Fd *fds[3];
struct NtStartupInfo startinfo;
struct NtConsoleScreenBufferInfoEx sbinfo;
if (!ws) return efault();
fds[0] = fd, fds[1] = 1, fds[2] = 0;
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 (__isfdkind(fds[i], kFdFile) || __isfdkind(fds[i], kFdConsole)) {
if (GetConsoleMode(g_fds.p[fds[i]].handle, &mode)) {
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(g_fds.p[fds[i]].handle, &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;

View file

@ -24,8 +24,6 @@
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h"
int ioctl_tiocgwinsz_nt(int, struct winsize *);
/**
* Returns width and height of terminal.
*
@ -44,7 +42,7 @@ int ioctl_tiocgwinsz(int fd, ...) {
} else if (!IsWindows()) {
return sys_ioctl(fd, TIOCGWINSZ, ws);
} else {
return ioctl_tiocgwinsz_nt(fd, ws);
return ioctl_tiocgwinsz_nt(g_fds.p + fd, ws);
}
} else {
return einval();

View file

@ -25,8 +25,6 @@
#include "libc/nt/thunk/msabi.h"
#include "libc/sysv/consts/nr.h"
extern __msabi typeof(VirtualProtect) *const __imp_VirtualProtect;
/**
* Modifies restrictions on virtual memory address range.
*

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -16,29 +16,33 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#define ShouldUseMsabiAttribute() 1
#include "libc/calls/internal.h"
#include "libc/nexgen32e/nexgen32e.h"
#include "libc/nt/enum/status.h"
#include "libc/errno.h"
#include "libc/macros.internal.h"
#include "libc/nt/errors.h"
#include "libc/nt/nt/time.h"
#include "libc/nt/synchronization.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
textwindows int sys_nanosleep_nt(const struct timespec *req,
struct timespec *rem) {
textwindows noinstrument int sys_nanosleep_nt(const struct timespec *req,
struct timespec *rem) {
/* no function tracing because timing sensitive */
int64_t millis, hectonanos, relasleep;
if (rem) memcpy(rem, req, sizeof(*rem));
hectonanos = req->tv_sec * 10000000ull + div100int64(req->tv_nsec);
hectonanos = req->tv_sec * 10000000 + req->tv_nsec / 100;
hectonanos = MAX(1, hectonanos);
relasleep = -hectonanos;
if (NtError(NtDelayExecution(true, &relasleep))) {
millis = div10000int64(hectonanos);
if (NtError(__imp_NtDelayExecution(true, &relasleep))) {
millis = hectonanos / 10000;
millis = MAX(1, millis);
if (SleepEx(millis, true) == kNtWaitIoCompletion) {
return eintr();
if (__imp_SleepEx(millis, true) == kNtWaitIoCompletion) {
errno = EINTR;
return -1;
}
}
if (rem) bzero(rem, sizeof(*rem));
if (rem) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
}
return 0;
}

View file

@ -84,7 +84,7 @@ textwindows int ntspawn(
(block =
MapViewOfFileExNuma(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0,
blocksize, NULL, kNtNumaNoPreferredNode))) {
if (mkntcmdline(block->cmdline, prog, argv) != -1 &&
if (mkntcmdline(block->cmdline, prog, argv + 1) != -1 &&
mkntenvblock(block->envvars, envp, extravar) != -1) {
if (CreateProcess(prog16, block->cmdline, opt_lpProcessAttributes,
opt_lpThreadAttributes, bInheritHandles,

View file

@ -63,7 +63,7 @@ ssize_t preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
/*
* NT, XNU, and 2007-era Linux don't support this system call.
*/
if (!once) {
if (!__vforked && !once) {
err = errno;
rc = sys_preadv(fd, iov, iovlen, off, off);
if (rc == -1 && errno == ENOSYS) {

View file

@ -22,6 +22,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/mem/alloca.h"
@ -45,8 +46,17 @@
* Absolute path of executable.
*
* This variable is initialized automatically at startup. The path is
* guaranteed to exist, except on XNU and OpenBSD. It may be a symlink.
* It may be spoofed.
* 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];
@ -75,45 +85,31 @@ static textwindows bool GetNtExePath(char executable[SIZE]) {
}
static textstartup void GetProgramExecutableName(char executable[SIZE],
char *p) {
char *t;
char *argv0, intptr_t *auxv) {
size_t m;
ssize_t n;
int cmd[4];
ssize_t n = 0;
char *p, *t;
if (IsWindows() && GetNtExePath(executable)) return;
if (fileexists(p)) {
for (p = 0; *auxv; auxv += 2) {
if (*auxv == AT_EXECFN) {
p = (char *)auxv[1];
break;
}
}
n = 0;
if (!p) p = argv0;
if (p) {
if (!_isabspath(p)) {
if (getcwd(executable, SIZE - 1)) {
n = strlen(executable);
executable[n++] = '/';
}
}
} else if ((n = sys_readlinkat(AT_FDCWD, "/proc/self/exe", executable,
SIZE - 1)) > 0) {
executable[n] = 0;
return;
} else if ((n = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", executable,
SIZE - 1)) > 0) {
executable[n] = 0;
return;
} else if (IsFreebsd() || IsNetbsd()) {
cmd[0] = CTL_KERN;
cmd[1] = KERN_PROC;
if (IsFreebsd()) {
cmd[2] = KERN_PROC_PATHNAME_FREEBSD;
} else {
cmd[2] = KERN_PROC_PATHNAME_NETBSD;
}
cmd[3] = -1;
m = SIZE;
if (sysctl(cmd, ARRAYLEN(cmd), executable, &m, 0, 0) != -1) {
return;
}
}
if (n < 0) n = 0;
for (; *p; ++p) {
if (n + 1 < SIZE) {
executable[n++] = *p;
for (; *p; ++p) {
if (n + 1 < SIZE) {
executable[n++] = *p;
}
}
}
executable[n] = 0;
@ -121,13 +117,15 @@ static textstartup void GetProgramExecutableName(char executable[SIZE],
textstartup void program_executable_name_init(int argc, char **argv,
char **envp, intptr_t *auxv) {
int e;
static bool once;
char executable[SIZE];
if (!cmpxchg(&once, 0, 1)) return;
__stpcpy(program_executable_name, argv[0]);
GetProgramExecutableName(executable, argv[0]);
e = errno;
GetProgramExecutableName(executable, argv[0], auxv);
errno = e;
__stpcpy(program_executable_name, executable);
SYSDEBUG("GetProgramExecutableName() -> %s", program_executable_name);
SYSDEBUG("program_executable_name → %#s", program_executable_name);
}
const void *const program_executable_name_init_ctor[] initarray = {

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/errno.h"
@ -45,6 +46,7 @@ textwindows ssize_t sys_read_nt(struct Fd *fd, const struct iovec *iov,
ssize_t rc;
uint32_t size;
size_t i, total;
if (weaken(_check_sigwinch) && weaken(_check_sigwinch)(fd)) return eintr();
while (iovlen && !iov[0].iov_len) iov++, iovlen--;
if (iovlen) {
for (total = i = 0; i < iovlen; ++i) {

View file

@ -35,21 +35,12 @@ static int GetFirstIov(struct iovec *iov, int iovlen) {
}
ssize_t sys_readv_serial(struct Fd *fd, const struct iovec *iov, int iovlen) {
size_t i, j, got = 0;
size_t i;
if ((i = GetFirstIov(iov, iovlen)) != -1) {
while (!IsDataAvailable(fd)) asm("pause");
i = 0;
j = 0;
do {
++got;
((char *)iov[i].iov_base)[j] = inb(fd->handle);
if (++j == iov[i].iov_len) {
j = 0;
if (++i == iovlen) {
break;
}
}
} while (IsDataAvailable(fd));
((char *)iov[i].iov_base)[0] = inb(fd->handle);
return 1;
} else {
return 0;
}
return got;
}

View file

@ -25,13 +25,14 @@
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/errno.h"
#include "libc/limits.h"
#include "libc/log/backtrace.internal.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
@ -73,12 +74,13 @@ static char *ResolvePath(char *d, const char *s, size_t n)
* symbolic link then it's resolved.
*
* @param resolved needs PATH_MAX bytes or NULL to use malloc()
* @return resolved or NULL w/ errno
*/
char *realpath(const char *filename, char *resolved)
{
ssize_t k;
int up, check_dir=0;
size_t p, q, l, l0, cnt=0, nup=0;
ssize_t rc;
int e, up, check_dir=0;
size_t k, p, q, l, l0, cnt=0, nup=0;
char output[PATH_MAX], stack[PATH_MAX+1], *z;
if (!filename) {
@ -160,15 +162,10 @@ restart:
* directories, processing .. can skip readlink. */
if (!check_dir) goto skip_readlink;
}
k = readlink(output, stack, p);
if (k<0) SYSDEBUG("realpath readlink failed %d", (long)errno);
if (k==p) goto toolong;
if (!k) {
errno = ENOENT;
return 0;
}
if (k<0) {
e = errno;
if ((rc = readlink(output, stack, p)) == -1) {
if (errno != EINVAL) return 0;
errno = e; /* [jart] undirty errno if not a symlink */
skip_readlink:
check_dir = 0;
if (up) {
@ -180,6 +177,14 @@ skip_readlink:
check_dir = stack[p];
continue;
}
k = rc;
assert(k <= p);
if (k==p)
goto toolong;
if (!k) {
errno = ENOENT;
return 0;
}
if (++cnt == SYMLOOP_MAX) {
errno = ELOOP;
return 0;

58
libc/calls/sigwinch-nt.c Normal file
View file

@ -0,0 +1,58 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/winsize.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/errno.h"
#include "libc/nt/struct/consolescreenbufferinfoex.h"
#include "libc/str/str.h"
static struct winsize __ws;
textwindows bool _check_sigwinch(struct Fd *fd) {
int e;
siginfo_t si;
struct winsize ws, old;
struct NtConsoleScreenBufferInfoEx sbinfo;
old = __ws;
if (old.ws_row != 0xffff) {
e = errno;
if (ioctl_tiocgwinsz_nt(fd, &ws) != -1) {
if (old.ws_col != ws.ws_col || old.ws_row != ws.ws_row) {
__ws = ws;
if (old.ws_col | old.ws_row) {
SYSDEBUG("SIGWINCH %hhu×%hhu → %hhu×%hhu", old.ws_col, old.ws_row,
ws.ws_col, ws.ws_row);
if (__sighandrvas[SIGWINCH] >= kSigactionMinRva) {
bzero(&si, sizeof(si));
((sigaction_f)(_base + __sighandrvas[SIGWINCH]))(SIGWINCH, &si, 0);
return true;
}
}
}
} else {
errno = e;
if (!old.ws_row && !old.ws_col) {
__ws.ws_row = 0xffff;
}
}
}
return false;
}

View file

@ -32,9 +32,10 @@ static ssize_t splicer(int infd, int64_t *inoffset, int outfd,
if (!uptobytes || flags == -1) return einval();
if (IsModeDbg() && uptobytes > 1) uptobytes >>= 1;
olderr = errno;
if ((transferred =
if (__isfdkind(infd, kFdZip) || __isfdkind(outfd, kFdZip) ||
(transferred =
impl(infd, inoffset, outfd, outoffset, uptobytes, flags)) == -1 &&
errno == ENOSYS) {
errno == ENOSYS) {
errno = olderr;
transferred = copyfd(infd, inoffset, outfd, outoffset, uptobytes, flags);
}

View file

@ -24,6 +24,7 @@ COSMOPOLITAN_C_START_
void _init_onntconsoleevent(void);
void _init_wincrash(void);
bool _check_sigwinch();
#ifndef __SIGACTION_YOINK
#define __SIGACTION_YOINK(SIG) \
@ -44,12 +45,16 @@ void _init_wincrash(void);
case SIGFPE: \
YOINK(_init_wincrash); \
break; \
case SIGWINCH: \
YOINK(_check_sigwinch); \
break; \
default: \
break; \
} \
} else { \
YOINK(_init_onntconsoleevent); \
YOINK(_init_wincrash); \
YOINK(_check_sigwinch); \
} \
} \
} while (0)

View file

@ -7,7 +7,7 @@
#endif
#if DEBUGSYS
#define SYSDEBUG(FMT, ...) __printf("SYS: " FMT "\n", ##__VA_ARGS__)
#define SYSDEBUG(FMT, ...) kprintf("SYS: " FMT "\n", ##__VA_ARGS__)
#else
#define SYSDEBUG(FMT, ...) (void)0
#endif

View file

@ -28,12 +28,21 @@
// @note FreeBSD is special (see freebsd/lib/csu/amd64/...)
// @noreturn
_start:
// Get startup timestamp as early as possible.
// Used by --strace flag and kprintf() %T.
rdtsc
ezlea kStartTsc,bx
mov %eax,(%rbx)
mov %edx,4(%rbx)
#if SupportsFreebsd()
test %rdi,%rdi
cmovnz %rdi,%rsp
jz 0f
movb $FREEBSD,__hostos(%rip)
#endif
0: mov (%rsp),%ebx # argc
lea 8(%rsp),%rsi # argv
lea 16(%rsp,%rbx,8),%rdx # envp

View file

@ -5,6 +5,8 @@
* @fileoverview Executable and Linkable Format Definitions.
*/
#define EI_NIDENT 16
#define EI_MAG0 0
#define EI_MAG1 1
#define EI_MAG2 2

View file

@ -24,13 +24,15 @@ char *GetElfStringTable(const Elf64_Ehdr *elf, size_t mapsize) {
char *name;
Elf64_Half i;
Elf64_Shdr *shdr;
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, mapsize, i);
if (shdr->sh_type == SHT_STRTAB) {
name = GetElfSectionName(elf, mapsize,
GetElfSectionHeaderAddress(elf, mapsize, i));
if (name && !strcmp(name, ".strtab")) {
return GetElfSectionAddress(elf, mapsize, shdr);
if (elf->e_shentsize) {
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, mapsize, i);
if (shdr->sh_type == SHT_STRTAB) {
name = GetElfSectionName(elf, mapsize,
GetElfSectionHeaderAddress(elf, mapsize, i));
if (name && !strcmp(name, ".strtab")) {
return GetElfSectionAddress(elf, mapsize, shdr);
}
}
}
}

View file

@ -23,12 +23,14 @@ Elf64_Sym *GetElfSymbolTable(const Elf64_Ehdr *elf, size_t mapsize,
Elf64_Xword *out_count) {
Elf64_Half i;
Elf64_Shdr *shdr;
for (i = elf->e_shnum; i > 0; --i) {
shdr = GetElfSectionHeaderAddress(elf, mapsize, i - 1);
if (shdr->sh_type == SHT_SYMTAB) {
if (shdr->sh_entsize != sizeof(Elf64_Sym)) continue;
if (out_count) *out_count = shdr->sh_size / shdr->sh_entsize;
return GetElfSectionAddress(elf, mapsize, shdr);
if (elf->e_shentsize) {
for (i = elf->e_shnum; i > 0; --i) {
shdr = GetElfSectionHeaderAddress(elf, mapsize, i - 1);
if (shdr->sh_type == SHT_SYMTAB) {
if (shdr->sh_entsize != sizeof(Elf64_Sym)) continue;
if (out_count) *out_count = shdr->sh_size / shdr->sh_entsize;
return GetElfSectionAddress(elf, mapsize, shdr);
}
}
}
return NULL;

View file

@ -0,0 +1,26 @@
#ifndef COSMOPOLITAN_LIBC_FMT_DIVMOD10_H_
#define COSMOPOLITAN_LIBC_FMT_DIVMOD10_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
forceinline uint64_t DivMod10(uint64_t x, unsigned *r) {
#if defined(__STRICT_ANSI__) || !defined(__GNUC__) || \
(defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__))
*r = x % 10;
return x / 10;
#else
uint128_t dw;
unsigned long long hi, rm;
dw = x;
dw *= 0xcccccccccccccccdull;
hi = dw >> 64;
hi >>= 3;
rm = hi;
rm += rm << 2;
rm += rm;
*r = x - rm;
return hi;
#endif
}
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_FMT_DIVMOD10_H_ */

View file

@ -27,6 +27,8 @@ int vsscanf(const char *, const char *, va_list);
int vcscanf(int (*)(void *), int (*)(int, void *), void *, const char *,
va_list);
int strerror_r(int, char *, size_t) nothrow nocallback;
const char *strerror_short(int) nosideeffect;
const char *strerror_long(int) nosideeffect;
int __fmt(void *, void *, const char *, va_list) hidden;
char *itoa(int, char *, int) compatfn;
char *fcvt(double, int, int *, int *);

View file

@ -29,6 +29,7 @@
.section .rodata
.align 4
kErrorNames:
.e EINVAL
.e ENOSYS
.e EPERM
.e ENOENT
@ -51,7 +52,6 @@ kErrorNames:
.e ENODEV
.e ENOTDIR
.e EISDIR
.e EINVAL
.e ENFILE
.e EMFILE
.e ENOTTY

View file

@ -29,155 +29,90 @@
.section .rodata
.align 4
kErrorNamesLong:
.e EPIPE,"EPIPE[Broken pipe]"
.e ENODEV,"ENODEV[No such device]"
.e EINVAL,"EINVAL[Invalid argument]"
.e EINTR,"EINTR[Interrupted system call]"
.e ENOTBLK,"ENOTBLK[Block device required]"
.e ENOSYS,"ENOSYS[Function not implemented]"
.e EHOSTUNREACH,"EHOSTUNREACH[No route to host]"
.e ESRCH,"ESRCH[No such process]"
.e EUSERS,"EUSERS[Too many users]"
.e EXDEV,"EXDEV[Cross-device link]"
.e E2BIG,"E2BIG[Arg list too long]"
.e EREMOTE,"EREMOTE[Object is remote]"
.e ECHILD,"ECHILD[No child processes]"
.e EMSGSIZE,"EMSGSIZE[Message too long]"
.e ENOTEMPTY,"ENOTEMPTY[Directory not empty]"
.e ENOBUFS,"ENOBUFS[No buffer space available]"
.e ELOOP,"ELOOP[Too many symbolic links encountered]"
.e EAFNOSUPPORT,"EAFNOSUPPORT[Address family not supported by protocol]"
.e EHOSTDOWN,"EHOSTDOWN[Host is down]"
.e EPFNOSUPPORT,"EPFNOSUPPORT[Protocol family not supported]"
.e ENOPROTOOPT,"ENOPROTOOPT[Protocol not available]"
.e EBUSY,"EBUSY[Device or resource busy]"
.e EWOULDBLOCK,"EWOULDBLOCK[Operation would block]"
.e EBADFD,"EBADFD[File descriptor in bad state]"
.e EISCONN,"EISCONN[Transport endpoint is already connected]"
.e ESHUTDOWN,"ESHUTDOWN[Cannot send after transport endpoint shutdown]"
.e ENONET,"ENONET[Machine is not on the network]"
.e EBADE,"EBADE[Invalid exchange]"
.e EBADF,"EBADF[Bad file number]"
.e EMULTIHOP,"EMULTIHOP[Multihop attempted]"
.e EIO,"EIO[I/O error]"
.e EUNATCH,"EUNATCH[Protocol driver not attached]"
.e EPROTOTYPE,"EPROTOTYPE[Protocol wrong type for socket]"
.e ENOSPC,"ENOSPC[No space left on device]"
.e ENOEXEC,"ENOEXEC[Exec format error]"
.e EALREADY,"EALREADY[Operation already in progress]"
.e ENETDOWN,"ENETDOWN[Network is down]"
.e ENOTNAM,"ENOTNAM[Not a XENIX named type file]"
.e EACCES,"EACCES[Permission denied]"
.e ELNRNG,"ELNRNG[Link number out of range]"
.e EILSEQ,"EILSEQ[Illegal byte sequence]"
.e ENOTDIR,"ENOTDIR[Not a directory]"
.e ENOTUNIQ,"ENOTUNIQ[Name not unique on network]"
.e EPERM,"EPERM[Operation not permitted]"
.e EDOM,"EDOM[Math argument out of domain of func]"
.e EXFULL,"EXFULL[Exchange full]"
.e ECONNREFUSED,"ECONNREFUSED[Connection refused]"
.e EISDIR,"EISDIR[Is a directory]"
.e EPROTONOSUPPORT,"EPROTONOSUPPORT[Protocol not supported]"
.e EROFS,"EROFS[Read-only file system]"
.e EADDRNOTAVAIL,"EADDRNOTAVAIL[Cannot assign requested address]"
.e EIDRM,"EIDRM[Identifier removed]"
.e ECOMM,"ECOMM[Communication error on send]"
.e ESRMNT,"ESRMNT[Srmount error]"
.e EREMOTEIO,"EREMOTEIO[Remote I/O error]"
.e EL3RST,"EL3RST[Level 3 reset]"
.e EBADMSG,"EBADMSG[Not a data message]"
.e ENFILE,"ENFILE[File table overflow]"
.e ELIBMAX,"ELIBMAX[Attempting to link in too many shared libraries]"
.e ESPIPE,"ESPIPE[Illegal seek]"
.e ENOLINK,"ENOLINK[Link has been severed]"
.e ENETRESET,"ENETRESET[Network dropped connection because of reset]"
.e ETIMEDOUT,"ETIMEDOUT[Connection timed out]"
.e ENOENT,"ENOENT[No such file or directory]"
.e EEXIST,"EEXIST[File exists]"
.e EDQUOT,"EDQUOT[Quota exceeded]"
.e ENOSTR,"ENOSTR[Device not a stream]"
.e EBADSLT,"EBADSLT[Invalid slot]"
.e EBADRQC,"EBADRQC[Invalid request code]"
.e ELIBACC,"ELIBACC[Can not access a needed shared library]"
.e EFAULT,"EFAULT[Bad address]"
.e EFBIG,"EFBIG[File too large]"
.e EDEADLK,"EDEADLK[Resource deadlock would occur]"
.e ENOTCONN,"ENOTCONN[Transport endpoint is not connected]"
.e EDESTADDRREQ,"EDESTADDRREQ[Destination address required]"
.e ELIBSCN,"ELIBSCN[.lib section in a.out corrupted]"
.e ENOLCK,"ENOLCK[No record locks available]"
.e EISNAM,"EISNAM[Is a named type file]"
.e ECONNABORTED,"ECONNABORTED[Software caused connection abort]"
.e ENETUNREACH,"ENETUNREACH[Network is unreachable]"
.e ESTALE,"ESTALE[Stale NFS file handle]"
.e ENOSR,"ENOSR[Out of streams resources]"
.e ENOMEM,"ENOMEM[Out of memory]"
.e ENOTSOCK,"ENOTSOCK[Socket operation on non-socket]"
.e ESTRPIPE,"ESTRPIPE[Streams pipe error]"
.e EMLINK,"EMLINK[Too many links]"
.e ERANGE,"ERANGE[Math result not representable]"
.e ELIBEXEC,"ELIBEXEC[Cannot exec a shared library directly]"
.e EL3HLT,"EL3HLT[Level 3 halted]"
.e ECONNRESET,"ECONNRESET[Connection reset by peer]"
.e EADDRINUSE,"EADDRINUSE[Address already in use]"
.e EOPNOTSUPP,"EOPNOTSUPP[Operation not supported on transport endpoint]"
.e EREMCHG,"EREMCHG[Remote address changed]"
.e EAGAIN,"EAGAIN[Try again]"
.e ENAMETOOLONG,"ENAMETOOLONG[File name too long]"
.e ENOTTY,"ENOTTY[Not a typewriter]"
.e ERESTART,"ERESTART[Interrupted system call should be restarted]"
.e ESOCKTNOSUPPORT,"ESOCKTNOSUPPORT[Socket type not supported]"
.e ETIME,"ETIME[Timer expired]"
.e ETOOMANYREFS,"ETOOMANYREFS[Too many references: cannot splice]"
.e EMFILE,"EMFILE[Too many open files]"
.e ETXTBSY,"ETXTBSY[Text file busy]"
.e EINPROGRESS,"EINPROGRESS[Operation now in progress]"
.e ENXIO,"ENXIO[No such device or address]"
.e ENOTSUP,"ENOTSUP[Operation not supported]"
.e EPROTO,"EPROTO[Protocol error]"
.e ENOMSG,"ENOMSG[No message of desired type]"
.e ENODATA,"ENODATA[No data available]"
.e EOVERFLOW,"EOVERFLOW[Value too large for defined data type]"
.e ENOMEDIUM,"ENOMEDIUM[No medium found]"
.e EMEDIUMTYPE,"EMEDIUMTYPE[Wrong medium type]"
.e ECANCELED,"ECANCELED[Operation Canceled]"
.e EOWNERDEAD,"EOWNERDEAD[Owner died]"
.e ENOTRECOVERABLE,"ENOTRECOVERABLE[State not recoverable]"
.e EOWNERDEAD,"EOWNERDEAD[Process died with the lock]"
.e ENOTRECOVERABLE,"ENOTRECOVERABLE[Lock is not recoverable]"
.e EFTYPE,"EFTYPE[Inappropriate file type or format]"
.e EAUTH,"EAUTH[Authentication error]"
.e EBADRPC,"EBADRPC[RPC struct is bad]"
.e ENEEDAUTH,"ENEEDAUTH[Need authenticator]"
.e ENOATTR,"ENOATTR[Attribute not found]"
.e EPROCUNAVAIL,"EPROCUNAVAIL[Bad procedure for program]"
.e EPROGMISMATCH,"EPROGMISMATCH[Program version wrong]"
.e EPROGUNAVAIL,"EPROGUNAVAIL[RPC prog. not avail]"
.e ERPCMISMATCH,"ERPCMISMATCH[RPC version wrong]"
.e EPROCLIM,"EPROCLIM[Too many processes]"
.e EBADARCH,"EBADARCH[Bad CPU type in executable]"
.e EBADEXEC,"EBADEXEC[Bad executable (or shared library)]"
.e EBADMACHO,"EBADMACHO[Malformed Mach-o file]"
.e EDEVERR,"EDEVERR[Device error]"
.e ENOPOLICY,"ENOPOLICY[Policy not found]"
.e EPWROFF,"EPWROFF[Device power is off]"
.e ESHLIBVERS,"ESHLIBVERS[Shared library version mismatch]"
.e ENOANO,"ENOANO[No anode]"
.e EADV,"EADV[Advertise error]"
.e EL2HLT,"EL2HLT[Level 2 halted]"
.e EDOTDOT,"EDOTDOT[RFS specific error]"
.e ENOPKG,"ENOPKG[Package not installed]"
.e EBADR,"EBADR[Invalid request descriptor]"
.e ENOCSI,"ENOCSI[No CSI structure available]"
.e ENOKEY,"ENOKEY[Required key not available]"
.e EUCLEAN,"EUCLEAN[Structure needs cleaning]"
.e ECHRNG,"ECHRNG[Channel number out of range]"
.e EL2NSYNC,"EL2NSYNC[Level 2 not synchronized]"
.e EKEYEXPIRED,"EKEYEXPIRED[Key has expired]"
.e ENAVAIL,"ENAVAIL[No XENIX semaphores available]"
.e EKEYREVOKED,"EKEYREVOKED[Key has been revoked]"
.e ELIBBAD,"ELIBBAD[Accessing a corrupted shared library]"
.e EKEYREJECTED,"EKEYREJECTED[Key was rejected by service]"
.e ERFKILL,"ERFKILL[Operation not possible due to RF-kill]"
.e EINVAL,"Invalid argument"
.e ENOSYS,"Function not implemented"
.e EPERM,"Operation not permitted"
.e ENOENT,"No such file or directory"
.e ESRCH,"No such process"
.e EINTR,"Interrupted system call"
.e EIO,"I/O error"
.e ENXIO,"No such device or address"
.e E2BIG,"Arg list too long"
.e ENOEXEC,"Exec format error"
.e EBADF,"Bad file number"
.e ECHILD,"No child processes"
.e EAGAIN,"Try again"
.e ENOMEM,"Out of memory"
.e EACCES,"Permission denied"
.e EFAULT,"Bad address"
.e ENOTBLK,"Block device required"
.e EBUSY,"Device or resource busy"
.e EEXIST,"File exists"
.e EXDEV,"Cross-device link"
.e ENODEV,"No such device"
.e ENOTDIR,"Not a directory"
.e EISDIR,"Is a directory"
.e ENFILE,"File table overflow"
.e EMFILE,"Too many open files"
.e ENOTTY,"Not a typewriter"
.e ETXTBSY,"Text file busy"
.e EFBIG,"File too large"
.e ENOSPC,"No space left on device"
.e EDQUOT,"Quota exceeded"
.e ESPIPE,"Illegal seek"
.e EROFS,"Read-only file system"
.e EMLINK,"Too many links"
.e EPIPE,"Broken pipe"
.e EDOM,"Math argument out of domain of func"
.e ERANGE,"Math result not representable"
.e EDEADLK,"Resource deadlock would occur"
.e ENAMETOOLONG,"File name too long"
.e ENOLCK,"No record locks available"
.e ENOTEMPTY,"Directory not empty"
.e ELOOP,"Too many symbolic links encountered"
.e ENOMSG,"No message of desired type"
.e EIDRM,"Identifier removed"
.e ETIME,"Timer expired"
.e EPROTO,"Protocol error"
.e EOVERFLOW,"Value too large for defined data type"
.e EILSEQ,"Illegal byte sequence"
.e EUSERS,"Too many users"
.e ENOTSOCK,"Socket operation on non-socket"
.e EDESTADDRREQ,"Destination address required"
.e EMSGSIZE,"Message too long"
.e EPROTOTYPE,"Protocol wrong type for socket"
.e ENOPROTOOPT,"Protocol not available"
.e EPROTONOSUPPORT,"Protocol not supported"
.e ESOCKTNOSUPPORT,"Socket type not supported"
.e ENOTSUP,"Operation not supported"
.e EOPNOTSUPP,"Operation not supported on transport endpoint"
.e EPFNOSUPPORT,"Protocol family not supported"
.e EAFNOSUPPORT,"Address family not supported by protocol"
.e EADDRINUSE,"Address already in use"
.e EADDRNOTAVAIL,"Cannot assign requested address"
.e ENETDOWN,"Network is down"
.e ENETUNREACH,"Network is unreachable"
.e ENETRESET,"Network dropped connection because of reset"
.e ECONNABORTED,"Software caused connection abort"
.e ECONNRESET,"Connection reset by peer"
.e ENOBUFS,"No buffer space available"
.e EISCONN,"Transport endpoint is already connected"
.e ENOTCONN,"Transport endpoint is not connected"
.e ESHUTDOWN,"Cannot send after transport endpoint shutdown"
.e ETOOMANYREFS,"Too many references: cannot splice"
.e ETIMEDOUT,"Connection timed out"
.e ECONNREFUSED,"Connection refused"
.e EHOSTDOWN,"Host is down"
.e EHOSTUNREACH,"No route to host"
.e EALREADY,"Operation already in progress"
.e EINPROGRESS,"Operation now in progress"
.e ESTALE,"Stale NFS file handle"
.e EREMOTE,"Object is remote"
.e EBADMSG,"Not a data message"
.e ECANCELED,"Operation Canceled"
.e EOWNERDEAD,"Owner died"
.e ENOTRECOVERABLE,"State not recoverable"
.e ENONET,"Machine is not on the network"
.e ERESTART,"Interrupted system call should be restarted"
.long 0
.endobj kErrorNamesLong,globl,hidden

View file

@ -0,0 +1,40 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
extern const struct { int x, s; } kErrorNamesLong[];
/**
* Converts errno value to descriptive sentence.
* @return non-null rodata string or null if not found
*/
privileged const char *strerror_long(int x) {
/* kprintf() weakly depends on this function */
int i;
if (x) {
for (i = 0; kErrorNamesLong[i].x; ++i) {
if (x ==
*(const long *)((uintptr_t)kErrorNamesLong + kErrorNamesLong[i].x)) {
return (const char *)((uintptr_t)kErrorNamesLong +
kErrorNamesLong[i].s);
}
}
}
return 0;
}

View file

@ -16,11 +16,13 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#define ShouldUseMsabiAttribute() 1
#include "libc/bits/safemacros.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/bsr.h"
@ -32,93 +34,48 @@
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
#if !IsTiny()
#if !IsTiny() && SupportsWindows()
/*
* If we're paying the code size costs for all the system five magnums
* that this module pulls in then we might as well pull in support for
* the improved accuracy windows errno conversions used by __winerr()
*/
STATIC_YOINK("__dos2errno");
#endif
struct Error {
int x;
int s;
};
extern const struct Error kErrorNames[];
extern const struct Error kErrorNamesLong[];
noasan static inline const char *GetErrorName(long x) {
int i;
if (x) {
for (i = 0; kErrorNames[i].x; ++i) {
if (x == *(const long *)((uintptr_t)kErrorNames + kErrorNames[i].x)) {
return (const char *)((uintptr_t)kErrorNames + kErrorNames[i].s);
}
}
}
return "EUNKNOWN";
}
noasan static inline const char *GetErrorNameLong(long x) {
int i;
if (x) {
for (i = 0; kErrorNamesLong[i].x; ++i) {
if (x ==
*(const long *)((uintptr_t)kErrorNamesLong + kErrorNamesLong[i].x)) {
return (const char *)((uintptr_t)kErrorNamesLong +
kErrorNamesLong[i].s);
}
}
}
return "EUNKNOWN[No error information]";
}
/**
* Converts errno value to string.
*
* @param err is error number or zero if unknown
* @return 0 on success, or error code
*/
noasan int strerror_r(int err, char *buf, size_t size) {
uint64_t w;
int c, i, n;
char *p, *e;
const char *s;
char16_t *ws = 0;
p = buf;
e = p + size;
err &= 0xFFFF;
s = IsTiny() ? GetErrorName(err) : GetErrorNameLong(err);
while ((c = *s++)) {
if (p + 1 + 1 <= e) *p++ = c;
}
if (!IsTiny()) {
if (p + 1 + 5 + 1 + 1 <= e) {
*p++ = '[';
p = __intcpy(p, err);
*p++ = ']';
}
if (IsWindows()) {
err = GetLastError() & 0xffff;
if ((n = FormatMessage(
kNtFormatMessageAllocateBuffer | kNtFormatMessageFromSystem |
kNtFormatMessageIgnoreInserts,
0, err, MAKELANGID(kNtLangNeutral, kNtSublangDefault),
(char16_t *)&ws, 0, 0))) {
while (n && ws[n - 1] <= L' ' || ws[n - 1] == L'.') --n;
if (p + 1 + 1 <= e) *p++ = '[';
for (i = 0; i < n; ++i) {
w = tpenc(ws[i] & 0xffff);
if (p + (bsrll(w) >> 3) + 1 + 1 <= e) {
do *p++ = w;
while ((w >>= 8));
}
}
if (p + 1 + 1 <= e) *p++ = ']';
LocalFree(ws);
}
if (p + 1 + 5 + 1 + 1 <= e) {
*p++ = '[';
p = __intcpy(p, err);
*p++ = ']';
}
privileged int strerror_r(int err, char *buf, size_t size) {
/* kprintf() weakly depends on this function */
int c, n, winerr;
char16_t winmsg[256];
const char *sym, *msg;
sym = firstnonnull(strerror_short(err), "EUNKNOWN");
msg = firstnonnull(strerror_long(err), "No error information");
if (IsTiny()) {
if (!sym) sym = "EUNKNOWN";
for (; (c = *sym++); --size)
if (size > 1) *buf++ = c;
if (size) *buf = 0;
} else if (!IsWindows()) {
ksnprintf(buf, size, "%s[%d][%s]", sym, err, msg);
} else {
winerr = __imp_GetLastError();
if ((n = __imp_FormatMessageW(
kNtFormatMessageFromSystem | kNtFormatMessageIgnoreInserts, 0,
winerr, MAKELANGID(kNtLangNeutral, kNtSublangDefault), winmsg,
ARRAYLEN(winmsg), 0))) {
while ((n && winmsg[n - 1] <= ' ') || winmsg[n - 1] == '.') --n;
ksnprintf(buf, size, "%s[%d][%s][%.*hs][%d]", sym, err, msg, n, winmsg,
winerr);
} else {
ksnprintf(buf, size, "%s[%d][%s][%d]", sym, err, msg, winerr);
}
__imp_SetLastError(winerr);
}
if (p + 1 <= e) *p = 0;
return 0;
}

View file

@ -0,0 +1,38 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
extern const struct { int x, s; } kErrorNames[];
/**
* Converts errno value to symbolic name.
* @return non-null rodata string or null if not found
*/
privileged const char *strerror_short(int x) {
/* kprintf() weakly depends on this function */
int i;
if (x) {
for (i = 0; kErrorNames[i].x; ++i) {
if (x == *(const *)((uintptr_t)kErrorNames + kErrorNames[i].x)) {
return (const char *)((uintptr_t)kErrorNames + kErrorNames[i].s);
}
}
}
return 0;
}

View file

@ -22,10 +22,11 @@
#include "libc/bits/likely.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
@ -89,12 +90,13 @@ STATIC_YOINK("_init_asan");
} \
} while (0)
#define REQUIRE(FUNC) \
do { \
if (!weaken(FUNC)) { \
__asan_die("error: asan needs " #FUNC "\n")(); \
__asan_unreachable(); \
} \
#define REQUIRE(FUNC) \
do { \
if (!weaken(FUNC)) { \
kprintf("error: asan needs %s%n", #FUNC); \
__asan_die()(); \
__asan_unreachable(); \
} \
} while (0)
typedef char xmm_t __attribute__((__vector_size__(16), __aligned__(1)));
@ -139,6 +141,7 @@ struct AsanMorgue {
};
bool __asan_noreentry;
extern bool __nomultics;
static struct AsanMorgue __asan_morgue;
static wontreturn void __asan_unreachable(void) {
@ -227,7 +230,8 @@ static void *__asan_memset(void *p, char c, size_t n) {
static void *__asan_mempcpy(void *dst, const void *src, size_t n) {
size_t i;
char *d, *s;
char *d;
const char *s;
uint64_t a, b;
d = dst;
s = src;
@ -303,14 +307,13 @@ static char *__asan_hexcpy(char *p, uint64_t x, uint8_t k) {
}
static void __asan_exit(void) {
__printf("your asan runtime needs\n"
"\tSTATIC_YOINK(\"__die\");\n"
"in order to show you backtraces\n");
kprintf("your asan runtime needs%n"
"\tSTATIC_YOINK(\"__die\");%n"
"in order to show you backtraces%n");
_Exit(99);
}
nodiscard static __asan_die_f *__asan_die(const char *msg) {
__printf("%s", msg);
nodiscard static __asan_die_f *__asan_die(void) {
if (weaken(__die)) {
return weaken(__die);
} else {
@ -358,7 +361,7 @@ static bool __asan_is_mapped(int x) {
struct MemoryIntervals *m;
m = weaken(_mmi);
i = FindMemoryInterval(m, x);
return i < m->i && m->p[i].x <= x && x <= m->p[i].y;
return i < m->i && x >= m->p[i].x;
}
static bool __asan_is_image(const unsigned char *p) {
@ -366,7 +369,7 @@ static bool __asan_is_image(const unsigned char *p) {
}
static bool __asan_exists(const void *x) {
return __asan_is_image(x) || __asan_is_mapped((intptr_t)x >> 16);
return !kisdangerous(x);
}
static struct AsanFault __asan_fault(const signed char *s, signed char dflt) {
@ -385,13 +388,13 @@ static struct AsanFault __asan_fault(const signed char *s, signed char dflt) {
static struct AsanFault __asan_checka(const signed char *s, long ndiv8) {
intptr_t a;
uint64_t w;
signed char c, *e = s + ndiv8;
const signed char *e = s + ndiv8;
for (; ((intptr_t)s & 7) && s < e; ++s) {
if (*s) return __asan_fault(s - 1, kAsanHeapOverrun);
}
for (; s + 8 <= e; s += 8) {
if (UNLIKELY(!((a = (intptr_t)s) & 0xffff))) {
if (!__asan_is_mapped(a >> 16)) {
if (kisdangerous((void *)a)) {
return (struct AsanFault){kAsanUnmapped, s};
}
}
@ -422,7 +425,6 @@ static struct AsanFault __asan_checka(const signed char *s, long ndiv8) {
*/
struct AsanFault __asan_check(const void *p, long n) {
intptr_t a;
uint64_t w;
struct AsanFault f;
signed char c, k, *s;
if (n > 0) {
@ -431,7 +433,7 @@ struct AsanFault __asan_check(const void *p, long n) {
s = (signed char *)a;
if (OverlapsShadowSpace(p, n)) {
return (struct AsanFault){kAsanProtected, s};
} else if (IsLegalPointer(a) && !__asan_is_mapped(a >> 16)) {
} else if (kisdangerous((void *)a)) {
return (struct AsanFault){kAsanUnmapped, s};
}
if (UNLIKELY(k)) {
@ -491,19 +493,6 @@ bool __asan_is_valid_strlist(char *const *p) {
}
}
static const char *__asan_dscribe_heap_poison(signed char c) {
switch (c) {
case kAsanHeapFree:
return "heap double free";
case kAsanStackFree:
return "free stack after return";
case kAsanHeapRelocated:
return "free after relocate";
default:
return "this corruption";
}
}
wint_t __asan_symbolize_access_poison(signed char kind) {
switch (kind) {
case kAsanNullPage:
@ -544,6 +533,10 @@ wint_t __asan_symbolize_access_poison(signed char kind) {
return L'G';
case kAsanGlobalGone:
return L'𝐺';
case kAsanGlobalUnderrun:
return L'μ';
case kAsanGlobalOverrun:
return L'Ω';
default:
return L'?';
}
@ -589,16 +582,19 @@ const char *__asan_describe_access_poison(signed char kind) {
return "global redzone";
case kAsanGlobalGone:
return "global gone";
case kAsanGlobalUnderrun:
return "global underrun";
case kAsanGlobalOverrun:
return "global overrun";
default:
return "poisoned";
}
}
nodiscard static __asan_die_f *__asan_report_invalid_pointer(void *addr) {
__printf("\r\n%sasan error%s: this corruption at 0x%p shadow 0x%p\r\n",
!g_isterminalinarticulate ? "\e[J\e[1;91m" : "",
!g_isterminalinarticulate ? "\e[0m" : "", addr, SHADOW(addr));
return __asan_die("");
nodiscard static __asan_die_f *__asan_report_invalid_pointer(const void *addr) {
kprintf("%n\e[J\e[1;31masan error\e[0m: this corruption at %p shadow %p%n",
addr, SHADOW(addr));
return __asan_die();
}
static char *__asan_format_interval(char *p, intptr_t a, intptr_t b) {
@ -607,8 +603,8 @@ static char *__asan_format_interval(char *p, intptr_t a, intptr_t b) {
return p;
}
static char *__asan_format_section(char *p, void *p1, void *p2,
const char *name, void *addr) {
static char *__asan_format_section(char *p, const void *p1, const void *p2,
const char *name, const void *addr) {
intptr_t a, b;
if ((a = (intptr_t)p1) < (b = (intptr_t)p2)) {
p = __asan_format_interval(p, a, b), *p++ = ' ';
@ -616,26 +612,25 @@ static char *__asan_format_section(char *p, void *p1, void *p2,
if (a <= (intptr_t)addr && (intptr_t)addr <= b) {
p = __stpcpy(p, " ←address");
}
*p++ = '\r', *p++ = '\n';
if (__nomultics) *p++ = '\r';
*p++ = '\n';
}
return p;
}
nodiscard static __asan_die_f *__asan_report(void *addr, int size,
nodiscard static __asan_die_f *__asan_report(const void *addr, int size,
const char *message,
signed char kind) {
int i;
wint_t c;
int i, cc;
signed char t;
uint64_t x, y, z;
char *p, *q, *base;
struct MemoryIntervals *m;
p = __fatalbuf;
__printf("\r\n%sasan error%s: %s %d-byte %s at 0x%p shadow 0x%p\r\n",
!g_isterminalinarticulate ? "\e[J\e[1;91m" : "",
!g_isterminalinarticulate ? "\e[0m" : "",
__asan_describe_access_poison(kind), size, message, addr,
SHADOW(addr));
kprintf("%n\e[J\e[1;31masan error\e[0m: %s %d-byte %s at %p shadow %p%n%s%n",
__asan_describe_access_poison(kind), size, message, addr,
SHADOW(addr), __argv[0]);
if (0 < size && size < 80) {
base = (char *)addr - ((80 >> 1) - (size >> 1));
for (i = 0; i < 80; ++i) {
@ -649,30 +644,32 @@ nodiscard static __asan_die_f *__asan_report(void *addr, int size,
*p++ = ' ';
}
}
*p++ = '\r', *p++ = '\n';
if (__nomultics) *p++ = '\r';
*p++ = '\n';
for (c = i = 0; i < 80; ++i) {
if (!(t = __asan_check(base + i, 1).kind)) {
if (!g_isterminalinarticulate && c != 32) {
if (c != 32) {
p = __stpcpy(p, "\e[32m");
c = 32;
}
*p++ = '.';
} else {
if (!g_isterminalinarticulate && c != 31) {
if (c != 31) {
p = __stpcpy(p, "\e[31m");
c = 31;
}
p = __asan_utf8cpy(p, __asan_symbolize_access_poison(t));
}
}
if (!g_isterminalinarticulate) p = __stpcpy(p, "\e[39m");
*p++ = '\r', *p++ = '\n';
p = __stpcpy(p, "\e[39m");
if (__nomultics) *p++ = '\r';
*p++ = '\n';
for (i = 0; (intptr_t)(base + i) & 7; ++i) *p++ = ' ';
for (; i + 8 <= 80; i += 8) {
q = p + 8;
*p++ = '|';
z = ((intptr_t)(base + i) >> 3) + 0x7fff8000;
if (__asan_is_mapped(z >> 16)) {
if (!kisdangerous((void *)z)) {
p = __intcpy(p, *(signed char *)z);
} else {
*p++ = '!';
@ -682,13 +679,15 @@ nodiscard static __asan_die_f *__asan_report(void *addr, int size,
}
}
for (; i < 80; ++i) *p++ = ' ';
*p++ = '\r', *p++ = '\n';
if (__nomultics) *p++ = '\r';
*p++ = '\n';
for (i = 0; i < 80; ++i) {
p = __asan_utf8cpy(p, __asan_exists(base + i)
? kCp437[((unsigned char *)base)[i]]
: L'');
}
*p++ = '\r', *p++ = '\n';
if (__nomultics) *p++ = '\r';
*p++ = '\n';
}
p = __asan_format_section(p, _base, _etext, ".text", addr);
p = __asan_format_section(p, _etext, _edata, ".data", addr);
@ -701,10 +700,12 @@ nodiscard static __asan_die_f *__asan_report(void *addr, int size,
if (x <= z && z <= y) p = __stpcpy(p, " ←address");
z = (((intptr_t)addr >> 3) + 0x7fff8000) >> 16;
if (x <= z && z <= y) p = __stpcpy(p, " ←shadow");
*p++ = '\r', *p++ = '\n';
if (__nomultics) *p++ = '\r';
*p++ = '\n';
}
*p = 0;
return __asan_die(__fatalbuf);
kprintf("%s", __fatalbuf);
return __asan_die();
}
void __asan_verify(const void *p, size_t n) {
@ -726,7 +727,7 @@ nodiscard __asan_die_f *__asan_report_memory_fault(void *addr, int size,
__asan_fault(SHADOW(addr), -128).kind);
}
const void *__asan_morgue_add(void *p) {
void *__asan_morgue_add(void *p) {
void *r;
int i, j;
for (;;) {
@ -785,6 +786,17 @@ static bool __asan_read48(uint64_t value, uint64_t *x) {
return cookie == ('J' | 'T' << 8);
}
static void __asan_rawtrace(struct AsanTrace *bt, const struct StackFrame *bp) {
size_t i;
for (i = 0; bp && i < ARRAYLEN(bt->p); ++i, bp = bp->next) {
if (kisdangerous(bp)) break;
bt->p[i] = bp->addr;
}
for (; i < ARRAYLEN(bt->p); ++i) {
bt->p[i] = 0;
}
}
static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
int f1, f2;
size_t i, gi;
@ -792,10 +804,9 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
struct Garbages *garbage;
garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0;
__asan_memset(bt, 0, sizeof(*bt));
for (f1 = -1, i = 0; bp && i < ARRAYLEN(bt->p); ++i, bp = bp->next) {
if (f1 != (f2 = ((intptr_t)bp >> 16))) {
if (!__asan_is_mapped(f2)) break;
if (kisdangerous(bp)) break;
f1 = f2;
}
if (!__asan_checka(SHADOW(bp), sizeof(*bp) >> 3).kind) {
@ -809,8 +820,13 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
break;
}
}
for (; i < ARRAYLEN(bt->p); ++i) {
bt->p[i] = 0;
}
}
#define __asan_trace __asan_rawtrace
static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
struct AsanTrace *bt) {
char *p;
@ -830,17 +846,14 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
return p;
}
static struct AsanExtra *__asan_get_extra(void *p, size_t *c) {
static struct AsanExtra *__asan_get_extra(const void *p, size_t *c) {
int f;
long x, n;
struct AsanExtra *e;
if ((0 < (intptr_t)p && (intptr_t)p < 0x800000000000) &&
__asan_is_mapped((f = (intptr_t)p >> 16)) &&
(LIKELY(f == (int)(((intptr_t)p - 16) >> 16)) ||
__asan_is_mapped(((intptr_t)p - 16) >> 16)) &&
(n = weaken(dlmalloc_usable_size)(p)) > sizeof(*e) &&
f = (intptr_t)p >> 16;
if (!kisdangerous(p) && (n = weaken(dlmalloc_usable_size)(p)) > sizeof(*e) &&
!__builtin_add_overflow((intptr_t)p, n, &x) && x <= 0x800000000000 &&
(LIKELY(f == (int)((x - 1) >> 16)) || __asan_is_mapped((x - 1) >> 16)) &&
(LIKELY(f == (int)((x - 1) >> 16)) || !kisdangerous((void *)(x - 1))) &&
(LIKELY(f == (int)((x = x - sizeof(*e)) >> 16)) ||
__asan_is_mapped(x >> 16)) &&
!(x & (alignof(struct AsanExtra) - 1))) {
@ -882,27 +895,25 @@ static size_t __asan_malloc_usable_size(const void *p) {
}
int __asan_print_trace(void *p) {
intptr_t x;
size_t c, i, n;
const char *name;
struct AsanExtra *e;
if (!(e = __asan_get_extra(p, &c))) {
__printf(" bad pointer");
kprintf(" bad pointer");
return einval();
}
if (!__asan_read48(e->size, &n)) {
__printf(" bad cookie");
kprintf(" bad cookie");
return -1;
}
__printf(" %,d used", n);
kprintf(" %'zu used", n);
if (!__asan_is_mapped((((intptr_t)p >> 3) + 0x7fff8000) >> 16)) {
__printf(" (shadow not mapped?!)");
kprintf(" (shadow not mapped?!)");
}
for (i = 0; i < ARRAYLEN(e->bt.p) && e->bt.p[i]; ++i) {
__printf("\n%*x %s", 12, e->bt.p[i],
weaken(__get_symbol_by_addr)
? weaken(__get_symbol_by_addr)(e->bt.p[i])
: "please STATIC_YOINK(\"__get_symbol_by_addr\")");
kprintf("%n%*lx %s", 12, e->bt.p[i],
weaken(__get_symbol_by_addr)
? weaken(__get_symbol_by_addr)(e->bt.p[i])
: "please STATIC_YOINK(\"__get_symbol_by_addr\")");
}
return 0;
}
@ -1078,21 +1089,36 @@ void __asan_unregister_globals(struct AsanGlobal g[], int n) {
}
}
void __asan_evil(uint8_t *addr, int size, const char *s1, const char *s2) {
struct AsanTrace tr;
__asan_rawtrace(&tr, __builtin_frame_address(0));
kprintf("WARNING: ASAN error during %s bad %d byte %s at %p bt %p %p %p %p%n",
s1, size, s2, addr, tr.p[0], tr.p[1], tr.p[2], tr.p[3]);
}
void __asan_report_load(uint8_t *addr, int size) {
if (cmpxchg(&__asan_noreentry, false, true)) {
__asan_report_memory_fault(addr, size, "load")();
__asan_unreachable();
if (!__vforked) {
__asan_report_memory_fault(addr, size, "load")();
__asan_unreachable();
} else {
__asan_evil(addr, size, "vfork()", "load");
}
} else {
__printf("WARNING: ASAN error reporting had an ASAN error\r\n");
__asan_evil(addr, size, "ASAN Reporting", "load");
}
}
void __asan_report_store(uint8_t *addr, int size) {
if (cmpxchg(&__asan_noreentry, false, true)) {
__asan_report_memory_fault(addr, size, "store")();
__asan_unreachable();
if (!__vforked) {
__asan_report_memory_fault(addr, size, "store")();
__asan_unreachable();
} else {
__asan_evil(addr, size, "vfork()", "store");
}
} else {
__printf("WARNING: ASAN error reporting had an ASAN error\r\n");
__asan_evil(addr, size, "ASAN reporting", "store");
}
}
@ -1138,12 +1164,11 @@ void __asan_install_malloc_hooks(void) {
void __asan_map_shadow(uintptr_t p, size_t n) {
void *addr;
int i, a, b;
size_t size;
int prot, flag;
int i, x, a, b;
struct DirectMap sm;
struct MemoryIntervals *m;
SYSDEBUG("__asan_map_shadow(0x%p, 0x%x)", p, n);
assert(!OverlapsShadowSpace((void *)p, n));
m = weaken(_mmi);
a = (0x7fff8000 + (p >> 3)) >> 16;
@ -1167,7 +1192,8 @@ void __asan_map_shadow(uintptr_t p, size_t n) {
weaken(TrackMemoryInterval)(
m, a, a + i - 1, sm.maphandle, PROT_READ | PROT_WRITE,
MAP_PRIVATE | *weaken(MAP_ANONYMOUS) | MAP_FIXED) == -1) {
__asan_die("error: could not map asan shadow memory\n")();
kprintf("error: could not map asan shadow memory%n");
__asan_die()();
__asan_unreachable();
}
__repstosb((void *)(intptr_t)((int64_t)((uint64_t)a << 32) >> 16),
@ -1202,20 +1228,21 @@ static textstartup void __asan_shadow_string_list(char **list) {
__asan_map_shadow((uintptr_t)list, (i + 1) * sizeof(char *));
}
static textstartup void __asan_shadow_existing_mappings(void) {
size_t i;
struct MemoryIntervals m;
__asan_memcpy(&m, weaken(_mmi), sizeof(m));
for (i = 0; i < m.i; ++i) {
__asan_map_shadow((uintptr_t)m.p[i].x << 16,
(uintptr_t)(m.p[i].y - m.p[i].x + 1) << 16);
static textstartup void __asan_shadow_mapping(struct MemoryIntervals *m,
size_t i) {
uintptr_t x, y;
if (i < m->i) {
x = m->p[i].x;
y = m->p[i].y;
__asan_shadow_mapping(m, i + 1);
__asan_map_shadow(x << 16, (y - x + 1) << 16);
}
__asan_poison(GetStackAddr(0), PAGESIZE, kAsanStackOverflow);
}
static textstartup bool IsMemoryManagementRuntimeLinked(void) {
return weaken(_mmi) && weaken(sys_mmap) && weaken(MAP_ANONYMOUS) &&
weaken(TrackMemoryInterval);
static textstartup void __asan_shadow_existing_mappings(void) {
__asan_shadow_mapping(&_mmi, 0);
__asan_map_shadow(GetStackAddr(0), GetStackSize());
__asan_poison(GetStackAddr(0), PAGESIZE, kAsanStackOverflow);
}
textstartup void __asan_init(int argc, char **argv, char **envp,
@ -1223,7 +1250,7 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
static bool once;
if (!cmpxchg(&once, false, true)) return;
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) {
__write_str("error: asan binaries require windows10\n");
__write_str("error: asan binaries require windows10\r\n");
_Exit(0); /* So `make MODE=dbg test` passes w/ Windows7 */
}
REQUIRE(_mmi);
@ -1241,7 +1268,7 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
__asan_map_shadow(0, 4096);
__asan_poison(0, PAGESIZE, kAsanNullPage);
if (!IsWindows()) {
__sysv_mprotect((void *)0x00007fff8000, 0x10000, PROT_READ);
__sysv_mprotect((void *)0x7fff8000, 0x10000, PROT_READ);
}
__asan_shadow_string_list(argv);
__asan_shadow_string_list(envp);

View file

@ -1,29 +1,10 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
#define COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
#include "libc/calls/struct/iovec.h"
#include "libc/intrin/asancodes.h"
#include "libc/macros.internal.h"
#define kAsanScale 3
#define kAsanMagic 0x7fff8000
#define kAsanNullPage -1 /* ∅ 0xff */
#define kAsanProtected -2 /* P 0xfe */
#define kAsanHeapFree -3 /* F 0xfd */
#define kAsanHeapRelocated -4 /* R 0xfc */
#define kAsanAllocaOverrun -5 /* 𝑂 0xfb */
#define kAsanHeapUnderrun -6 /* U 0xfa */
#define kAsanHeapOverrun -7 /* O 0xf9 */
#define kAsanStackUnscoped -8 /* s 0xf8 */
#define kAsanStackOverflow -9 /* ! 0xf7 */
#define kAsanGlobalOrder -10 /* I 0xf6 */
#define kAsanStackFree -11 /* r 0xf5 */
#define kAsanStackPartial -12 /* p 0xf4 */
#define kAsanStackOverrun -13 /* o 0xf3 */
#define kAsanStackMiddle -14 /* m 0xf2 */
#define kAsanStackUnderrun -15 /* u 0xf1 */
#define kAsanAllocaUnderrun -16 /* 𝑈 0xf0 */
#define kAsanUnmapped -17 /* M 0xef */
#define kAsanGlobalRedzone -18 /* G 0xee */
#define kAsanGlobalGone -19 /* 𝐺 0xed */
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define SHADOW(x) ((signed char *)(((intptr_t)(x) >> kAsanScale) + kAsanMagic))
#define UNSHADOW(x) ((void *)(MAX(0, (intptr_t)(x)-kAsanMagic) << kAsanScale))
@ -32,7 +13,7 @@ typedef void __asan_die_f(void);
struct AsanFault {
signed char kind;
signed char *shadow;
const signed char *shadow;
};
extern bool __asan_noreentry;
@ -58,4 +39,6 @@ void *__asan_memalign(size_t, size_t);
size_t __asan_get_heap_size(const void *);
void *__asan_realloc_in_place(void *, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ */

28
libc/intrin/asancodes.h Normal file
View file

@ -0,0 +1,28 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_ASANCODES_H_
#define COSMOPOLITAN_LIBC_INTRIN_ASANCODES_H_
#define kAsanScale 3
#define kAsanMagic 0x7fff8000
#define kAsanNullPage -1 /* ∅ 0xff */
#define kAsanProtected -2 /* P 0xfe */
#define kAsanHeapFree -3 /* F 0xfd */
#define kAsanHeapRelocated -4 /* R 0xfc */
#define kAsanAllocaOverrun -5 /* 𝑂 0xfb */
#define kAsanHeapUnderrun -6 /* U 0xfa */
#define kAsanHeapOverrun -7 /* O 0xf9 */
#define kAsanStackUnscoped -8 /* s 0xf8 */
#define kAsanStackOverflow -9 /* ! 0xf7 */
#define kAsanGlobalOrder -10 /* I 0xf6 */
#define kAsanStackFree -11 /* r 0xf5 */
#define kAsanStackPartial -12 /* p 0xf4 */
#define kAsanStackOverrun -13 /* o 0xf3 */
#define kAsanStackMiddle -14 /* m 0xf2 */
#define kAsanStackUnderrun -15 /* u 0xf1 */
#define kAsanAllocaUnderrun -16 /* 𝑈 0xf0 */
#define kAsanUnmapped -17 /* M 0xef */
#define kAsanGlobalRedzone -18 /* G 0xee */
#define kAsanGlobalGone -19 /* 𝐺 0xed */
#define kAsanGlobalUnderrun -20 /* μ 0xec */
#define kAsanGlobalOverrun -21 /* Ω 0xeb */
#endif /* COSMOPOLITAN_LIBC_INTRIN_ASANCODES_H_ */

View file

@ -19,7 +19,7 @@
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/log/libfatal.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
@ -29,12 +29,12 @@
relegated wontreturn void __assert_fail(const char *expr, const char *file,
int line) {
static bool noreentry;
__printf("%s:%d: assert(%s) failed\r\n", file, line, expr);
kprintf("%s:%d: assert(%s) failed%n", file, line, expr);
if (cmpxchg(&noreentry, false, true)) {
if (weaken(__die)) {
weaken(__die)();
} else {
__printf("can't backtrace b/c `__die` not linked\r\n");
kprintf("can't backtrace b/c `__die` not linked%n");
}
quick_exit(23);
}

View file

@ -16,15 +16,15 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#define ShouldUseMsabiAttribute() 1
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/nexgen32e/vendor.internal.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/sysv/consts/nr.h"
extern void(__msabi* __imp_ExitProcess)(uint32_t);
/**
* Terminates process, ignoring destructors and atexit() handlers.
*

View file

@ -57,6 +57,12 @@ o/$(MODE)/libc/intrin/asan.o: \
-finline \
-finline-functions
o/$(MODE)/libc/intrin/kstarttsc.o \
o/$(MODE)/libc/intrin/nomultics.o \
o/$(MODE)/libc/intrin/ntconsolemode.o: \
OVERRIDE_CFLAGS += \
-fno-sanitize=all
o/$(MODE)/libc/intrin/asan.o \
o/$(MODE)/libc/intrin/ubsan.o: \
OVERRIDE_CFLAGS += \

798
libc/intrin/kprintf.greg.c Normal file
View file

@ -0,0 +1,798 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#define ShouldUseMsabiAttribute() 1
#include "libc/bits/bits.h"
#include "libc/bits/likely.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/divmod10.internal.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h"
#include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/uart.internal.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
#include "libc/str/utf16.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/prot.h"
#define MAXT (24 * 60 * 60 * 1000000000ull)
#define WRAP ((MAXT + 1) / 10 * 33)
struct Timestamps {
unsigned long long birth;
unsigned long long start;
};
extern int __pid;
extern bool __replmode;
extern bool __nomultics;
static volatile unsigned long long kbirth;
privileged static struct Timestamps kenter(void) {
struct Timestamps ts;
ts.start = rdtsc();
ts.birth = kbirth;
if (!ts.birth) {
ts.birth = kStartTsc;
if (!ts.birth) ts.birth = 1;
cmpxchg(&kbirth, 0, ts.birth);
}
return ts;
}
privileged static void kleave(struct Timestamps ts) {
uint64_t finish, elapse, adjust;
finish = rdtsc();
elapse = unsignedsubtract(finish, ts.start);
adjust = ts.birth + elapse;
if (!adjust) adjust = 1;
cmpxchg(&kbirth, ts.birth, adjust); /* ignore overlapping time intervals */
}
privileged static inline char *kadvance(char *p, char *e, long n) {
intptr_t t = (intptr_t)p;
if (__builtin_add_overflow(t, n, &t)) t = (intptr_t)e;
return (char *)t;
}
privileged static char *kemitquote(char *p, char *e, signed char t,
unsigned c) {
if (t) {
if (p < e) {
*p = t < 0 ? 'u' : 'L';
}
++p;
}
if (p < e) {
*p = c;
}
++p;
return p;
}
privileged static unsigned long long kgetint(va_list va, signed char t,
bool s) {
#ifdef __LP64__
int bits;
unsigned long long x;
x = va_arg(va, unsigned long);
if (t <= 0) {
bits = 64 - (32 >> MIN(5, -t));
x <<= bits;
if (s) {
x = (signed long)x >> bits;
} else {
x >>= bits;
}
}
return x;
#else
if (s) {
switch (t) {
case -2:
return (signed char)va_arg(va, int);
case -1:
return (signed short)va_arg(va, int);
default:
return va_arg(va, signed int);
case 1:
return va_arg(va, signed long);
case 2:
return va_arg(va, signed long long);
}
} else {
switch (t) {
case -2:
return (unsigned char)va_arg(va, int);
case -1:
return (unsigned short)va_arg(va, int);
default:
return va_arg(va, unsigned int);
case 1:
return va_arg(va, unsigned long);
case 2:
return va_arg(va, unsigned long long);
}
}
#endif
}
privileged static inline bool kiskernelpointer(const void *p) {
return 0x7f0000000000 <= (intptr_t)p && (intptr_t)p < 0x800000000000;
}
privileged static inline bool kistextpointer(const void *p) {
return _base <= (const unsigned char *)p && (const unsigned char *)p < _etext;
}
privileged static inline bool kisimagepointer(const void *p) {
return _base <= (const unsigned char *)p && (const unsigned char *)p < _end;
}
privileged static inline bool kischarmisaligned(const char *p, signed char t) {
if (t == -1) return (intptr_t)p & 1;
if (t >= 1) return !!((intptr_t)p & 3);
return false;
}
privileged static inline bool kismemtrackhosed(void) {
return !((weaken(_mmi)->i <= weaken(_mmi)->n) &&
(weaken(_mmi)->p == weaken(_mmi)->s ||
weaken(_mmi)->p == (struct MemoryInterval *)kMemtrackStart));
}
privileged static bool kismapped(int x) {
size_t m, r, l = 0;
if (!weaken(_mmi)) return true;
if (kismemtrackhosed()) return false;
r = weaken(_mmi)->i;
while (l < r) {
m = (l + r) >> 1;
if (weaken(_mmi)->p[m].y < x) {
l = m + 1;
} else {
r = m;
}
}
if (l < weaken(_mmi)->i && x >= weaken(_mmi)->p[l].x) {
return !!(weaken(_mmi)->p[l].prot & PROT_READ);
} else {
return false;
}
}
privileged bool kisdangerous(const void *p) {
int frame;
if (kisimagepointer(p)) return false;
if (kiskernelpointer(p)) return false;
if (IsLegalPointer(p)) {
frame = (intptr_t)p >> 16;
if (IsStackFrame(frame)) return false;
if (IsOldStackFrame(frame)) return false;
if (kismapped(frame)) return false;
}
return true;
}
privileged static void klog(const char *b, size_t n) {
int e;
size_t i;
uint16_t dx;
uint32_t wrote;
unsigned char al;
long rax, rdi, rsi, rdx;
if (IsWindows()) {
e = __imp_GetLastError();
__imp_WriteFile(__imp_GetStdHandle(kNtStdErrorHandle), b, n, &wrote, 0);
__imp_SetLastError(e);
} else if (IsMetal()) {
for (i = 0; i < n; ++i) {
for (;;) {
dx = 0x3F8 + UART_LSR;
asm("inb\t%1,%0" : "=a"(al) : "dN"(dx));
if (al & UART_TTYTXR) break;
asm("pause");
}
dx = 0x3F8;
asm volatile("outb\t%0,%1"
: /* no inputs */
: "a"(b[i]), "dN"(dx));
}
} else {
asm volatile("syscall"
: "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)
: "0"(__NR_write), "1"(2), "2"(b), "3"(n)
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
}
}
privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va,
struct Timestamps ts) {
int si;
wint_t t, u;
const char *abet;
signed char type;
const char *s, *f;
unsigned long long x;
unsigned i, j, m, rem, sign, hash, cols, prec;
char c, *p, *e, pdot, zero, flip, dang, base, quot, z[128];
if (kistextpointer(b) || kisdangerous(b)) n = 0;
if (!kistextpointer(fmt)) fmt = "!!WONTFMT";
p = b;
f = fmt;
e = p + n;
for (;;) {
for (;;) {
if (!(c = *f++) || c == '%') break;
EmitFormatByte:
if (p < e) *p = c;
++p;
}
if (!c) break;
pdot = 0;
flip = 0;
dang = 0;
hash = 0;
sign = 0;
prec = 0;
quot = 0;
type = 0;
cols = 0;
zero = 0;
abet = "0123456789abcdef";
for (;;) {
switch ((c = *f++)) {
default:
goto EmitFormatByte;
case '\0':
break;
case '.':
pdot = 1;
continue;
case '-':
flip = 1;
continue;
case '#':
hash = '0';
continue;
case '_':
case ',':
case '\'':
quot = c;
continue;
case ' ':
case '+':
sign = c;
continue;
case 'h':
--type;
continue;
case 'j':
case 'l':
case 'z':
++type;
continue;
case '!':
dang = 1;
continue;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
si = pdot ? prec : cols;
si *= 10;
si += c - '0';
goto UpdateCols;
case '*':
si = va_arg(va, int);
UpdateCols:
if (pdot) {
if (si >= 0) {
prec = si;
}
} else {
if (si < 0) {
flip = 1;
si = -si;
}
cols = si;
if (!cols) {
zero = 1;
}
}
continue;
case 'T':
x = unsignedsubtract(ts.start, ts.birth) % WRAP * 10 / 33;
goto FormatUnsigned;
case 'P':
if (!__vforked) {
x = __pid;
} else {
asm volatile("syscall"
: "=a"(x)
: "0"(__NR_getpid)
: "rcx", "rdx", "r11", "memory", "cc");
}
goto FormatUnsigned;
case 'u':
case 'd':
if (UNLIKELY(type <= -3)) {
s = va_arg(va, int) ? "true" : "false";
goto FormatString;
}
x = kgetint(va, type, c == 'd');
FormatDecimal:
if ((long long)x < 0 && c != 'u') {
x = -x;
sign = '-';
}
FormatUnsigned:
if (x && hash) sign = hash;
for (i = j = 0;;) {
x = DivMod10(x, &rem);
z[i++ & 127] = '0' + rem;
if (pdot ? i >= prec : !x) break;
if (quot && ++j == 3) {
z[i++ & 127] = quot;
j = 0;
}
}
EmitNumber:
if (flip || pdot) zero = 0;
while (zero && sign) {
if (p < e) *p = sign;
if (cols) --cols;
sign >>= 8;
++p;
}
t = !!sign + !!(sign >> 8);
if (!flip && cols >= t) {
for (j = i; j < cols - t; ++j) {
if (p < e) {
*p++ = zero ? '0' : ' ';
} else {
p = kadvance(p, e, cols - t - j);
break;
}
}
}
while (sign) {
if (p < e) *p = sign;
sign >>= 8;
++p;
}
for (j = i; j; ++p) {
--j;
if (p < e) {
*p = z[j & 127];
}
}
if (flip && cols >= t) {
for (j = i; j < cols - t; ++j) {
if (p < e) {
*p++ = ' ';
} else {
p = kadvance(p, e, cols - t - j);
break;
}
}
}
break;
case 'b':
base = 1;
if (hash) hash = '0' | 'b' << 8;
BinaryNumber:
x = kgetint(va, type, false);
FormatNumber:
i = 0;
m = (1 << base) - 1;
if (hash && x) sign = hash;
do z[i++ & 127] = abet[x & m];
while ((x >>= base) || (pdot && i < prec));
goto EmitNumber;
case 'X':
abet = "0123456789ABCDEF";
/* fallthrough */
case 'x':
base = 4;
if (hash) hash = '0' | 'x' << 8;
goto BinaryNumber;
case 'o':
base = 3;
goto BinaryNumber;
case 'p':
x = va_arg(va, intptr_t);
if (!x && pdot) pdot = 0;
if ((long)x == -1) {
pdot = 0;
goto FormatDecimal;
}
hash = '0' | 'x' << 8;
base = 4;
goto FormatNumber;
case 'C':
c = 'c';
type = 1;
/* fallthrough */
case 'c':
i = 1;
j = 0;
x = 0;
s = (const char *)&x;
t = va_arg(va, int);
if (!type) t &= 255;
if (hash) {
quot = 1;
hash = '\'';
p = kemitquote(p, e, type, hash);
if (cols && type) --cols; /* u/L */
if (cols) --cols; /* start quote */
if (cols) --cols; /* end quote */
}
goto EmitChar;
case 'm':
if (!(x = errno) && sign == ' ') {
break;
} else if (weaken(strerror_r) &&
!weaken(strerror_r)(x, z, sizeof(z))) {
s = z;
goto FormatString;
} else {
goto FormatDecimal;
}
case 'n':
if (__nomultics) {
if (p < e) *p = '\r';
++p;
}
if (p < e) *p = '\n';
++p;
break;
case 'r':
if (!__replmode) {
break;
} else {
s = "\r\033[K";
goto FormatString;
}
case 'S':
c = 's';
type = 1;
/* fallthrough */
case 's':
if (!(s = va_arg(va, const void *))) {
s = sign != ' ' ? "NULL" : "";
FormatString:
type = 0;
hash = 0;
} else if (!dang && (kisdangerous(s) || kischarmisaligned(s, type))) {
if (sign == ' ') {
if (p < e) *p = ' ';
++p;
}
x = (intptr_t)s;
base = 4;
hash = '!' | '!' << 8;
goto FormatNumber;
} else if (hash) {
quot = 1;
hash = '"';
if (cols && type) --cols; /* u/L */
if (cols) --cols; /* start quote */
if (cols) --cols; /* end quote */
p = kemitquote(p, e, type, hash);
}
if (sign == ' ' && (!pdot || prec) && *s) {
if (p < e) *p = ' ';
++p;
}
for (i = j = 0; !pdot || j < prec; ++j) {
if (UNLIKELY(!((intptr_t)s & (PAGESIZE - 1)))) {
if (!dang && kisdangerous(s)) break;
}
if (!type) {
if (!(t = *s++ & 255)) break;
if ((t & 0300) == 0200) goto ActuallyEmitByte;
++i;
EmitByte:
if (UNLIKELY(quot) && (t == '\\' || ((t == '"' && c == 's') ||
(t == '\'' && c == 'c')))) {
if (p + 2 <= e) {
p[0] = '\\';
p[1] = t;
}
p += 2;
i += 1;
continue;
}
if (pdot ||
(t != 0x7F && (t >= 0x20 || (t == '\n' || t == '\t' ||
t == '\r' || t == '\e')))) {
ActuallyEmitByte:
if (p < e) *p = t;
p += 1;
continue;
} else if (quot) {
if (p + 4 <= e) {
p[0] = '\\';
p[1] = '0' + ((t & 0300) >> 6);
p[2] = '0' + ((t & 0070) >> 3);
p[3] = '0' + ((t & 0007) >> 0);
}
p += 4;
i += 3;
continue;
} else {
/* Control Pictures
2400 0 1 2 3 4 5 6 7 8 9 a b c d e f
2400
2410
2420 */
if (t != 0x7F) {
t += 0x2400;
} else {
t = 0x2421;
}
goto EmitChar;
}
} else if (type < -1) {
if ((t = *s++ & 255)) {
t = kCp437[t];
}
} else if (type < 0) {
t = *(const char16_t *)s;
s += sizeof(char16_t);
if (IsHighSurrogate(t)) {
if (!pdot || j + 1 < prec) {
if (UNLIKELY(!((intptr_t)s & (PAGESIZE - 1)))) {
if (!dang && kisdangerous(s)) break;
}
u = *(const char16_t *)s;
if (IsLowSurrogate(u)) {
t = MergeUtf16(t, u);
s += sizeof(char16_t);
j += 1;
}
} else {
break;
}
} else if (!t) {
break;
}
} else {
t = *(const wchar_t *)s;
s += sizeof(wchar_t);
}
if (!t) break;
++i;
EmitChar:
if (t <= 0x7f) {
goto EmitByte;
} else if (t <= 0x7ff) {
if (p + 2 <= e) {
p[0] = 0300 | (t >> 6);
p[1] = 0200 | (t & 077);
}
p += 2;
} else if (t <= 0xffff) {
if (UNLIKELY(IsSurrogate(t))) {
EncodeReplacementCharacter:
t = 0xfffd;
}
if (p + 3 <= e) {
p[0] = 0340 | (t >> 12);
p[1] = 0200 | ((t >> 6) & 077);
p[2] = 0200 | (t & 077);
}
p += 3;
} else if (~(t >> 18) & 007) {
if (p + 4 <= e) {
p[0] = 0360 | (t >> 18);
p[1] = 0200 | ((t >> 12) & 077);
p[2] = 0200 | ((t >> 6) & 077);
p[3] = 0200 | (t & 077);
}
p += 4;
} else {
goto EncodeReplacementCharacter;
}
}
if (hash) {
if (p < e) *p = hash;
++p;
}
for (; cols > i; --cols) {
if (p < e) {
*p++ = ' ';
} else {
p = kadvance(p, e, cols - i);
break;
}
}
break;
}
break;
}
}
if (p < e) {
*p = 0;
} else if (e > b) {
u = 0;
*--e = 0;
s = "\n...";
if (!(((f - fmt) >= 2 && f[-2] == '\n') ||
((f - fmt) >= 3 && f[-3] == '%' && f[-2] == 'n'))) {
++s;
}
while ((t = *s++) && e > b) {
u = *--e;
*e = t;
}
if ((u & 0300) == 0200) {
while (e > b) {
u = *--e;
*e = '.';
if ((u & 0300) != 0200) {
break;
}
}
}
}
return p - b;
}
/**
* Privileged snprintf().
*
* @param b is buffer, and guaranteed a NUL-terminator if `n>0`
* @param n is number of bytes available in buffer
* @return length of output excluding NUL, which may exceed `n`
* @see kprintf() for documentation
* @asyncsignalsafe
* @vforksafe
*/
privileged size_t ksnprintf(char *b, size_t n, const char *fmt, ...) {
size_t m;
va_list v;
struct Timestamps t = {0};
va_start(v, fmt);
m = kformat(b, n, fmt, v, t);
va_end(v);
return m;
}
/**
* Privileged vsnprintf().
*
* @param b is buffer, and guaranteed a NUL-terminator if `n>0`
* @param n is number of bytes available in buffer
* @return length of output excluding NUL, which may exceed `n`
* @see kprintf() for documentation
* @asyncsignalsafe
* @vforksafe
*/
privileged size_t kvsnprintf(char *b, size_t n, const char *fmt, va_list v) {
struct Timestamps t = {0};
return kformat(b, n, fmt, v, t);
}
/**
* Privileged vprintf.
*
* @see kprintf() for documentation
* @asyncsignalsafe
* @vforksafe
*/
privileged void kvprintf(const char *fmt, va_list v) {
size_t n;
char b[2048];
struct Timestamps t;
if (!v) return;
t = kenter();
n = kformat(b, sizeof(b), fmt, v, t);
klog(b, MIN(n, sizeof(b)));
kleave(t);
}
/**
* Privileged printf().
*
* This function is intended for crash reporting. It's designed to be as
* unbreakable as possible, so that error messages can always be printed
* even when the rest of the runtime is broken. As such, it has continue
* on error semantics, doesn't support buffering between invocations and
* floating point is not supported. Output is also truncated if the line
* gets too long, but care is taken to preserve your newline characters.
* Your errno and GetLastError() state will not be clobbered, and ftrace
* and other runtime magic won't be invoked, since all the runtime magic
* depends on this function.
*
* Directives:
*
* %[FLAGS][WIDTH|*][.[PRECISION|*]][TYPE]SPECIFIER
*
* Specifiers:
*
* - `P` pid
* - `c` char
* - `o` octal
* - `b` binary
* - `s` string
* - `p` pointer
* - `d` decimal
* - `n` newline
* - `u` unsigned
* - `r` carriage
* - `m` strerror
* - `X` uppercase
* - `T` timestamp
* - `x` hexadecimal
*
* Types:
*
* - `hhh` bool
* - `hh` char or cp437
* - `h` short or char16_t
* - `l` long or wchar_t
* - `ll` long long
*
* Flags:
*
* - `0` zero padding
* - `-` flip alignment
* - `!` bypass memory safety
* - `,` thousands grouping w/ comma
* - `'` thousands grouping w/ apostrophe
* - `_` thousands grouping w/ underscore
* - `+` plus leftpad if positive (aligns w/ negatives)
* - ` ` space leftpad if positive (aligns w/ negatives)
* - `#` represent value with literal syntax, e.g. 0x, 0b, quotes
*
* @asyncsignalsafe
* @vforksafe
*/
privileged void kprintf(const char *fmt, ...) {
/* system call support runtime depends on this function */
/* function tracing runtime depends on this function */
/* asan runtime depends on this function */
va_list v;
va_start(v, fmt);
kvprintf(fmt, v);
va_end(v);
}

14
libc/intrin/kprintf.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_KPRINTF_H_
#define COSMOPOLITAN_LIBC_INTRIN_KPRINTF_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void kprintf(const char *, ...);
size_t ksnprintf(char *, size_t, const char *, ...);
void kvprintf(const char *, va_list);
size_t kvsnprintf(char *, size_t, const char *, va_list);
bool kisdangerous(const void *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_KPRINTF_H_ */

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -16,24 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macros.internal.h"
// Stores CPU Timestamp Counter at startup.
//
// It can be useful as an added source of seeding information.
//
// @note rdtsc is a 25 cycle instruction
.initbss 200,_init_kStartTsc
kStartTsc:
.quad 0
.endobj kStartTsc,globl
.previous
.init.start 200,_init_kStartTsc
rdtsc
stosl
xchg %edx,%eax
stosl
.init.end 200,_init_kStartTsc
.source __FILE__
/**
* Timestamp of process start.
*
* @see libc/runtime/winmain.greg.h
* @see libc/crt/crt.S
*/
uint64_t kStartTsc;

30
libc/intrin/nomultics.c Normal file
View file

@ -0,0 +1,30 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
/**
* Controls disablement of MULTICS newlines.
*
* Normally we use `\n` for newlines. If this is `true` then we'll try
* our best to use `\r\n`. This is toggled automatically on Windows or
* when `ioctl(TCSETS)` disables `OPOST`.
*
* @see kprintf()
*/
bool __nomultics;
bool __replmode;

View file

@ -0,0 +1,21 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/runtime/internal.h"
uint32_t __ntconsolemode[2];

View file

@ -1,242 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/limits.h"
#include "libc/log/libfatal.internal.h"
#include "libc/nexgen32e/uart.internal.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/str/tpenc.h"
#include "libc/sysv/consts/nr.h"
/**
* Privileged vprintf.
*
* This will work without any cosmopolitan runtime support once the
* executable has been loaded into memory.
*/
privileged noasan noubsan noinstrument void __vprintf(const char *fmt,
va_list va) {
short w[2];
uint16_t dx;
const void *s;
uint32_t wrote;
unsigned long x;
unsigned char al;
int i, j, t, cstr;
long d, rax, rdi, rsi, rdx, dot;
char c, *p, *e, pad, bits, base, sign, thou, z[28], b[2048];
p = b;
e = p + sizeof(b);
do {
switch ((c = *fmt++)) {
default:
if (p < e) {
*p++ = c;
}
break;
case '\0':
break;
case '%':
dot = 0;
pad = ' ';
sign = 0;
bits = 0;
thou = 0;
w[0] = 0;
w[1] = SHRT_MAX;
NeedMoar:
switch ((c = *fmt++)) {
case '\0':
break;
case 'l':
case 'z':
goto NeedMoar;
case ' ':
case '+':
sign = c;
goto NeedMoar;
case 'e':
dot = 1;
goto NeedMoar;
case ',':
thou = c;
goto NeedMoar;
case 'h':
bits = 16;
goto NeedMoar;
case '0':
pad = c;
/* fallthrough */
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
w[dot] *= 10;
w[dot] += c - '0';
goto NeedMoar;
case '*':
w[dot] = va_arg(va, int);
goto NeedMoar;
case 'd':
d = va_arg(va, long);
ApiAbuse:
x = d;
if (d < 0) {
x = -x;
sign = '-';
}
for (i = j = 0;;) {
z[i++] = x % 10 + '0';
if (!(x /= 10)) break;
if (thou && !(++j % 3)) {
z[i++] = thou;
}
}
if (sign) {
z[i++] = sign;
}
EmitNumber:
while (w[0]-- > i) {
if (p < e) *p++ = pad;
}
do {
if (p < e) *p++ = z[--i];
} while (i);
break;
case 'b':
base = 1;
BinaryNumber:
i = 0;
x = va_arg(va, unsigned long);
do z[i++] = "0123456789abcdef"[x & ((1 << base) - 1)];
while ((x >>= base) && i < w[1]);
goto EmitNumber;
case 'p':
pad = '0';
w[0] = 12;
w[1] = 12;
/* fallthrough */
case 'x':
base = 4;
goto BinaryNumber;
case 'o':
base = 3;
goto BinaryNumber;
case 'c':
cstr = va_arg(va, int);
s = &cstr;
goto EmitString;
case 's':
s = va_arg(va, const void *);
EmitString:
if (!s) {
s = "NULL";
bits = 0;
} else if ((uintptr_t)s < PAGESIZE) {
d = (intptr_t)s;
goto ApiAbuse;
}
for (i = 0; i < w[1]; ++i) {
if (!bits) {
t = ((const char *)s)[i];
EmitByte:
if (t) {
if (p < e) {
*p++ = t;
}
} else {
break;
}
} else {
t = ((const char16_t *)s)[i];
if (t <= 0x7f) {
goto EmitByte;
} else if (t <= 0x7ff) {
if (p + 1 < e) {
p[0] = 0300 | t >> 6;
p[1] = 0200 | x << 8 | t & 077;
p += 2;
}
} else if (p + 2 < e) {
p[0] = 0340 | t >> 12;
p[1] = 0200 | x << 8 | (t >> 6) & 077;
p[2] = 0200 | x << 8 | t & 077;
p += 3;
}
}
}
while (w[0]-- > i) {
if (p < e) *p++ = pad;
}
break;
default:
break;
}
break;
}
} while (c);
if (p == e) {
e[-4] = '.';
e[-3] = '.';
e[-2] = '.';
e[-1] = '\n';
}
if (IsWindows()) {
WriteFile(GetStdHandle(kNtStdErrorHandle), b, p - b, &wrote, 0);
} else if (IsMetal()) {
for (e = p, p = b; p < e; ++p) {
for (;;) {
dx = 0x3F8 + UART_LSR;
asm("inb\t%1,%0" : "=a"(al) : "dN"(dx));
if (al & UART_TTYTXR) break;
asm("pause");
}
dx = 0x3F8;
asm volatile("outb\t%0,%1"
: /* no inputs */
: "a"(*p), "dN"(dx));
}
} else {
asm volatile("syscall"
: "=a"(rax), "=D"(rdi), "=S"(rsi), "=d"(rdx)
: "0"(__NR_write), "1"(2L), "2"(b), "3"(p - b)
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc");
}
}
/**
* Privileged printf.
*
* This will work without any cosmopolitan runtime support once the
* executable has been loaded into memory.
*/
privileged noasan noubsan noinstrument void __printf(const char *fmt, ...) {
/* system call support runtime depends on this function */
/* function tracing runtime depends on this function */
/* asan runtime depends on this function */
va_list va;
va_start(va, fmt);
__vprintf(fmt, va);
va_end(va);
}

View file

@ -16,15 +16,16 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/pushpop.h"
#include "libc/bits/weaken.h"
#include "libc/dce.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
const char kConsoleHandles[2] = {kNtStdInputHandle, kNtStdOutputHandle};
/**
* Exits process faster.
*
@ -32,18 +33,18 @@
* @noreturn
*/
wontreturn void quick_exit(int exitcode) {
int i;
const uintptr_t *p;
if (weaken(fflush)) {
weaken(fflush)(0);
}
if (SupportsWindows() && __ntconsolemode[0]) {
for (i = 0; i < 2; ++i) {
SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]);
}
}
for (p = __fini_array_end; p > __fini_array_start;) {
((void (*)(void))(*--p))();
}
if (SupportsWindows() && __ntconsolemode) {
SetConsoleMode(GetStdHandle(pushpop(kNtStdInputHandle)), __ntconsolemode);
SetConsoleMode(GetStdHandle(pushpop(kNtStdOutputHandle)),
kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput |
kNtEnableVirtualTerminalProcessing);
}
_Exit(exitcode);
}

View file

@ -21,6 +21,7 @@
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
@ -189,7 +190,7 @@ static uintptr_t __ubsan_extend(struct UbsanTypeDescriptor *t, uintptr_t x) {
void __ubsan_abort(const struct UbsanSourceLocation *loc,
const char *description) {
__printf("\r\n%s:%d: ubsan error: %s\r\n", loc->file, loc->line, description);
kprintf("%n%s:%d: ubsan error: %s%n", loc->file, loc->line, description);
if (weaken(__die)) weaken(__die)();
_Exit(134);
}
@ -258,7 +259,7 @@ void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *info,
p = __stpcpy(p, " align ");
p = __intcpy(p, info->alignment);
} else {
p = __stpcpy(p, "insufficient size\r\n\t");
p = __stpcpy(p, "insufficient size%n\t");
p = __stpcpy(p, kind);
p = __stpcpy(p, " address 0x");
p = __fixcpy(p, pointer, sizeof(pointer) * CHAR_BIT);

View file

@ -18,6 +18,6 @@
*/
#include "libc/log/log.h"
noasan const char *GetAddr2linePath(void) {
const char *GetAddr2linePath(void) {
return commandvenv("ADDR2LINE", "addr2line");
}

View file

@ -19,6 +19,7 @@
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/color.internal.h"
#include "libc/log/gdb.h"
#include "libc/log/internal.h"
@ -50,17 +51,17 @@
* @return gdb pid if continuing, 0 if detached, or -1 w/ errno
* @note this is called via eponymous spinlock macro wrapper
*/
relegated int(attachdebugger)(intptr_t continuetoaddr) {
relegated int(AttachDebugger)(intptr_t continuetoaddr) {
int pid, ttyfd;
struct StackFrame *bp;
char pidstr[11], breakcmd[40];
const char *se, *elf, *gdb, *rewind, *layout;
if (IsGenuineCosmo() || !(gdb = GetGdbPath()) ||
if (IsGenuineCosmo() || !(gdb = GetGdbPath()) || !isatty(0) || !isatty(1) ||
(ttyfd = open(_PATH_TTY, O_RDWR | O_CLOEXEC)) == -1) {
return -1;
}
__restore_tty(ttyfd);
snprintf(pidstr, sizeof(pidstr), "%u", getpid());
ksnprintf(pidstr, sizeof(pidstr), "%u", getpid());
layout = "layout asm";
if ((elf = FindDebugBinary())) {
se = "-se";
@ -75,12 +76,12 @@ relegated int(attachdebugger)(intptr_t continuetoaddr) {
continuetoaddr = bp->addr;
}
rewind = "-ex";
snprintf(breakcmd, sizeof(breakcmd), "%s *%#p", "break", continuetoaddr);
ksnprintf(breakcmd, sizeof(breakcmd), "%s *%#p", "break", continuetoaddr);
} else {
rewind = NULL;
breakcmd[0] = '\0';
}
if (!(pid = vfork())) {
if (!(pid = fork())) {
dup2(ttyfd, 0);
dup2(ttyfd, 1);
execv(gdb, (char *const[]){

View file

@ -27,6 +27,7 @@
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
@ -46,8 +47,7 @@
#define kBacktraceMaxFrames 128
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (18 + 1))
static noasan int PrintBacktraceUsingAddr2line(int fd,
const struct StackFrame *bp) {
static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
ssize_t got;
intptr_t addr;
size_t i, j, gi;
@ -57,10 +57,32 @@ static noasan int PrintBacktraceUsingAddr2line(int fd,
const struct StackFrame *frame;
char *debugbin, *p1, *p2, *p3, *addr2line;
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
if (IsOpenbsd()) return -1;
if (IsWindows()) return -1;
if (!(debugbin = FindDebugBinary())) return -1;
if (!(addr2line = GetAddr2linePath())) return -1;
if (!(debugbin = FindDebugBinary())) {
if (IsLinux()) {
kprintf("warning: can't find debug binary try setting COMDBG%n");
}
return -1;
}
if (!(addr2line = GetAddr2linePath())) {
if (IsLinux()) {
kprintf("warning: can't find addr2line try setting ADDR2LINE%n");
}
return -1;
}
/*
* DWARF is a weak standard. If we build on Linux then only the
* precice same version of the same tools on Linux can be counted upon
* to work reliably. So if it's not Linux, we fall back to our builtin
* tooling which can be counted upon.
*/
if (!IsLinux()) {
kprintf("note: won't print addr2line backtrace on non-linux%n");
return -1;
}
i = 0;
j = 0;
argv[i++] = "addr2line";
@ -92,8 +114,8 @@ static noasan int PrintBacktraceUsingAddr2line(int fd,
if (!(pid = vfork())) {
sigprocmask(SIG_SETMASK, &savemask, NULL);
dup2(pipefds[1], 1);
close(pipefds[0]);
close(pipefds[1]);
if (pipefds[0] != 1) close(pipefds[0]);
if (pipefds[1] != 1) close(pipefds[1]);
execvp(addr2line, argv);
_exit(127);
}
@ -101,36 +123,6 @@ static noasan int PrintBacktraceUsingAddr2line(int fd,
while ((got = read(pipefds[0], buf, kBacktraceBufSize)) > 0) {
p1 = buf;
p3 = p1 + got;
/*
* Remove deep libc error reporting facilities from backtraces.
*
* For example, if the following shows up in Emacs:
*
* 40d097: __die at libc/log/die.c:33
* 434daa: __asan_die at libc/intrin/asan.c:483
* 435146: __asan_report_memory_fault at libc/intrin/asan.c:524
* 435b32: __asan_report_store at libc/intrin/asan.c:719
* 43472e: __asan_report_store1 at libc/intrin/somanyasan.S:118
* 40c3a9: GetCipherSuite at net/https/getciphersuite.c:80
* 4383a5: GetCipherSuite_test at test/net/https/getciphersuite.c:23
* ...
*
* Then it's unpleasant to need to press C-x C-n six times.
*/
#if 0
while ((p2 = memchr(p1, '\n', p3 - p1))) {
if (memmem(p1, p2 - p1, ": __asan_", 9) ||
memmem(p1, p2 - p1, ": __die", 7)) {
memmove(p1, p2 + 1, p3 - (p2 + 1));
p3 -= p2 + 1 - p1;
} else {
p1 = p2 + 1;
break;
}
}
#endif
/*
* remove racist output from gnu tooling, that can't be disabled
* otherwise, since it breaks other tools like emacs that aren't
@ -165,7 +157,7 @@ static noasan int PrintBacktraceUsingAddr2line(int fd,
}
}
static noasan int PrintBacktrace(int fd, const struct StackFrame *bp) {
static int PrintBacktrace(int fd, const struct StackFrame *bp) {
if (!IsTiny()) {
if (PrintBacktraceUsingAddr2line(fd, bp) != -1) {
return 0;
@ -174,21 +166,23 @@ static noasan int PrintBacktrace(int fd, const struct StackFrame *bp) {
return PrintBacktraceUsingSymbols(fd, bp, GetSymbolTable());
}
noasan void ShowBacktrace(int fd, const struct StackFrame *bp) {
void ShowBacktrace(int fd, const struct StackFrame *bp) {
#ifdef __FNO_OMIT_FRAME_POINTER__
/* asan runtime depends on this function */
static bool noreentry;
++g_ftrace;
--g_ftrace;
if (!bp) bp = __builtin_frame_address(0);
if (!noreentry) {
noreentry = true;
PrintBacktrace(fd, bp);
noreentry = false;
} else {
kprintf("warning: re-entered ShowBackTrace()%n");
}
--g_ftrace;
++g_ftrace;
#else
__printf("ShowBacktrace() needs these flags to show C backtrace:\n"
"\t-D__FNO_OMIT_FRAME_POINTER__\n"
"\t-fno-omit-frame-pointer\n");
kprintf("ShowBacktrace() needs these flags to show C backtrace:%n"
"\t-D__FNO_OMIT_FRAME_POINTER__%n"
"\t-fno-omit-frame-pointer%n");
#endif
}

View file

@ -22,8 +22,8 @@
#include "libc/calls/calls.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/gc.internal.h"
#include "libc/nexgen32e/stackframe.h"
@ -51,17 +51,16 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
int i, symbol, addend;
struct Garbages *garbage;
const struct StackFrame *frame;
++g_ftrace;
if (!bp) bp = __builtin_frame_address(0);
garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0;
for (i = 0, frame = bp; frame; frame = frame->next) {
if (!IsValidStackFramePointer(frame)) {
__printf("%p corrupt frame pointer\n", frame);
kprintf("%p corrupt frame pointer%n", frame);
break;
}
if (++i == LIMIT) {
__printf("<truncated backtrace>\n");
kprintf("<truncated backtrace>%n");
break;
}
addr = frame->addr;
@ -85,9 +84,8 @@ noinstrument noasan int PrintBacktraceUsingSymbols(int fd,
} else {
addend = 0;
}
__printf("%p %p %s%+d\r\n", frame, addr, __get_symbol_name(st, symbol),
addend);
kprintf("%012lx %012lx %s%+d\r%n", frame, addr,
__get_symbol_name(st, symbol), addend);
}
--g_ftrace;
return 0;
}

View file

@ -17,8 +17,8 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
@ -35,8 +35,8 @@
relegated void ___check_fail_ndebug(uint64_t want, uint64_t got,
const char *opchar) {
__restore_tty(1);
__printf("\n%serror: %s: check failed: 0x%x %s 0x%x (%s)\n",
!g_isterminalinarticulate ? "\e[J" : "", program_invocation_name,
want, opchar, got, strerror(errno));
kprintf("%n%serror: %s: check failed: 0x%x %s 0x%x (%s)%n",
!g_isterminalinarticulate ? "\e[J" : "", program_invocation_name,
want, opchar, got, strerror(errno));
exit(1);
}

View file

@ -18,10 +18,10 @@ COSMOPOLITAN_C_START_
extern volatile int g_gdbsync;
int gdbexec(const char *);
int attachdebugger(intptr_t);
int AttachDebugger(intptr_t);
#define attachdebugger(CONTINUE_TO_ADDR) /* shorten backtraces */ \
SYNCHRONIZE_DEBUGGER((attachdebugger)(CONTINUE_TO_ADDR))
#define AttachDebugger(CONTINUE_TO_ADDR) /* shorten backtraces */ \
SYNCHRONIZE_DEBUGGER((AttachDebugger)(CONTINUE_TO_ADDR))
#define SYNCHRONIZE_DEBUGGER(PID) \
({ \
@ -40,20 +40,20 @@ int attachdebugger(intptr_t);
Pid; \
})
#define __inline_wait4(PID, OPT_OUT_WSTATUS, OPTIONS, OPT_OUT_RUSAGE) \
({ \
int64_t WaAx; \
if (!IsWindows()) { \
asm volatile("mov\t%5,%%r10\n\t" \
"syscall" \
: "=a"(WaAx) \
: "0"(__NR_wait4), "D"(PID), "S"(OPT_OUT_WSTATUS), \
"d"(OPTIONS), "g"(OPT_OUT_RUSAGE) \
: "rcx", "r10", "r11", "cc", "memory"); \
} else { \
#define __inline_wait4(PID, OPT_OUT_WSTATUS, OPTIONS, OPT_OUT_RUSAGE) \
({ \
int64_t WaAx; \
if (!IsWindows()) { \
asm volatile("mov\t%5,%%r10\n\t" \
"syscall" \
: "=a"(WaAx) \
: "0"(__NR_wait4), "D"(PID), "S"(OPT_OUT_WSTATUS), \
"d"(OPTIONS), "g"(OPT_OUT_RUSAGE) \
: "rcx", "r8", "r9", "r10", "r11", "memory", "cc"); \
} else { \
WaAx = sys_wait4_nt(PID, OPT_OUT_WSTATUS, OPTIONS, OPT_OUT_RUSAGE); \
} \
WaAx; \
} \
WaAx; \
})
COSMOPOLITAN_C_END_

View file

@ -7,11 +7,11 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern hidden int kCrashSigs[8];
extern hidden int kCrashSigs[7];
extern hidden bool g_isrunningundermake;
extern hidden bool g_isterminalinarticulate;
extern hidden struct termios g_oldtermios;
extern hidden struct sigaction g_oldcrashacts[8];
extern hidden struct sigaction g_oldcrashacts[7];
void __start_fatal(const char *, int) hidden;
void __oncrash(int, struct siginfo *, struct ucontext *) relegated;

View file

@ -13,9 +13,6 @@ COSMOPOLITAN_C_START_
extern char __fatalbuf[];
void __printf(const char *, ...);
void __vprintf(const char *, va_list);
forceinline long __sysv_exit(long rc) {
long ax;
#if defined(__MNO_RED_ZONE__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)

View file

@ -19,6 +19,7 @@
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h"
@ -30,6 +31,7 @@
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/color.internal.h"
#include "libc/log/gdb.h"
@ -59,6 +61,8 @@
* @see libc/onkill.c
*/
STATIC_YOINK("strerror_r");
static const char kGregOrder[17] forcealign(1) = {
13, 11, 8, 14, 12, 9, 10, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7,
};
@ -72,9 +76,9 @@ static const char kCpuFlags[12] forcealign(1) = "CVPRAKZSTIDO";
static const char kFpuExceptions[6] forcealign(1) = "IDZOUP";
/* <SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
int kCrashSigs[8];
struct sigaction g_oldcrashacts[8];
static const char kCrashSigNames[8][5] forcealign(1) = {
int kCrashSigs[7];
struct sigaction g_oldcrashacts[7];
static const char kCrashSigNames[7][5] forcealign(1) = {
"QUIT", //
"FPE", //
"ILL", //
@ -82,11 +86,10 @@ static const char kCrashSigNames[8][5] forcealign(1) = {
"TRAP", //
"ABRT", //
"BUS", //
"PIPE", //
};
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
relegated static const char *TinyStrSignal(int sig) {
static relegated noasan noinstrument const char *TinyStrSignal(int sig) {
size_t i;
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
if (kCrashSigs[i] && sig == kCrashSigs[i]) {
@ -100,14 +103,15 @@ relegated static void ShowFunctionCalls(ucontext_t *ctx) {
struct StackFrame *bp;
struct StackFrame goodframe;
if (!ctx->uc_mcontext.rip) {
__printf("%s is NULL can't show backtrace\n", "RIP");
kprintf("%s is NULL can't show backtrace%n", "RIP");
} else if (!ctx->uc_mcontext.rbp) {
__printf("%s is NULL can't show backtrace\n", "RBP");
kprintf("%s is NULL can't show backtrace%n", "RBP");
} else {
goodframe.next = (struct StackFrame *)ctx->uc_mcontext.rbp;
goodframe.addr = ctx->uc_mcontext.rip;
bp = &goodframe;
ShowBacktrace(2, bp);
kprintf("%n");
}
}
@ -153,7 +157,7 @@ relegated static void ShowGeneralRegisters(ucontext_t *ctx) {
long double st;
char *p, buf[128];
p = buf;
*p++ = '\n';
printf("%n");
for (i = 0, j = 0, k = 0; i < ARRAYLEN(kGregNames); ++i) {
if (j > 0) *p++ = ' ';
if (!(s = kGregNames[(unsigned)kGregOrder[i]])[2]) *p++ = ' ';
@ -172,9 +176,9 @@ relegated static void ShowGeneralRegisters(ucontext_t *ctx) {
x = st * 1000;
if (x < 0) x = -x, *p++ = '-';
p = __uintcpy(p, x / 1000), *p++ = '.';
p = __uintcpy(p, x % 1000), *p++ = '\n';
p = __uintcpy(p, x % 1000);
*p = 0;
__printf("%s", buf);
kprintf("%s%n", buf);
p = buf;
}
}
@ -182,14 +186,14 @@ relegated static void ShowGeneralRegisters(ucontext_t *ctx) {
p, ctx->uc_mcontext.gregs[REG_EFL],
ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->swd : 0,
ctx->uc_mcontext.fpregs ? ctx->uc_mcontext.fpregs->mxcsr : 0);
__printf("%s\n", buf);
kprintf("%s%n", buf);
}
relegated static void ShowSseRegisters(ucontext_t *ctx) {
size_t i;
char *p, buf[128];
if (ctx->uc_mcontext.fpregs) {
__printf("\n");
kprintf("%n");
for (i = 0; i < 8; ++i) {
p = buf;
if (i >= 10) {
@ -214,7 +218,7 @@ relegated static void ShowSseRegisters(ucontext_t *ctx) {
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[1], 64);
p = __fixcpy(p, ctx->uc_mcontext.fpregs->xmm[i + 8].u64[0], 64);
*p = 0;
__printf("XMM%s\n", buf);
kprintf("XMM%s%n", buf);
}
}
}
@ -226,48 +230,49 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
int i;
char *p;
char host[64];
intptr_t stackaddr;
struct utsname names;
static char buf[4096];
if (weaken(ShowCrashReportHook)) {
ShowCrashReportHook(2, err, sig, si, ctx);
}
names.sysname[0] = 0;
names.release[0] = 0;
names.version[0] = 0;
names.nodename[0] = 0;
__stpcpy(host, "unknown");
gethostname(host, sizeof(host));
uname(&names);
p = buf;
__printf("\n%serror%s: Uncaught SIG%s",
!g_isterminalinarticulate ? "\e[30;101m" : "",
!g_isterminalinarticulate ? "\e[0m" : "", TinyStrSignal(sig));
stackaddr = GetStackAddr(0);
if (ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) &&
ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE)) {
__printf(" (Stack Overflow)");
} else if (si) {
__printf(" (%s)", GetSiCodeName(sig, si->si_code));
}
__printf(" on %s pid %d\n %s\n %s\n", host, __getpid(),
program_invocation_name, strerror(err));
if (uname(&names) != -1) {
__printf(" %s %s %s %s\n", names.sysname, names.nodename, names.release,
names.version);
}
errno = err;
kprintf("%n%serror%s: Uncaught SIG%s (%s) on %s pid %d%n"
" %s%n"
" %m%n"
" %s %s %s %s%n",
!g_isterminalinarticulate ? "\e[30;101m" : "",
!g_isterminalinarticulate ? "\e[0m" : "", TinyStrSignal(sig),
(ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) &&
ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE))
? "Stack Overflow"
: GetSiCodeName(sig, si->si_code),
host, __getpid(), program_invocation_name, names.sysname,
names.nodename, names.release, names.version);
if (ctx) {
__printf("\n");
kprintf("%n");
ShowFunctionCalls(ctx);
ShowGeneralRegisters(ctx);
ShowSseRegisters(ctx);
}
__printf("\n");
kprintf("%n");
PrintMemoryIntervals(2, &_mmi);
/* PrintSystemMappings(2); */
if (__argv) {
for (i = 0; i < __argc; ++i) {
if (!__argv[i]) continue;
if (IsAsan() && !__asan_is_valid(__argv[i], 1)) continue;
__printf("%s ", __argv[i]);
kprintf("%s ", __argv[i]);
}
}
__printf("\n");
kprintf("%n");
}
relegated static void RestoreDefaultCrashSignalHandlers(void) {
@ -280,6 +285,21 @@ relegated static void RestoreDefaultCrashSignalHandlers(void) {
}
}
static wontreturn noasan relegated noinstrument void __minicrash(
int sig, struct siginfo *si, ucontext_t *ctx, const char *kind) {
kprintf("%n"
"%n"
"CRASHED %s WITH SIG%s%n"
"%s%n"
"RIP %x%n"
"RSP %x%n"
"RBP %x%n"
"%n",
kind, TinyStrSignal(sig), __argv[0], ctx ? ctx->uc_mcontext.rip : 0,
ctx ? ctx->uc_mcontext.rsp : 0, ctx ? ctx->uc_mcontext.rbp : 0);
quick_exit(119);
}
/**
* Crashes in a developer-friendly human-centric way.
*
@ -293,48 +313,47 @@ relegated static void RestoreDefaultCrashSignalHandlers(void) {
*
* This function never returns, except for traps w/ human supervision.
*/
noasan relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) {
noasan relegated noinstrument void __oncrash(int sig, struct siginfo *si,
ucontext_t *ctx) {
intptr_t rip;
int gdbpid, err;
static bool noreentry, notpossible;
++g_ftrace;
rip = ctx ? ctx->uc_mcontext.rip : 0;
--g_ftrace;
if (cmpxchg(&noreentry, false, true)) {
err = errno;
if ((gdbpid = IsDebuggerPresent(true))) {
DebugBreak();
} else if (g_isterminalinarticulate || g_isrunningundermake) {
gdbpid = -1;
} else if (FindDebugBinary()) {
RestoreDefaultCrashSignalHandlers();
gdbpid =
attachdebugger(((sig == SIGTRAP || sig == SIGQUIT) &&
(rip >= (intptr_t)&_base && rip < (intptr_t)&_etext))
? rip
: 0);
}
if (!(gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT))) {
__restore_tty(1);
ShowCrashReport(err, sig, si, ctx);
_Exit(128 + sig);
if (!__vforked) {
rip = ctx ? ctx->uc_mcontext.rip : 0;
err = errno;
if ((gdbpid = IsDebuggerPresent(true))) {
DebugBreak();
} else if (g_isterminalinarticulate || g_isrunningundermake) {
gdbpid = -1;
} else if (IsLinux() && FindDebugBinary()) {
RestoreDefaultCrashSignalHandlers();
gdbpid = AttachDebugger(
((sig == SIGTRAP || sig == SIGQUIT) &&
(rip >= (intptr_t)&_base && rip < (intptr_t)&_etext))
? rip
: 0);
}
if (!(gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT))) {
__restore_tty(1);
ShowCrashReport(err, sig, si, ctx);
quick_exit(128 + sig);
}
} else {
__minicrash(sig, si, ctx, "WHILE VFORKED");
}
} else if (sig == SIGTRAP) {
/* chances are IsDebuggerPresent() confused strace w/ gdb */
++g_ftrace;
return;
} else if (cmpxchg(&notpossible, false, true)) {
__printf("\n"
"\n"
"CRASHED WHILE CRASHING WITH SIG%s\n"
"%s\n"
"RIP %x\n"
"RSP %x\n"
"RBP %x\n"
"\n",
TinyStrSignal(sig), __argv[0], rip, ctx ? ctx->uc_mcontext.rsp : 0,
ctx ? ctx->uc_mcontext.rbp : 0);
_Exit(119);
__minicrash(sig, si, ctx, "WHILE CRASHING");
} else {
for (;;) {
asm("ud2");
}
}
noreentry = false;
--g_ftrace;
++g_ftrace;
}

View file

@ -90,15 +90,6 @@ __oncrash_sigbus:
ret
.endfn __oncrash_sigbus,globl
.org 11*7
__oncrash_sigpipe:
push %rbp
mov %rsp,%rbp
call __oncrash
pop %rbp
ret
.endfn __oncrash_sigpipe,globl
// </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c
.endobj __oncrash_thunks,globl

View file

@ -17,7 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/fmt.h"
#include "libc/log/libfatal.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
#include "libc/nexgen32e/gc.internal.h"
#include "libc/stdio/stdio.h"
@ -30,27 +30,27 @@ void PrintGarbage(void) {
size_t i;
char name[19];
const char *symbol;
__printf("\n");
__printf(" SHADOW STACK @ 0x%p\n", __builtin_frame_address(0));
__printf("garbage entry parent frame original ret callback arg \n");
__printf("-------------- -------------- ------------------ ------------------ ------------------\n");
kprintf("%n");
kprintf(" SHADOW STACK @ %p%n", __builtin_frame_address(0));
kprintf("garbage ent. parent frame original ret callback arg %n");
kprintf("------------ ------------ ------------------ ------------------ ------------------%n");
if (__garbage.i) {
for (i = __garbage.i; i--;) {
symbol = __get_symbol_by_addr(__garbage.p[i].ret);
if (symbol) {
snprintf(name, sizeof(name), "%s", symbol);
ksnprintf(name, sizeof(name), "%s", symbol);
} else {
snprintf(name, sizeof(name), "0x%012lx", __garbage.p[i].ret);
ksnprintf(name, sizeof(name), "%#014lx", __garbage.p[i].ret);
}
__printf("0x%p 0x%p %18s %18s 0x%016lx\n",
__garbage.p + i,
__garbage.p[i].frame,
name,
__get_symbol_by_addr(__garbage.p[i].fn),
__garbage.p[i].arg);
kprintf("%12lx %12lx %18s %18s %#18lx%n",
__garbage.p + i,
__garbage.p[i].frame,
name,
__get_symbol_by_addr(__garbage.p[i].fn),
__garbage.p[i].arg);
}
} else {
__printf("%14s %14s %18s %18s %18s\n","empty","-","-","-","-");
kprintf("%12s %12s %18s %18s %18s%n","empty","-","-","-","-");
}
__printf("\n");
kprintf("%n");
}

View file

@ -59,7 +59,6 @@ void ShowCrashReports(void) {
kCrashSigs[4] = SIGTRAP; /* bad system call */
kCrashSigs[5] = SIGABRT; /* abort() called */
kCrashSigs[6] = SIGBUS; /* misaligned, noncanonical ptr, etc. */
kCrashSigs[7] = SIGPIPE; /* write to closed thing */
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
bzero(&sa, sizeof(sa));
ss.ss_flags = 0;

View file

@ -189,10 +189,8 @@
.endm
// LOOP Instruction Replacement.
// With its mop-Fusion Mexican equivalent.
// Thus avoiding 3x legacy pipeline slowdown.
.macro .loop label:req
.byte 0x83,0xe9,0x01 # sub $1,%ecx
.byte 0x83,0xe9,0x01 # sub §1,%ecx
jnz \label
.endm

View file

@ -5,6 +5,7 @@
#include "libc/nt/struct/linkedlist.h"
#include "libc/nt/struct/securityattributes.h"
#include "libc/nt/struct/systemtime.h"
#include "libc/nt/thunk/msabi.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
/* ░░░░
@ -115,6 +116,9 @@ bool32 GetSystemTimeAdjustment(uint32_t *lpTimeAdjustment,
uint32_t *lpTimeIncrement,
bool32 *lpTimeAdjustmentDisabled);
#if ShouldUseMsabiAttribute()
#include "libc/nt/thunk/synchronization.inc"
#endif /* ShouldUseMsabiAttribute() */
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NT_SYNCHRONIZATION_H_ */

View file

@ -3,6 +3,8 @@
#define FlushViewOfFile(...) __imp_FlushViewOfFile(__VA_ARGS__)
#define UnmapViewOfFile(...) __imp_UnmapViewOfFile(__VA_ARGS__)
extern typeof(LocalFree) *const __imp_LocalFree __msabi;
extern typeof(VirtualProtect) *const __imp_VirtualProtect __msabi;
extern typeof(UnmapViewOfFile) *const __imp_UnmapViewOfFile __msabi;
extern typeof(FlushViewOfFile) *const __imp_FlushViewOfFile __msabi;
extern typeof(MapViewOfFileExNuma) *const __imp_MapViewOfFileExNuma __msabi;

View file

@ -17,3 +17,6 @@ extern typeof(GetCurrentProcessId) *const __imp_GetCurrentProcessId __msabi;
#define CreateProcess(...) __imp_CreateProcessW(__VA_ARGS__)
extern typeof(CreateProcess) *const __imp_CreateProcessW __msabi;
extern typeof(FormatMessage) *const __imp_FormatMessageW __msabi;
extern typeof(SetLastError) *const __imp_SetLastError __msabi;

View file

@ -31,3 +31,6 @@ extern typeof(GetCurrentProcess) *const __imp_GetCurrentProcess __msabi;
#define GetModuleFileName(...) __imp_GetModuleFileNameW(__VA_ARGS__)
extern typeof(GetModuleFileName) *const __imp_GetModuleFileNameW __msabi;
extern typeof(GetLastError) *const __imp_GetLastError __msabi;
extern typeof(ExitProcess) *const __imp_ExitProcess __msabi;

View file

@ -0,0 +1 @@
extern typeof(SleepEx) *const __imp_SleepEx __msabi;

View file

@ -4,8 +4,22 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
bool IsAtLeastWindows10(void) pureconst;
bool32 GetVersionEx(struct NtOsVersionInfo *lpVersionInformation);
#if defined(__GCC_ASM_FLAG_OUTPUTS__) && !defined(__STRICT_ANSI__)
#define IsAtLeastWindows10() \
({ \
long ReG; \
bool NoTbelow; \
asm("mov\t%%gs:96,%1\r\n" \
"cmpb\t%2,280(%1)" \
: "=@ccnb"(NoTbelow), "=l"(ReG) \
: "i"(10)); \
NoTbelow; \
})
#endif
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NT_VERSION_H_ */

View file

@ -16,13 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/pushpop.h"
#include "libc/bits/weaken.h"
#include "libc/dce.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/pedef.internal.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
@ -38,18 +32,8 @@
* @noreturn
*/
wontreturn void exit(int exitcode) {
const uintptr_t *p;
if (weaken(__cxa_finalize)) {
weaken(__cxa_finalize)(NULL);
}
for (p = __fini_array_end; p > __fini_array_start;) {
((void (*)(void))(*--p))();
}
if (SupportsWindows() && __ntconsolemode) {
SetConsoleMode(GetStdHandle(pushpop(kNtStdInputHandle)), __ntconsolemode);
SetConsoleMode(GetStdHandle(pushpop(kNtStdOutputHandle)),
kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput |
kNtEnableVirtualTerminalProcessing);
}
_Exit(exitcode);
quick_exit(exitcode);
}

View file

@ -17,9 +17,14 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/nt/process.h"
extern int __pid;
/**
* Creates new process.
@ -29,7 +34,7 @@
*/
int fork(void) {
axdx_t ad;
int ax, dx;
int ax, dx, parent;
if (!IsWindows()) {
ad = sys_fork();
ax = ad.ax;
@ -43,7 +48,19 @@ int fork(void) {
ax = sys_fork_nt();
}
if (!ax) {
__onfork();
if (!IsWindows()) {
dx = sys_getpid().ax;
} else {
dx = GetCurrentProcessId();
}
parent = __pid;
__pid = dx;
SYSDEBUG("fork() → 0 (child of %d)", parent);
if (weaken(__onfork)) {
weaken(__onfork)();
}
} else {
SYSDEBUG("fork() → %d% m", ax);
}
return ax;
}

View file

@ -18,6 +18,7 @@
*/
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/rdtsc.h"
@ -91,9 +92,9 @@ privileged noinstrument noasan noubsan void ftracer(void) {
if ((symbol = __get_symbol(g_symbols, frame->addr)) != -1 &&
symbol != g_lastsymbol) {
g_lastsymbol = symbol;
__printf("+ %*s%s %d\r\n", GetNestingLevel(frame) * 2, "",
__get_symbol_name(g_symbols, symbol),
(long)(unsignedsubtract(stamp, laststamp) / 3.3));
kprintf("+ %*s%s %d\r\n", GetNestingLevel(frame) * 2, "",
__get_symbol_name(g_symbols, symbol),
(long)(unsignedsubtract(stamp, laststamp) / 3.3));
laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
}
}
@ -110,9 +111,9 @@ textstartup void ftrace_install(void) {
ftrace_enabled = 1;
__hook(ftrace_hook, g_symbols);
} else {
__printf("error: --ftrace failed to open symbol table\r\n");
kprintf("error: --ftrace failed to open symbol table\r\n");
}
} else {
__printf("error: --ftrace needs concomitant .com.dbg binary\r\n");
kprintf("error: --ftrace needs concomitant .com.dbg binary\r\n");
}
}

View file

@ -16,9 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/pushpop.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/runtime/internal.h"
#include "libc/str/str.h"
@ -32,25 +30,23 @@ struct DosArgv {
wint_t wc;
};
static textwindows noasan wint_t DecodeDosArgv(const char16_t **s) {
textwindows noasan void DecodeDosArgv(int ignore, struct DosArgv *st) {
wint_t x, y;
for (;;) {
if (!(x = *(*s)++)) break;
if (IsUtf16Cont(x)) continue;
if (IsUcs2(x)) {
return x;
} else {
if ((y = *(*s)++)) {
return MergeUtf16(x, y);
if (!(x = *st->s++)) break;
if (!IsUcs2(x)) {
if ((y = *st->s++)) {
x = MergeUtf16(x, y);
} else {
return 0;
x = 0;
}
}
break;
}
return x;
st->wc = x;
}
static textwindows noasan void AppendDosArgv(struct DosArgv *st, wint_t wc) {
static textwindows noasan void AppendDosArgv(wint_t wc, struct DosArgv *st) {
uint64_t w;
w = tpenc(wc);
do {
@ -59,6 +55,16 @@ static textwindows noasan void AppendDosArgv(struct DosArgv *st, wint_t wc) {
} while (w >>= 8);
}
static textwindows noasan int Count(int c, struct DosArgv *st) {
int ignore, n = 0;
asm("" : "=g"(ignore));
while (st->wc == c) {
DecodeDosArgv(ignore, st);
n++;
}
return n;
}
/**
* Tokenizes and transcodes Windows NT CLI args, thus avoiding
* CommandLineToArgv() schlepping in forty megs of dependencies.
@ -81,49 +87,60 @@ static textwindows noasan void AppendDosArgv(struct DosArgv *st, wint_t wc) {
textwindows noasan int GetDosArgv(const char16_t *cmdline, char *buf,
size_t size, char **argv, size_t max) {
bool inquote;
size_t i, argc, slashes, quotes;
struct DosArgv st;
st.s = cmdline;
st.p = buf;
st.pe = buf + size;
int i, argc, slashes, quotes, ignore;
static struct DosArgv st_;
struct DosArgv *st = &st_;
asm("" : "=g"(ignore));
asm("" : "+r"(st));
st->s = cmdline;
st->p = buf;
st->pe = buf + size;
argc = 0;
st.wc = DecodeDosArgv(&st.s);
while (st.wc) {
while (st.wc && (st.wc == ' ' || st.wc == '\t')) {
st.wc = DecodeDosArgv(&st.s);
DecodeDosArgv(ignore, st);
while (st->wc) {
while (st->wc && (st->wc == ' ' || st->wc == '\t')) {
DecodeDosArgv(ignore, st);
}
if (!st.wc) break;
if (!st->wc) break;
if (++argc < max) {
argv[argc - 1] = st.p < st.pe ? st.p : NULL;
argv[argc - 1] = st->p < st->pe ? st->p : NULL;
}
inquote = false;
while (st.wc) {
if (!inquote && (st.wc == ' ' || st.wc == '\t')) break;
if (st.wc == '"' || st.wc == '\\') {
slashes = 0;
quotes = 0;
while (st.wc == '\\') st.wc = DecodeDosArgv(&st.s), slashes++;
while (st.wc == '"') st.wc = DecodeDosArgv(&st.s), quotes++;
while (st->wc) {
if (!inquote && (st->wc == ' ' || st->wc == '\t')) break;
if (st->wc == '"' || st->wc == '\\') {
slashes = Count('\\', st);
quotes = Count('"', st);
if (!quotes) {
while (slashes--) AppendDosArgv(&st, '\\');
while (slashes--) {
AppendDosArgv('\\', st);
}
} else {
while (slashes >= 2) AppendDosArgv(&st, '\\'), slashes -= 2;
if (slashes) AppendDosArgv(&st, '"'), quotes--;
while (slashes >= 2) {
AppendDosArgv('\\', st);
slashes -= 2;
}
if (slashes) {
AppendDosArgv('"', st);
quotes--;
}
if (quotes > 0) {
if (!inquote) quotes--;
for (i = 3; i <= quotes + 1; i += 3) AppendDosArgv(&st, '"');
for (i = 3; i <= quotes + 1; i += 3) {
AppendDosArgv('"', st);
}
inquote = (quotes % 3 == 0);
}
}
} else {
AppendDosArgv(&st, st.wc);
st.wc = DecodeDosArgv(&st.s);
AppendDosArgv(st->wc, st);
DecodeDosArgv(ignore, st);
}
}
AppendDosArgv(&st, '\0');
AppendDosArgv('\0', st);
}
AppendDosArgv(&st, '\0');
if (size) buf[min(st.p - buf, size - 1)] = '\0';
AppendDosArgv('\0', st);
if (size) buf[min(st->p - buf, size - 1)] = '\0';
if (max) argv[min(argc, max - 1)] = NULL;
return argc;
}

View file

@ -32,7 +32,6 @@ static textwindows noasan noinstrument axdx_t Recode16to8(char *dst,
wint_t x, y;
for (v = r.ax = 0, r.dx = 0;;) {
if (!(x = src[r.dx++])) break;
if (IsUtf16Cont(x)) continue;
if (!IsUcs2(x)) {
y = src[r.dx++];
x = MergeUtf16(x, y);

View file

@ -0,0 +1,83 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
/**
* Returns path of executable interperter.
*
* Unlike `program_executable_name` which is designed to figure out the
* absolute path of the first argument passed to `execve()`, what we do
* here is probe things like `/proc` and `sysctl()` to figure out if we
* were launched by something like `ape-loader`, and then we return its
* path. If we can't determine that path, possibly because we're on XNU
* or OpenBSD, then we return -1 with an error code.
*
* @param p receives utf8 output
* @param n is byte size of res buffer
* @return p on success or null w/ errno if out of buf or error
* @see program_invocation_short_name
* @see program_invocation_name
* @see program_executable_name
*/
char *GetInterpreterExecutableName(char *p, size_t n) {
int e;
size_t m;
int cmd[4];
ssize_t rc;
char *r, *t;
e = errno;
if (n < 2) {
errno = ENAMETOOLONG;
} else if (IsWindows()) {
if (strlen(program_executable_name) < n) {
strcpy(p, program_executable_name);
return p;
}
errno = ENAMETOOLONG;
} else if ((rc = sys_readlinkat(AT_FDCWD, "/proc/self/exe", p, n - 1)) > 0) {
p[rc] = 0;
return p;
} else if ((rc = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", p, n - 1)) >
0) {
errno = e;
p[n] = 0;
return p;
} else if (IsFreebsd() || IsNetbsd()) {
cmd[0] = 1 /* CTL_KERN */;
cmd[1] = 14 /* KERN_PROC */;
if (IsFreebsd()) {
cmd[2] = 12 /* KERN_PROC_PATHNAME */;
} else {
cmd[2] = 5 /* KERN_PROC_PATHNAME */;
}
cmd[3] = -1; /* current process */
if (sysctl(cmd, ARRAYLEN(cmd), p, &n, 0, 0) != -1) {
errno = e;
return p;
}
}
return 0;
}

View file

@ -12,7 +12,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
extern uint32_t __ntconsolemode;
extern uint32_t __ntconsolemode[2];
extern const char v_ntsubsystem[] __attribute__((__weak__));
extern const uintptr_t __fini_array_end[] __attribute__((__weak__));
extern const uintptr_t __fini_array_start[] __attribute__((__weak__));

View file

@ -21,8 +21,9 @@ COSMOPOLITAN_C_START_
#define kFixedmapStart _kMem(0x300000000000, 0x000040000000)
#define kFixedmapSize \
_kMem(0x400000000000 - 0x300000000000, 0x000070000000 - 0x000040000000)
#define _kMmi(VSPACE) \
ROUNDUP(VSPACE / FRAMESIZE * sizeof(struct MemoryInterval), FRAMESIZE)
#define _kMmi(VSPACE) \
ROUNDUP(VSPACE / FRAMESIZE * (intptr_t)sizeof(struct MemoryInterval), \
FRAMESIZE)
#define _kMem(NORMAL, WIN7) \
(!(IsWindows() && NtGetVersion() < kNtVersionWindows10) ? NORMAL : WIN7)
@ -35,7 +36,7 @@ struct MemoryInterval {
};
struct MemoryIntervals {
long i, n;
size_t i, n;
struct MemoryInterval *p;
struct MemoryInterval s[OPEN_MAX];
};
@ -57,6 +58,10 @@ int UntrackMemoryIntervals(void *, size_t) hidden;
#define IsLegalPointer(p) \
(-0x800000000000 <= (intptr_t)(p) && (intptr_t)(p) <= 0x7fffffffffff)
forceinline pureconst bool IsLegalSize(size_t n) {
return n <= 0xffffffffffff;
}
forceinline pureconst bool IsAutoFrame(int x) {
return (kAutomapStart >> 16) <= x &&
x <= ((kAutomapStart + (kAutomapSize - 1)) >> 16);
@ -75,14 +80,26 @@ forceinline pureconst bool IsShadowFrame(int x) {
return 0x7fff <= x && x < 0x10008000;
}
forceinline pureconst bool IsKernelFrame(int x) {
return (int)(GetStaticStackAddr(0) >> 16) <= x &&
x <= (int)((GetStaticStackAddr(0) + (GetStackSize() - FRAMESIZE)) >>
16);
}
forceinline pureconst bool IsStaticStackFrame(int x) {
return (GetStaticStackAddr(0) >> 16) <= x &&
x <= ((GetStaticStackAddr(0) + (GetStackSize() - FRAMESIZE)) >> 16);
return (int)(GetStaticStackAddr(0) >> 16) <= x &&
x <= (int)((GetStaticStackAddr(0) + (GetStackSize() - FRAMESIZE)) >>
16);
}
forceinline pureconst bool IsStackFrame(int x) {
return (int)(GetStackAddr(0) >> 16) <= x &&
x <= (int)((GetStackAddr(0) + (GetStackSize() - FRAMESIZE)) >> 16);
}
forceinline pureconst bool IsSigAltStackFrame(int x) {
return (GetStackAddr(0) >> 16) <= x &&
x <= ((GetStackAddr(0) + (SIGSTKSZ - FRAMESIZE)) >> 16);
return (int)(GetStackAddr(0) >> 16) <= x &&
x <= (int)((GetStackAddr(0) + (SIGSTKSZ - FRAMESIZE)) >> 16);
}
forceinline pureconst bool IsOldStackFrame(int x) {

View file

@ -17,7 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/fmt/itoa.h"
#include "libc/log/libfatal.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/runtime/memtrack.internal.h"
@ -41,20 +41,20 @@ void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) {
for (i = 0; i < mm->i; ++i) {
frames = mm->p[i].y + 1 - mm->p[i].x;
maptally += frames;
__printf("%012x-%012x %s %,*dx%s", ADDR(mm->p[i].x), ADDR(mm->p[i].y + 1),
DescribeMapping(mm->p[i].prot, mm->p[i].flags, mode), w, frames,
DescribeFrame(mm->p[i].x));
kprintf("%012lx-%012lx %s %'*ldx%s", ADDR(mm->p[i].x), ADDR(mm->p[i].y + 1),
DescribeMapping(mm->p[i].prot, mm->p[i].flags, mode), w, frames,
DescribeFrame(mm->p[i].x));
if (i + 1 < _mmi.i) {
frames = mm->p[i + 1].x - mm->p[i].y - 1;
if (frames && IsNoteworthyHole(i, mm)) {
gaptally += frames;
__printf(" w/ %,d frame hole", frames);
kprintf(" w/ %'ld frame hole", frames);
}
}
if (mm->p[i].h != -1) {
__printf(" h=%d", mm->p[i].h);
kprintf(" h=%ld", mm->p[i].h);
}
__printf("\r\n");
kprintf("%n");
}
__printf("# %d frames mapped w/ %,d frames gapped\r\n", maptally, gaptally);
kprintf("# %ld frames mapped w/ %'ld frames gapped%n", maptally, gaptally);
}

View file

@ -97,6 +97,7 @@ int OpenExecutable(void);
void ftrace_install(void);
long GetResourceLimit(int);
long GetMaxFd(void);
char *GetInterpreterExecutableName(char *, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -2,6 +2,7 @@
#define COSMOPOLITAN_LIBC_RUNTIME_STACK_H_
#include "ape/config.h"
#include "libc/dce.h"
#include "libc/nt/version.h"
#include "libc/runtime/runtime.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
@ -27,7 +28,7 @@
/**
* Tunes APE stack virtual address.
*
* This defaults to `0x700000000000 - STACKSIZE`. The value defined by
* This defaults to `0x7e0000000000 - STACKSIZE`. The value defined by
* this macro will be respected, with two exceptions: (1) in MODE=tiny
* the operating system provided stack is used instead and (2) Windows
* Seven doesn't support 64-bit addresses so 0x10000000 - GetStackSize
@ -48,7 +49,7 @@
#define _STACK_EXTRA ""
#endif
#if defined(__GNUC__) && defined(__ELF__)
#if defined(__GNUC__) && defined(__ELF__) && !defined(__STRICT_ANSI__)
COSMOPOLITAN_C_START_
extern char ape_stack_memsz[] __attribute__((__weak__));
@ -64,18 +65,18 @@ extern char ape_stack_memsz[] __attribute__((__weak__));
/**
* Returns preferred bottom address of stack.
*/
#define GetStaticStackAddr(ADDEND) \
({ \
intptr_t vAddr; \
if (!IsWindows() || NtGetVersion() >= kNtVersionWindows10) { \
asm(".weak\tape_stack_vaddr\n\t" \
"movabs\t%1+ape_stack_vaddr,%0" \
: "=r"(vAddr) \
: "i"(ADDEND)); \
} else { \
vAddr = 0x10000000; \
} \
vAddr; \
#define GetStaticStackAddr(ADDEND) \
({ \
intptr_t vAddr; \
if (!IsWindows() || IsAtLeastWindows10()) { \
__asm__(".weak\tape_stack_vaddr\n\t" \
"movabs\t%1+ape_stack_vaddr,%0" \
: "=r"(vAddr) \
: "i"(ADDEND)); \
} else { \
vAddr = 0x10000000; \
} \
vAddr; \
})
COSMOPOLITAN_C_END_

View file

@ -22,9 +22,11 @@
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/enum/filemapflags.h"
@ -66,9 +68,20 @@ struct WinArgs {
char envblock[ARG_MAX];
};
uint32_t __ntconsolemode;
extern int __pid;
extern bool __nomultics;
extern const char kConsoleHandles[2];
static noasan textwindows noinstrument void MakeLongDoubleLongAgain(void) {
static const short kConsoleModes[2] = {
kNtEnableProcessedInput | kNtEnableLineInput | kNtEnableEchoInput |
kNtEnableMouseInput | kNtEnableQuickEditMode | kNtEnableExtendedFlags |
kNtEnableAutoPosition | kNtEnableInsertMode |
kNtEnableVirtualTerminalInput,
kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput |
kNtEnableVirtualTerminalProcessing,
};
forceinline void MakeLongDoubleLongAgain(void) {
/* 8087 FPU Control Word
IM: Invalid Operation
DM: Denormal Operand
@ -90,29 +103,22 @@ static noasan textwindows wontreturn noinstrument void WinMainNew(void) {
int64_t h;
int version;
int i, count;
int64_t inhand;
int64_t hand;
struct WinArgs *wa;
const char16_t *env16;
intptr_t stackaddr, allocaddr;
size_t allocsize, argsize, stacksize;
extern char os asm("__hostos");
os = WINDOWS; /* madness https://news.ycombinator.com/item?id=21019722 */
version = NtGetPeb()->OSMajorVersion;
__oldstack = (intptr_t)__builtin_frame_address(0);
if ((intptr_t)v_ntsubsystem == kNtImageSubsystemWindowsCui && version >= 10) {
SetConsoleCP(kNtCpUtf8);
SetConsoleOutputCP(kNtCpUtf8);
inhand = GetStdHandle(pushpop(kNtStdInputHandle));
SetEnvironmentVariable(u"TERM", u"xterm-truecolor");
GetConsoleMode(inhand, &__ntconsolemode);
SetConsoleMode(inhand, kNtEnableProcessedInput | kNtEnableLineInput |
kNtEnableEchoInput | kNtEnableMouseInput |
kNtEnableQuickEditMode | kNtEnableExtendedFlags |
kNtEnableAutoPosition |
kNtEnableVirtualTerminalInput);
SetConsoleMode(GetStdHandle(pushpop(kNtStdOutputHandle)),
kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput |
kNtEnableVirtualTerminalProcessing);
for (i = 0; i < 2; ++i) {
hand = GetStdHandle(kConsoleHandles[i]);
GetConsoleMode(hand, __ntconsolemode + i);
SetConsoleMode(hand, kConsoleModes[i]);
}
}
_mmi.p = _mmi.s;
_mmi.n = ARRAYLEN(_mmi.s);
@ -186,6 +192,12 @@ noasan textwindows noinstrument int64_t WinMain(int64_t hInstance,
int64_t hPrevInstance,
const char *lpCmdLine,
int nCmdShow) {
extern char os asm("__hostos");
extern uint64_t ts asm("kStartTsc");
os = WINDOWS; /* madness https://news.ycombinator.com/item?id=21019722 */
ts = rdtsc();
__nomultics = true;
__pid = GetCurrentProcessId();
MakeLongDoubleLongAgain();
if (weaken(WinSockInit)) weaken(WinSockInit)();
if (weaken(WinMainForked)) weaken(WinMainForked)();

View file

@ -17,7 +17,9 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/macros.internal.h"
#include "libc/nt/struct/pollfd.h"
#include "libc/nt/winsock.h"
@ -42,6 +44,9 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t ms) {
}
for (;;) {
if (cmpxchg(&__interrupted, true, false)) return eintr();
if (weaken(_check_sigwinch) && weaken(_check_sigwinch)(g_fds.p + 0)) {
return eintr();
}
waitfor = MIN(1000, ms); /* for ctrl+c */
if ((got = WSAPoll(ntfds, nfds, waitfor)) != -1) {
if (!got && (ms -= waitfor) > 0) continue;

View file

@ -1,20 +1,23 @@
#ifndef COSMOPOLITAN_LIBC_STR_UTF16_H_
#define COSMOPOLITAN_LIBC_STR_UTF16_H_
#include "libc/bits/likely.h"
#define UTF16_MASK 0xfc00
#define UTF16_MOAR 0xd800 /* 0xD800..0xDBFF */
#define UTF16_CONT 0xdc00 /* 0xDC00..0xDBFF */
#define UTF16_CONT 0xdc00 /* 0xDC00..0xDFFF */
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define IsUcs2(wc) (((wc)&UTF16_MASK) != UTF16_MOAR)
#define IsUtf16Cont(wc) (((wc)&UTF16_MASK) == UTF16_CONT)
#define MergeUtf16(lo, hi) ((((lo)-0xD800) << 10) + ((hi)-0xDC00) + 0x10000)
#define IsSurrogate(wc) ((0xf800 & (wc)) == 0xd800)
#define IsHighSurrogate(wc) ((UTF16_MASK & (wc)) == UTF16_MOAR)
#define IsLowSurrogate(wc) ((UTF16_MASK & (wc)) == UTF16_CONT)
#define IsUcs2(wc) (((65535 & (wc)) >> 11) != 27)
#define IsUtf16Cont(wc) IsLowSurrogate(wc) /* TODO: DELETE */
#define MergeUtf16(hi, lo) ((((hi)-0xD800) << 10) + ((lo)-0xDC00) + 0x10000)
#define EncodeUtf16(wc) \
(__builtin_expect(((0x0000 <= (wc) && (wc) <= 0xFFFF) || \
(0xE000 <= (wc) && (wc) <= 0xFFFF)), \
1) \
(LIKELY((0x0000 <= (wc) && (wc) <= 0xFFFF) || \
(0xE000 <= (wc) && (wc) <= 0xFFFF)) \
? (wc) \
: 0x10000 <= (wc) && (wc) <= 0x10FFFF \
? (((((wc)-0x10000) >> 10) + 0xD800) | \

View file

@ -1,2 +0,0 @@
.include "o/libc/sysv/macros.internal.inc"
.scall __syscall,0xfff0c6ffffffffff,globl

View file

@ -224,11 +224,11 @@ syscon compat MAP_FILE 0 0 0 0 0 0 # consensus
syscon mmap MAP_SHARED 1 1 1 1 1 1 # forced consensus & faked nt
syscon mmap MAP_PRIVATE 2 2 2 2 2 2 # forced consensus & faked nt
syscon mmap MAP_TYPE 15 15 15 15 15 15 # mask for type of mapping
syscon mmap MAP_FIXED 0x10 0x10 0x10 0x10 0x10 0x10 # unix consensus; openbsd appears to forbid; faked nt
syscon mmap MAP_FIXED 0x0000010 0x0000010 0x0000010 0x0000010 0x0000010 0x0000010 # unix consensus; openbsd appears to forbid; faked nt
syscon mmap MAP_FIXED_NOREPLACE 0x8000000 0x8000000 0x8000000 0x8000000 0x8000000 0x8000000 # handled and defined by cosmo runtime; 0x100000 on linux 4.7+
syscon mmap MAP_ANONYMOUS 0x20 0x1000 0x1000 0x1000 0x1000 0x20 # bsd consensus; faked nt
syscon mmap MAP_GROWSDOWN 0x0100 0 0x0400 0x4000 0x4000 0x100000 # mandatory for OpenBSD stacks; MAP_STACK on Free/OpenBSD; MEM_TOP_DOWN on NT
syscon mmap MAP_CONCEAL 0 0 0x20000 0x8000 0x8000 0 # omit from core dumps; MAP_NOCORE on FreeBSD
syscon mmap MAP_ANONYMOUS 0x20 0x1000 0x0001000 0x1000 0x1000 0x20 # bsd consensus; faked nt
syscon mmap MAP_GROWSDOWN 0x0100 0 0x0000400 0x4000 0x4000 0x100000 # mandatory for OpenBSD stacks; MAP_STACK on Free/OpenBSD; MEM_TOP_DOWN on NT
syscon mmap MAP_CONCEAL 0 0 0x0020000 0x8000 0x8000 0 # omit from core dumps; MAP_NOCORE on FreeBSD
syscon mmap MAP_NORESERVE 0x4000 0x40 0 0 64 0 # Linux calls it "reserve"; NT calls it "commit"? which is default?
syscon mmap MAP_HUGETLB 0x040000 0 0 0 0 0x80000000 # kNtSecLargePages
syscon mmap MAP_HUGE_MASK 63 0 0 0 0 0
@ -237,44 +237,43 @@ syscon mmap MAP_LOCKED 0x2000 0 0 0 0 0
syscon mmap MAP_NONBLOCK 0x10000 0 0 0 0 0
syscon mmap MAP_POPULATE 0x8000 0 0 0 0 0 # can avoid madvise(MADV_WILLNEED) on private file mapping
syscon mmap MAP_CONCEAL 0 0 0 0x8000 0 0 # omit from dumps
syscon compat MAP_STACK 0x0100 0 0x0400 0x4000 0x2000 0x100000 # use MAP_GROWSDOWN
syscon compat MAP_NOCORE 0 0 0x20000 0x8000 0x8000 0 # use MAP_CONCEAL
syscon compat MAP_ANON 0x20 0x1000 0x1000 0x1000 0x1000 0x20 # bsd consensus; faked nt
syscon mmap MAP_STACK 0x0100 0 0x0000400 0x4000 0x2000 0x100000 # use MAP_GROWSDOWN
syscon compat MAP_NOCORE 0 0 0x0020000 0x8000 0x8000 0 # use MAP_CONCEAL
syscon compat MAP_ANON 0x20 0x1000 0x0001000 0x1000 0x1000 0x20 # bsd consensus; faked nt
syscon compat MAP_EXECUTABLE 0x1000 0 0 0 0 0 # ignored
syscon compat MAP_DENYWRITE 0x0800 0 0 0 0 0
syscon compat MAP_32BIT 0x40 0 0x080000 0 0 0 # iffy
# madvise() flags
# beneath the iceberg memory management
#
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon madv MADV_NORMAL 0 0 0 0 0 0x00000080 # consensus & kNtFileAttributeNormal
syscon compat POSIX_FADV_NORMAL 0 0 0 0 0 0x00000080 # consensus & kNtFileAttributeNormal
syscon compat POSIX_MADV_NORMAL 0 0 0 0 0 0x00000080 # consensus & kNtFileAttributeNormal
syscon madv MADV_DONTNEED 4 4 4 4 4 0 # TODO(jart): weird nt decommit thing?
syscon compat POSIX_MADV_DONTNEED 4 4 4 4 4 0 # unix consensus
syscon compat POSIX_FADV_DONTNEED 4 0 4 4 4 0 # unix consensus
syscon madv MADV_DONTNEED 4 4 4 4 4 127 # TODO(jart): weird nt decommit thing?
syscon compat POSIX_MADV_DONTNEED 4 4 4 4 4 127 # unix consensus
syscon compat POSIX_FADV_DONTNEED 4 127 4 4 4 127 # unix consensus
syscon madv MADV_RANDOM 1 1 1 1 1 0x10000000 # unix consensus & kNtFileFlagRandomAccess
syscon compat POSIX_MADV_RANDOM 1 1 1 1 1 0x10000000 # unix consensus & kNtFileFlagRandomAccess
syscon compat POSIX_FADV_RANDOM 1 0 1 1 1 0x10000000 # unix consensus & kNtFileFlagRandomAccess
syscon compat POSIX_FADV_RANDOM 1 127 1 1 1 0x10000000 # unix consensus & kNtFileFlagRandomAccess
syscon madv MADV_SEQUENTIAL 2 2 2 2 2 0x8000000 # unix consensus & kNtFileFlagSequentialScan
syscon compat POSIX_MADV_SEQUENTIAL 2 2 2 2 2 0x8000000 # unix consensus
syscon compat POSIX_FADV_SEQUENTIAL 2 0 2 2 2 0x8000000 # TODO(jart): double check xnu
syscon compat POSIX_FADV_SEQUENTIAL 2 127 2 2 2 0x8000000 # TODO(jart): double check xnu
syscon madv MADV_WILLNEED 3 3 3 3 3 3 # unix consensus (faked on NT)
syscon compat POSIX_MADV_WILLNEED 3 3 3 3 3 3 # unix consensus
syscon compat POSIX_FADV_WILLNEED 3 0 3 3 3 3 # TODO(jart): double check xnu
syscon madv MADV_MERGEABLE 12 0 0 0 0 0 # turns on (private anon range) page scanning and merging service (linux only)
syscon madv MADV_UNMERGEABLE 13 0 0 0 0 0 # turns off mergeable (linux only)
syscon compat POSIX_FADV_WILLNEED 3 127 3 3 3 3 # TODO(jart): double check xnu
syscon madv MADV_MERGEABLE 12 127 127 127 127 127 # turns on (private anon range) page scanning and merging service (linux only)
syscon madv MADV_UNMERGEABLE 13 127 127 127 127 127 # turns off mergeable (linux only)
syscon madv MADV_FREE 8 5 5 6 6 8 # Linux 4.5+ (c. 2016) / NT Faked → VMOfferPriorityNormal (Win8+)
syscon madv MADV_HUGEPAGE 14 0 0 0 0 0 # TODO(jart): why would we need it?
syscon madv MADV_NOHUGEPAGE 15 0 0 0 0 0 # TODO(jart): why would we need it?
syscon madv MADV_DODUMP 17 0 0 0 0 0 # TODO(jart): what is it?
syscon madv MADV_DOFORK 11 0 0 0 0 0 # TODO(jart): what is it?
syscon madv MADV_DONTDUMP 16 0 0 0 0 0 # see MAP_CONCEAL in OpenBSD; TODO(jart): what is it?
syscon madv MADV_DONTFORK 10 0 0 0 0 0 # TODO(jart): what is it?
syscon madv MADV_HWPOISON 100 0 0 0 0 0 # TODO(jart): what is it?
syscon madv MADV_REMOVE 9 0 0 0 0 0 # TODO(jart): what is it?
syscon fadv POSIX_FADV_NOREUSE 5 0 5 0 5 0 # wut
syscon madv MADV_HUGEPAGE 14 127 127 127 127 127 # TODO(jart): why would we need it?
syscon madv MADV_NOHUGEPAGE 15 127 127 127 127 127 # TODO(jart): why would we need it?
syscon madv MADV_DODUMP 17 127 127 127 127 127 # TODO(jart): what is it?
syscon madv MADV_DOFORK 11 127 127 127 127 127 # TODO(jart): what is it?
syscon madv MADV_DONTDUMP 16 127 127 127 127 127 # see MAP_CONCEAL in OpenBSD; TODO(jart): what is it?
syscon madv MADV_DONTFORK 10 127 127 127 127 127 # TODO(jart): what is it?
syscon madv MADV_HWPOISON 100 127 127 127 127 127 # TODO(jart): what is it?
syscon madv MADV_REMOVE 9 127 127 127 127 127 # TODO(jart): what is it?
syscon fadv POSIX_FADV_NOREUSE 5 127 5 127 5 127 # wut
# mmap(), mprotect(), etc.
# digital restrictions management for the people
@ -471,7 +470,7 @@ syscon auxv AT_PHENT 4 0 4 0 4 0
syscon auxv AT_PHNUM 5 0 5 0 5 0
syscon auxv AT_PAGESZ 6 0 6 0 6 0
syscon auxv AT_BASE 7 0 7 0 7 0 # address of program interpreter
syscon auxv AT_FLAGS 8 0 0 0 0 0
syscon auxv AT_FLAGS 8 0 8 0 8 0
syscon auxv AT_ENTRY 9 0 9 0 9 0 # entry address of executable
syscon auxv AT_NOTELF 10 0 10 0 0 0
syscon auxv AT_OSRELDATE 0 0 18 0 0 0
@ -487,10 +486,20 @@ syscon auxv AT_ICACHEBSIZE 20 0 0 0 0 0
syscon auxv AT_UCACHEBSIZE 21 0 0 0 0 0
syscon auxv AT_SECURE 23 0 0 0 0 0
syscon auxv AT_BASE_PLATFORM 24 0 0 0 0 0
syscon auxv AT_RANDOM 25 0 0 0 0 0 # address of sixteen bytes of random data
syscon auxv AT_RANDOM 25 0 16 0 0 0 # address of sixteen bytes of random data; AT_CANARY on FreeBSD whose AT_CANARYLEN should be 64
syscon auxv AT_HWCAP2 26 0 0 0 0 0
syscon auxv AT_EXECFN 31 31 999 999 2014 31 # address of string containing first argument passed to execve() used when running program [faked on non-linux]
syscon auxv AT_EXECFN 31 31 15 999 2014 31 # address of string containing first argument passed to execve() used when running program; AT_EXECPATH on FreeBSD
syscon auxv AT_SYSINFO_EHDR 33 0 0 0 0 0
syscon auxv AT_STACKBASE 0 0 0 0 13 0
syscon auxv AT_EXECPATH 31 31 15 999 2014 31 # FreeBSD name for AT_EXECFN
syscon auxv AT_CANARY 0 0 16 0 0 0
syscon auxv AT_CANARYLEN 0 0 17 0 0 0
syscon auxv AT_NCPUS 0 0 19 0 0 0
syscon auxv AT_PAGESIZES 0 0 20 0 0 0
syscon auxv AT_PAGESIZESLEN 0 0 21 0 0 0
syscon auxv AT_TIMEKEEP 0 0 22 0 0 0
syscon auxv AT_STACKPROT 0 0 23 0 0 0
syscon auxv AT_EHDRFLAGS 0 0 24 0 0 0
syscon auxv AT_NO_AUTOMOUNT 0x0800 0 0 0 0 0
# getrlimit() / setrlimit() resource parameter
@ -1477,13 +1486,13 @@ syscon termios IGNCR 0b0000000010000000 0b0000000010000000 0b000000001000000
syscon termios ICRNL 0b0000000100000000 0b0000000100000000 0b0000000100000000 0b0000000100000000 0b0000000100000000 0b0000000100000000 # termios.c_iflag|=ICRNL maps \r → \n input UNIXCONSENSUS
syscon termios IUCLC 0b0000001000000000 0 0 0b0001000000000000 0 0b0000001000000000 # termios.c_iflag|=IUCLC maps A-Z → a-z input
syscon termios IXON 0b0000010000000000 0b0000001000000000 0b0000001000000000 0b0000001000000000 0b0000001000000000 0b0000010000000000 # termios.c_iflag|=IXON enables flow rida
syscon termios IXANY 0b0000100000000000 0b0000100000000000 0b0000100000000000 0b0000100000000000 0b0000100000000000 0b0000100000000000 # termios.c_iflag|=IXANY tying will un-stuck teletype UNIXCONSENSUS
syscon termios IXANY 0b0000100000000000 0b0000100000000000 0b0000100000000000 0b0000100000000000 0b0000100000000000 0b0000100000000000 # termios.c_iflag|=IXANY typing will un-stuck teletype UNIXCONSENSUS
syscon termios IXOFF 0b0001000000000000 0b0000010000000000 0b0000010000000000 0b0000010000000000 0b0000010000000000 0b0001000000000000 # termios.c_iflag|=IXOFF disables annoying display freeze keys
syscon termios IMAXBEL 0b0010000000000000 0b0010000000000000 0b0010000000000000 0b0010000000000000 0b0010000000000000 0b0010000000000000 # termios.c_iflag|=IMAXBEL rings when queue full UNIXCONSENSUS
syscon termios IUTF8 0b0100000000000000 0b0100000000000000 0 0 0 0b0100000000000000 # termios.c_iflag|=IUTF8 helps w/ rubout on UTF-8 input
syscon termios OPOST 0b0000000000000001 0b000000000000000001 0b000000000000000001 0b0000000000000001 0b0000000000000001 0b0000000000000001 # termios.c_oflag&=~OPOST disables output processing magic
syscon termios OPOST 0b0000000000000001 0b000000000000000001 0b000000000000000001 0b0000000000000001 0b0000000000000001 0b0000000000000001 # termios.c_oflag&=~OPOST disables output processing magic, e.g. MULTICS newlines
syscon termios OLCUC 0b0000000000000010 0 0 0b0000000000100000 0 0b0000000000000010 # termios.c_oflag|=OLCUC maps a-z → A-Z output
syscon termios ONLCR 0b0000000000000100 0b000000000000000010 0b000000000000000010 0b0000000000000010 0b0000000000000010 0b0000000000000100 # termios.c_oflag|=ONLCR maps \n → \r\n output
syscon termios ONLCR 0b0000000000000100 0b000000000000000010 0b000000000000000010 0b0000000000000010 0b0000000000000010 0b0000000000000100 # termios.c_oflag|=ONLCR claims to map \n → \r\n output
syscon termios OCRNL 0b0000000000001000 0b000000000000010000 0b000000000000010000 0b0000000000010000 0b0000000000010000 0b0000000000001000 # termios.c_oflag|=OCRNL maps \r → \n output
syscon termios ONOCR 0b0000000000010000 0b000000000000100000 0b000000000000100000 0b0000000001000000 0b0000000001000000 0b0000000000010000 # termios.c_oflag|=ONOCR maps \r → ∅ output iff column 0
syscon termios ONLRET 0b0000000000100000 0b000000000001000000 0b000000000001000000 0b0000000010000000 0b0000000010000000 0b0000000000100000 # termios.c_oflag|=ONLRET maps \r → ∅ output

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_CANARY,0,0,16,0,0,0

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_CANARYLEN,0,0,17,0,0,0

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_EHDRFLAGS,0,0,24,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_EXECFN,31,31,999,999,2014,31
.syscon auxv,AT_EXECFN,31,31,15,999,2014,31

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_EXECPATH,31,31,15,999,2014,31

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_FLAGS,8,0,0,0,0,0
.syscon auxv,AT_FLAGS,8,0,8,0,8,0

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_NCPUS,0,0,19,0,0,0

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_PAGESIZES,0,0,20,0,0,0

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_PAGESIZESLEN,0,0,21,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_RANDOM,25,0,0,0,0,0
.syscon auxv,AT_RANDOM,25,0,16,0,0,0

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_STACKBASE,0,0,0,0,13,0

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_STACKPROT,0,0,23,0,0,0

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon auxv,AT_TIMEKEEP,0,0,22,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon madv,MADV_DODUMP,17,0,0,0,0,0
.syscon madv,MADV_DODUMP,17,127,127,127,127,127

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon madv,MADV_DOFORK,11,0,0,0,0,0
.syscon madv,MADV_DOFORK,11,127,127,127,127,127

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon madv,MADV_DONTDUMP,16,0,0,0,0,0
.syscon madv,MADV_DONTDUMP,16,127,127,127,127,127

Some files were not shown because too many files have changed in this diff Show more