Make improvements

- Get threads working on NetBSD
- Get threads working on OpenBSD
- Fix Emacs config for Emacs v28
- Improve --strace logging of sigset_t
- Improve --strace logging of struct stat
- Improve memory safety of DescribeThing functions
- Refactor auto stack allocation into LIBC_RUNTIME
- Introduce shell.com example which works on Windows
- Refactor __strace_thing into DescribeThing functions
- Document the CHECK macros and improve them in NDEBUG mode
- Rewrite MAP_STACK so it uses FreeBSD behavior across platforms
- Deprecate and discourage the use of MAP_GROWSDOWN (it's weird)
This commit is contained in:
Justine Tunney 2022-05-12 06:43:59 -07:00
parent dd9ab01d25
commit e7611a8476
101 changed files with 967 additions and 464 deletions

88
examples/check.c Normal file
View file

@ -0,0 +1,88 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/log/check.h"
/**
* @fileoverview Check Macros
*
* The simplest assertion is:
*
* assert(123 == x);
*
* This has some downsides:
*
* 1. It's nice to know what `x` is when it crashes
* 2. It's sometimes nice to have the check always take effect.
* 3. It's problematic that assert() can't do __builtin_assume()
*
* Cosmopolitan provides alternative macros like:
*
* - `CHECK(EXPR, ...)`
* - `CHECK_EQ(WANT, GOT, ...)`
* - `CHECK_NE(WANT, GOT, ...)`
* - `CHECK_GT(WANT, GOT, ...)`
* - `CHECK_LT(WANT, GOT, ...)`
* - `CHECK_NOTNULL(EXPR, ...)`
*
* The CHECK macros always happen. They always kill the process when
* they fail. Printf formatting information may be provided as extra
* arguments. On the other hand, there exists:
*
* - `DCHECK(EXPR, ...)`
* - `DCHECK_EQ(WANT, GOT, ...)`
* - `DCHECK_NE(WANT, GOT, ...)`
* - `DCHECK_GT(WANT, GOT, ...)`
* - `DCHECK_LT(WANT, GOT, ...)`
* - `DCHECK_NOTNULL(EXPR, ...)`
*
* The DCHECK macros always happen when NDEBUG isn't defined. When
* NDEBUG is defined, they still happen, but in a special way that
* causes the compiler to recognize their failure as undefined behavior.
* What this means is that, if the provided expressions are pure without
* side-effects, then the code compiles down to nothing and the compiler
* may be able to use the knowledge of something being the case in order
* to optimize other code adjacent to your DCHECK.
*
* In the default build modes, this prints lots of information:
*
* error:examples/check.c:23:check.com: check failed on nightmare pid 15412
* CHECK_EQ(123, some_source_code);
* 0x7b (123)
* == 0x64 (some_source_code)
* extra info: hello
* EUNKNOWN/0/No error information
* ./o//examples/check.com
* 0x0000000000407404: __die at libc/log/die.c:42
* 0x0000000000407340: __check_fail at libc/log/checkfail.c:73
* 0x00000000004071d0: main at examples/check.c:23
* 0x000000000040256e: cosmo at libc/runtime/cosmo.S:69
* 0x000000000040217d: _start at libc/crt/crt.S:85
*
* In NDEBUG mode (e.g. MODE=rel, MODE=tiny, etc.) this prints a much
* simpler message that, most importantly, doesn't include any source
* code, although it still includes the file name for reference.
*
* error:examples/check.c:14: check failed: 123 == 100: extra info: hello
*
* That way your release binaries won't leak CI. You may optionally link
* the following functions to further expand the information shown by
* the NDEBUG check failure:
*
* STATIC_YOINK("__die");
* STATIC_YOINK("strerror");
*
* Please note that backtraces aren't ever available in MODE=tiny.
*/
int main(int argc, char *argv[]) {
int some_source_code = 100;
CHECK_EQ(123, some_source_code, "extra info: %s", "hello");
return 0;
}

View file

@ -22,7 +22,7 @@
* o//examples/crashreport.com
*/
int main(int argc, char *argv[]) {
noubsan int main(int argc, char *argv[]) {
volatile int64_t x;
ShowCrashReports();
return 1 / (x = 0);

14
examples/exit.c Normal file
View file

@ -0,0 +1,14 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/fmt/conv.h"
int main(int argc, char *argv[]) {
return atoi(argc > 1 ? argv[1] : "0");
}

View file

@ -11,6 +11,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/rlimit.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/color.internal.h"
#include "libc/macros.internal.h"
@ -37,12 +38,12 @@ static void SetLimit(int resource, uint64_t soft, uint64_t hard) {
lim.rlim_cur = MIN(soft, lim.rlim_max);
if (!setrlimit(resource, &lim)) {
fprintf(stderr, "%sNOTE: SETRLIMIT(%s) DOWNGRADED TO {%,ld, %,ld}\n",
__strace_rlimit_name(resource), lim.rlim_cur, lim.rlim_max);
DescribeRlimitName(resource), lim.rlim_cur, lim.rlim_max);
return;
}
}
fprintf(stderr, "ERROR: SETRLIMIT(%s, %,ld, %,ld) FAILED %m%n",
__strace_rlimit_name(resource), soft, hard);
DescribeRlimitName(resource), soft, hard);
exit(1);
}
}
@ -63,9 +64,8 @@ int main(int argc, char *argv[]) {
for (i = 0; i < RLIM_NLIMITS; ++i) {
rc = getrlimit(i, &rlim);
printf("SETRLIMIT(%-20s, %,16ld, %,16ld) → %d %s\n",
__strace_rlimit_name(i), rlim.rlim_cur, rlim.rlim_max, rc,
!rc ? "" : strerror(errno));
printf("SETRLIMIT(%-20s, %,16ld, %,16ld) → %d %s\n", DescribeRlimitName(i),
rlim.rlim_cur, rlim.rlim_max, rc, !rc ? "" : strerror(errno));
}
return 0;

172
examples/shell.c Normal file
View file

@ -0,0 +1,172 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/calls/calls.h"
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigset.h"
#include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h"
#include "libc/log/internal.h"
#include "libc/macros.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/dt.h"
#include "libc/sysv/consts/sig.h"
#include "libc/x/x.h"
#include "third_party/linenoise/linenoise.h"
/**
* @fileoverview Shell that works on Windows.
*
* This doesn't have script language features like UNBOURNE.COM but it
* works on Windows and, unlike CMD.EXE, actually has CTRL-P and CTRL-R
* which alone make it so much better.
*
* One day we'll have UNBOURNE.COM working on Windows but the code isn't
* very maintainable sadly.
*/
static void AddUniqueCompletion(linenoiseCompletions *c, char *s) {
size_t i;
if (!s) return;
for (i = 0; i < c->len; ++i) {
if (!strcmp(s, c->cvec[i])) {
return;
}
}
c->cvec = realloc(c->cvec, ++c->len * sizeof(*c->cvec));
c->cvec[c->len - 1] = s;
}
static void CompleteFilename(const char *p, const char *q, const char *b,
linenoiseCompletions *c) {
DIR *d;
char *buf;
const char *g;
struct dirent *e;
if ((buf = malloc(512))) {
if ((g = memrchr(p, '/', q - p))) {
*(char *)mempcpy(buf, p, MIN(g - p, 511)) = 0;
p = ++g;
} else {
strcpy(buf, ".");
}
if ((d = opendir(buf))) {
while ((e = readdir(d))) {
if (!strcmp(e->d_name, ".")) continue;
if (!strcmp(e->d_name, "..")) continue;
if (!strncmp(e->d_name, p, q - p)) {
snprintf(buf, 512, "%.*s%s%s", p - b, b, e->d_name,
e->d_type == DT_DIR ? "/" : "");
AddUniqueCompletion(c, strdup(buf));
}
}
closedir(d);
}
free(buf);
}
}
static void ShellCompletion(const char *p, linenoiseCompletions *c) {
bool slashed;
const char *q, *b;
for (slashed = false, b = p, q = (p += strlen(p)); p > b; --p) {
if (p[-1] == '/' && p[-1] == '\\') slashed = true;
if (!isalnum(p[-1]) &&
(p[-1] != '.' && p[-1] != '_' && p[-1] != '-' && p[-1] != '+' &&
p[-1] != '[' && p[-1] != '/' && p[-1] != '\\')) {
break;
}
}
CompleteFilename(p, q, b, c);
}
static char *ShellHint(const char *p, const char **ansi1, const char **ansi2) {
char *h = 0;
linenoiseCompletions c = {0};
ShellCompletion(p, &c);
if (c.len == 1) {
h = strdup(c.cvec[0] + strlen(p));
}
linenoiseFreeCompletions(&c);
return h;
}
int main(int argc, char *argv[]) {
int n, ws, pid;
char *prog, path[PATH_MAX];
sigset_t chldmask, savemask;
struct sigaction ignore, saveint, savequit;
char *p, *line, **args, *arg, *start, *state, prompt[64];
linenoiseSetFreeHintsCallback(free);
linenoiseSetHintsCallback(ShellHint);
linenoiseSetCompletionCallback(ShellCompletion);
stpcpy(prompt, "$ ");
while ((line = linenoiseWithHistory(prompt, "cmd"))) {
n = 0;
start = line;
args = xcalloc(1, sizeof(*args));
while ((arg = strtok_r(start, " \t\r\n", &state))) {
args = xrealloc(args, (++n + 1) * sizeof(*args));
args[n - 1] = arg;
args[n - 0] = 0;
start = 0;
}
if (n > 0) {
if ((prog = commandv(args[0], path, sizeof(path)))) {
ignore.sa_flags = 0;
ignore.sa_handler = SIG_IGN;
sigemptyset(&ignore.sa_mask);
sigaction(SIGINT, &ignore, &saveint);
sigaction(SIGQUIT, &ignore, &savequit);
sigemptyset(&chldmask);
sigaddset(&chldmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &chldmask, &savemask);
if (!fork()) {
sigaction(SIGINT, &saveint, 0);
sigaction(SIGQUIT, &savequit, 0);
sigprocmask(SIG_SETMASK, &savemask, 0);
execv(prog, args);
_Exit(127);
}
wait(&ws);
p = prompt;
if (WIFEXITED(ws)) {
if (WEXITSTATUS(ws)) {
if (!__nocolor) p = stpcpy(p, "\e[1;31m");
p = stpcpy(p, "rc=");
p = FormatInt32(p, WEXITSTATUS(ws));
if (!__nocolor) p = stpcpy(p, "\e[0m");
*p++ = ' ';
}
} else {
if (!__nocolor) p = stpcpy(p, "\e[1;31m");
p = stpcpy(p, "rc=");
p = stpcpy(p, strsignal(WTERMSIG(ws)));
if (!__nocolor) p = stpcpy(p, "\e[0m");
*p++ = ' ';
}
p = stpcpy(p, "$ ");
sigaction(SIGINT, &saveint, 0);
sigaction(SIGQUIT, &savequit, 0);
sigprocmask(SIG_SETMASK, &savemask, 0);
} else {
fprintf(stderr, "%s: %s: command not found\n", argv[0], args[0]);
}
}
free(line);
free(args);
}
}

View file

@ -68,6 +68,10 @@ $(LIBC_CALLS_A).pkg: \
o/$(MODE)/libc/calls/vdsofunc.greg.o \
o/$(MODE)/libc/calls/directmap.o \
o/$(MODE)/libc/calls/directmap-nt.o \
o/$(MODE)/libc/calls/mapstack.greg.o \
o/$(MODE)/libc/calls/getcwd.greg.o \
o/$(MODE)/libc/calls/getcwd-xnu.greg.o \
o/$(MODE)/libc/calls/getprogramexecutablename.greg.o \
o/$(MODE)/libc/calls/raise.o: \
OVERRIDE_COPTS += \
-ffreestanding \
@ -116,7 +120,6 @@ o/$(MODE)/libc/calls/renameat-nt.o \
o/$(MODE)/libc/calls/execve-sysv.o \
o/$(MODE)/libc/calls/symlinkat-nt.o \
o/$(MODE)/libc/calls/readlinkat-nt.o \
o/$(MODE)/libc/calls/describeopenflags.greg.o \
o/$(MODE)/libc/calls/mkntenvblock.o: \
OVERRIDE_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED

View file

@ -23,6 +23,7 @@
#include "libc/dce.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/errfuns.h"
@ -70,7 +71,7 @@ noinstrument int clock_gettime(int clockid, struct timespec *ts) {
}
if (!__time_critical) {
STRACE("clock_gettime(%d, [%s]) → %d% m", clockid,
__strace_timespec(buf, sizeof(buf), rc, ts), rc);
DescribeTimespec(buf, sizeof(buf), rc, ts), rc);
}
return rc;
}

View file

@ -16,16 +16,23 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
privileged const char *__strace_sigaction(char *buf, size_t bufsize, int rc,
const struct sigaction *sa) {
char maskbuf[41];
const char *DescribeSigaction(char *buf, size_t bufsize, int rc,
const struct sigaction *sa) {
char maskbuf[64];
if (rc == -1) return "n/a";
if (!sa) return "NULL";
ksnprintf(buf, bufsize, "{.sa_handler=%p, .sa_flags=%#lx, .sa_mask=%s}",
sa->sa_handler, sa->sa_flags,
__strace_sigset(maskbuf, sizeof(maskbuf), rc, &sa->sa_mask));
if ((!IsAsan() && kisdangerous(sa)) ||
(IsAsan() && !__asan_is_valid(sa, sizeof(*sa)))) {
ksnprintf(buf, sizeof(buf), "%p", sa);
} else {
ksnprintf(buf, bufsize, "{.sa_handler=%p, .sa_flags=%#lx, .sa_mask=%s}",
sa->sa_handler, sa->sa_flags,
DescribeSigset(maskbuf, sizeof(maskbuf), rc, &sa->sa_mask));
}
return buf;
}

View file

@ -16,14 +16,49 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/strace.internal.h"
#include "libc/bits/popcnt.h"
#include "libc/calls/sigbits.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/str/str.h"
const char *DescribeSigset(char *buf, size_t bufsize, int rc,
const sigset_t *ss) {
bool gotsome;
int i, n, sig;
sigset_t sigset;
privileged const char *__strace_stat(int rc, const struct stat *st) {
static char buf[256];
if (rc == -1) return "n/a";
if (!st) return "NULL";
ksnprintf(buf, sizeof(buf), "{.st_size=%'ld, .st_mode=%#o, .st_ino=%'lu}",
st->st_size, st->st_mode, st->st_ino);
if (!ss) return "NULL";
if ((!IsAsan() && kisdangerous(ss)) ||
(IsAsan() && !__asan_is_valid(ss, sizeof(*ss)))) {
ksnprintf(buf, sizeof(buf), "%p", ss);
return buf;
}
i = 0;
n = bufsize;
sigset = *ss;
gotsome = false;
if (popcnt(sigset.__bits[0]) + popcnt(sigset.__bits[1]) > 64) {
i += ksnprintf(buf + i, n - i, "~");
sigset.__bits[0] = ~sigset.__bits[0];
sigset.__bits[1] = ~sigset.__bits[1];
}
i += ksnprintf(buf + i, n - i, "{");
for (sig = 1; sig < 128; ++sig) {
if (sigismember(&sigset, sig)) {
if (gotsome) {
sig += ksnprintf(buf + sig, n - sig, ", ");
} else {
gotsome = true;
}
sig += ksnprintf(buf + sig, n - sig, "%s", strsignal(sig));
}
}
i += ksnprintf(buf + i, n - i, "}");
return buf;
}

View file

@ -48,7 +48,7 @@ textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
handle = kNtInvalidHandleValue;
}
if (flags & MAP_PRIVATE) {
if ((flags & MAP_TYPE) != MAP_SHARED) {
sec = 0; // MAP_PRIVATE isn't inherited across fork()
} else {
sec = &kNtIsInheritable; // MAP_SHARED gives us zero-copy fork()
@ -60,14 +60,13 @@ textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
// note that open-nt.c always requests an kNtGenericExecute accessmask
iscow = false;
if (handle != -1) {
if (flags & MAP_PRIVATE) {
if ((flags & MAP_TYPE) != MAP_SHARED) {
// windows has cow pages but they can't propagate across fork()
// that means we only get copy-on-write for the root process :(
fl = (struct ProtectNt){kNtPageExecuteWritecopy,
kNtFileMapCopy | kNtFileMapExecute};
iscow = true;
} else {
assert(flags & MAP_SHARED);
if ((g_fds.p[fd].flags & O_ACCMODE) == O_RDONLY) {
fl = (struct ProtectNt){kNtPageExecuteRead,
kNtFileMapRead | kNtFileMapExecute};

View file

@ -22,6 +22,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -50,7 +51,7 @@ int faccessat(int dirfd, const char *path, int mode, uint32_t flags) {
} else {
rc = sys_faccessat_nt(dirfd, path, mode, flags);
}
STRACE("faccessat(%s, %#s, %#o, %#x) → %d% m", __strace_dirfd(buf, dirfd),
STRACE("faccessat(%s, %#s, %#o, %#x) → %d% m", DescribeDirfd(buf, dirfd),
path, mode, flags, rc);
return rc;
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -51,7 +52,7 @@ int fchmodat(int dirfd, const char *path, uint32_t mode, int flags) {
} else {
rc = sys_fchmodat_nt(dirfd, path, mode, flags);
}
STRACE("fchmodat(%s, %#s, %#o, %d) → %d% m", __strace_dirfd(buf, dirfd), path,
STRACE("fchmodat(%s, %#s, %#o, %d) → %d% m", DescribeDirfd(buf, dirfd), path,
mode, flags, rc);
return rc;
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -49,7 +50,7 @@ int fchownat(int dirfd, const char *path, uint32_t uid, uint32_t gid,
} else {
rc = sys_fchownat(dirfd, path, uid, gid, flags);
}
STRACE("fchownat(%s, %#s, %d, %d, %#b) → %d% m", __strace_dirfd(sb, dirfd),
STRACE("fchownat(%s, %#s, %d, %d, %#b) → %d% m", DescribeDirfd(sb, dirfd),
path, uid, gid, flags, rc);
return rc;
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -45,6 +46,6 @@ int fstat(int fd, struct stat *st) {
} else {
rc = sys_fstat_nt(__getfdhandleactual(fd), st);
}
STRACE("fstat(%d, [%s]) → %d% m", fd, __strace_stat(rc, st), rc);
STRACE("fstat(%d, [%s]) → %d% m", fd, DescribeStat(rc, st), rc);
return rc;
}

View file

@ -24,6 +24,7 @@
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
#include "libc/str/str.h"
@ -70,7 +71,7 @@ int fstatat(int dirfd, const char *path, struct stat *st, int flags) {
} else {
rc = sys_fstatat_nt(dirfd, path, st, flags);
}
STRACE("fstatat(%s, %#s, [%s], %s) → %d% m", __strace_dirfd(buf, dirfd), path,
__strace_stat(rc, st), __strace_fstatat_flags(flags), rc);
STRACE("fstatat(%s, %#s, [%s], %s) → %d% m", DescribeDirfd(buf, dirfd), path,
DescribeStat(rc, st), __strace_fstatat_flags(flags), rc);
return rc;
}

View file

@ -21,6 +21,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/rlimit.h"
#include "libc/sysv/errfuns.h"
@ -48,7 +49,7 @@ int getrlimit(int resource, struct rlimit *rlim) {
} else {
rc = einval();
}
STRACE("getrlimit(%s, [%s]) → %d% m", __strace_rlimit_name(resource),
__strace_rlimit(buf, sizeof(buf), rc, rlim), rc);
STRACE("getrlimit(%s, [%s]) → %d% m", DescribeRlimitName(resource),
DescribeRlimit(buf, sizeof(buf), rc, rlim), rc);
return rc;
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -52,7 +53,7 @@ int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath,
rc = sys_linkat_nt(olddirfd, oldpath, newdirfd, newpath);
}
STRACE("linkat(%s, %#s, %s, %#s, %#b) → %d% m",
__strace_dirfd(buf[0], olddirfd), oldpath,
__strace_dirfd(buf[1], newdirfd), newpath, flags, rc);
DescribeDirfd(buf[0], olddirfd), oldpath,
DescribeDirfd(buf[1], newdirfd), newpath, flags, rc);
return rc;
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -50,7 +51,7 @@ int mkdirat(int dirfd, const char *path, unsigned mode) {
} else {
rc = sys_mkdirat_nt(dirfd, path, mode);
}
STRACE("mkdirat(%s, %#s, %#o) → %d% m", __strace_dirfd(buf, dirfd), path,
mode, rc);
STRACE("mkdirat(%s, %#s, %#o) → %d% m", DescribeDirfd(buf, dirfd), path, mode,
rc);
return rc;
}

View file

@ -20,6 +20,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/errfuns.h"
/**
@ -45,8 +46,8 @@ noinstrument int nanosleep(const struct timespec *req, struct timespec *rem) {
}
if (!__time_critical) {
STRACE("nanosleep(%s, [%s]) → %d% m",
__strace_timespec(buf[0], sizeof(buf[0]), rc, req),
__strace_timespec(buf[1], sizeof(buf[1]), rc, rem), rc);
DescribeTimespec(buf[0], sizeof(buf[0]), rc, req),
DescribeTimespec(buf[1], sizeof(buf[1]), rc, rem), rc);
}
return rc;
}

View file

@ -23,6 +23,7 @@
#include "libc/dce.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/log/log.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
@ -75,7 +76,7 @@ int openat(int dirfd, const char *file, int flags, ...) {
} else {
rc = efault();
}
STRACE("openat(%s, %#s, %s, %#o) → %d% m", __strace_dirfd(buf, dirfd), file,
STRACE("openat(%s, %#s, %s, %#o) → %d% m", DescribeDirfd(buf, dirfd), file,
DescribeOpenFlags(flags), (flags & (O_CREAT | O_TMPFILE)) ? mode : 0,
rc);
return rc;

View file

@ -84,20 +84,22 @@ int poll(struct pollfd *fds, size_t nfds, int timeout_ms) {
#if defined(SYSDEBUG) && _POLLTRACE
if (__strace > 0) {
if (rc == -1 && errno == EFAULT) {
STRACE("poll(%p, %'lu, %'d) → %d% lm", fds, nfds, timeout_ms, rc);
kprintf(STRACE_PROLOGUE "poll(");
if ((!IsAsan() && kisdangerous(fds)) ||
(IsAsan() && !__asan_is_valid(fds, nfds * sizeof(struct pollfd)))) {
kprintf("%p", fds);
} else {
char flagbuf[2][64];
kprintf(STRACE_PROLOGUE "poll({");
kprintf("[{");
for (i = 0; i < MIN(5, nfds); ++i) {
kprintf(
"%s{%d, %s, %s}", i ? ", " : "", fds[i].fd,
DescribePollFlags(flagbuf[0], sizeof(flagbuf[0]), fds[i].events),
DescribePollFlags(flagbuf[1], sizeof(flagbuf[1]), fds[i].revents));
}
kprintf("%s}, %'zu, %'d) → %d% lm\n", i == 5 ? "..." : "", nfds,
timeout_ms, rc);
kprintf("%s}]", i == 5 ? "..." : "");
}
kprintf(", %'zu, %'d) → %d% lm\n", nfds, timeout_ms, rc);
}
#endif

View file

@ -25,6 +25,7 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/sysv/consts/iov.h"
@ -113,13 +114,9 @@ ssize_t preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
rc = Preadv(fd, iov, iovlen, off);
#if defined(SYSDEBUG) && _DATATRACE
if (__strace > 0) {
if (rc == -1 && errno == EFAULT) {
STRACE("preadv(%d, %p, %d, %'ld) → %'zd% m", fd, iov, iovlen, off, rc);
} else {
kprintf(STRACE_PROLOGUE "preadv(%d, [", fd);
__strace_iov(iov, iovlen, rc != -1 ? rc : 0);
kprintf("], %d, %'ld) → %'ld% m\n", iovlen, off, rc);
}
kprintf(STRACE_PROLOGUE "preadv(%d, [", fd);
DescribeIov(iov, iovlen, rc != -1 ? rc : 0);
kprintf("], %d, %'ld) → %'ld% m\n", iovlen, off, rc);
}
#endif
return rc;

View file

@ -24,6 +24,7 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/sysv/consts/iov.h"
@ -118,13 +119,9 @@ ssize_t pwritev(int fd, const struct iovec *iov, int iovlen, int64_t off) {
rc = Pwritev(fd, iov, iovlen, off);
#if defined(SYSDEBUG) && _DATATRACE
if (__strace > 0) {
if (rc == -1 && errno == EFAULT) {
STRACE("pwritev(%d, %p, %d, %'ld) → %'zd% m", fd, iov, iovlen, off, rc);
} else {
kprintf(STRACE_PROLOGUE "pwritev(%d, ", fd);
__strace_iov(iov, iovlen, rc != -1 ? rc : 0);
kprintf(", %d, %'ld) → %'ld% m\n", iovlen, off, rc);
}
kprintf(STRACE_PROLOGUE "pwritev(%d, ", fd);
DescribeIov(iov, iovlen, rc != -1 ? rc : 0);
kprintf(", %d, %'ld) → %'ld% m\n", iovlen, off, rc);
}
#endif
return rc;

View file

@ -21,6 +21,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -53,7 +54,7 @@ ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) {
} else {
bytes = sys_readlinkat_nt(dirfd, path, buf, bufsiz);
}
STRACE("readlinkat(%s, %#s, [%#.*s]) → %d% m", __strace_dirfd(sb, dirfd),
path, MAX(0, bytes), buf, bytes);
STRACE("readlinkat(%s, %#s, [%#.*s]) → %d% m", DescribeDirfd(sb, dirfd), path,
MAX(0, bytes), buf, bytes);
return bytes;
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/sock/internal.h"
#include "libc/sysv/errfuns.h"
@ -71,7 +72,7 @@ ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
STRACE("readv(%d, %p, %d) → %'zd% m", fd, iov, iovlen, rc);
} else {
kprintf(STRACE_PROLOGUE "readv(%d, [", fd);
__strace_iov(iov, iovlen, rc != -1 ? rc : 0);
DescribeIov(iov, iovlen, rc != -1 ? rc : 0);
kprintf("], %d) → %'ld% m\n", iovlen, rc);
}
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -57,7 +58,7 @@ int renameat(int olddirfd, const char *oldpath, int newdirfd,
} else {
rc = sys_renameat_nt(olddirfd, oldpath, newdirfd, newpath);
}
STRACE("renameat(%s, %#s, %s, %#s) → %d% m", __strace_dirfd(buf[0], olddirfd),
oldpath, __strace_dirfd(buf[1], newdirfd), newpath, rc);
STRACE("renameat(%s, %#s, %s, %#s) → %d% m", DescribeDirfd(buf[0], olddirfd),
oldpath, DescribeDirfd(buf[1], newdirfd), newpath, rc);
return rc;
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/rlimit.h"
#include "libc/sysv/errfuns.h"
@ -82,7 +83,7 @@ int setrlimit(int resource, const struct rlimit *rlim) {
} else {
rc = einval();
}
STRACE("setrlimit(%s, %s) → %d% m", __strace_rlimit_name(resource),
__strace_rlimit(buf, sizeof(buf), 0, rlim), rc);
STRACE("setrlimit(%s, %s) → %d% m", DescribeRlimitName(resource),
DescribeRlimit(buf, sizeof(buf), 0, rlim), rc);
return rc;
}

View file

@ -33,6 +33,7 @@
#include "libc/calls/ucontext.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/spinlock.h"
#include "libc/limits.h"
#include "libc/log/backtrace.internal.h"
@ -449,7 +450,7 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact) {
rc = __sigaction(sig, act, oldact);
}
STRACE("sigaction(%G, %s, [%s]) → %d% m", sig,
__strace_sigaction(buf[0], sizeof(buf[0]), 0, act),
__strace_sigaction(buf[1], sizeof(buf[1]), rc, oldact), rc);
DescribeSigaction(buf[0], sizeof(buf[0]), 0, act),
DescribeSigaction(buf[1], sizeof(buf[1]), rc, oldact), rc);
return rc;
}

View file

@ -26,6 +26,7 @@
#include "libc/dce.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
#include "libc/str/str.h"
@ -78,7 +79,7 @@ int sigprocmask(int how, const sigset_t *opt_set, sigset_t *opt_out_oldset) {
*opt_out_oldset = old;
}
STRACE("sigprocmask(%s, %s, [%s]) → %d% m", DescribeHow(howbuf, how),
__strace_sigset(buf[0], sizeof(buf[0]), 0, opt_set),
__strace_sigset(buf[1], sizeof(buf[1]), rc, opt_out_oldset), rc);
DescribeSigset(buf[0], sizeof(buf[0]), 0, opt_set),
DescribeSigset(buf[1], sizeof(buf[1]), rc, opt_out_oldset), rc);
return rc;
}

View file

@ -25,6 +25,7 @@
#include "libc/calls/struct/sigset.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/log/backtrace.internal.h"
#include "libc/nt/errors.h"
#include "libc/nt/synchronization.h"
@ -47,7 +48,7 @@ int sigsuspend(const sigset_t *ignore) {
char buf[41];
long ms, totoms;
sigset_t save, mask, *arg;
STRACE("sigsuspend(%s) → ...", __strace_sigset(buf, sizeof(buf), 0, ignore));
STRACE("sigsuspend(%s) → ...", DescribeSigset(buf, sizeof(buf), 0, ignore));
if (IsAsan() && ignore && !__asan_is_valid(ignore, sizeof(*ignore))) {
rc = efault();
} else if (IsXnu() || IsOpenbsd()) {

View file

@ -5,10 +5,10 @@
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/stat.h"
#define _KERNTRACE 0 /* not configurable w/ flag yet */
#define _POLLTRACE 0 /* not configurable w/ flag yet */
#define _KERNTRACE 1 /* not configurable w/ flag yet */
#define _POLLTRACE 1 /* not configurable w/ flag yet */
#define _DATATRACE 1 /* not configurable w/ flag yet */
#define _NTTRACE 0 /* not configurable w/ flag yet */
#define _NTTRACE 1 /* not configurable w/ flag yet */
#define STRACE_PROLOGUE "%rSYS %5P %'18T "
@ -53,14 +53,6 @@ COSMOPOLITAN_C_START_
extern int __strace;
void __stracef(const char *, ...);
void __strace_iov(const struct iovec *, int, ssize_t);
const char *__strace_stat(int, const struct stat *);
const char *__strace_sigaction(char *, size_t, int, const struct sigaction *);
const char *__strace_sigset(char[41], size_t, int, const sigset_t *);
const char *__strace_rlimit_name(int);
const char *__strace_rlimit(char[41], size_t, int, const struct rlimit *);
const char *__strace_timespec(char[45], size_t, int, const struct timespec *);
const char *__strace_dirfd(char[12], int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -1,58 +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/calls/strace.internal.h"
#include "libc/calls/struct/rlimit.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/sysv/consts/rlimit.h"
const char *__strace_rlimit_name(int resource) {
static char buf[12];
if (resource != 127) {
if (resource == RLIMIT_AS) return "RLIMIT_AS";
if (resource == RLIMIT_CPU) return "RLIMIT_CPU";
if (resource == RLIMIT_FSIZE) return "RLIMIT_FSIZE";
if (resource == RLIMIT_NPROC) return "RLIMIT_NPROC";
if (resource == RLIMIT_NOFILE) return "RLIMIT_NOFILE";
if (resource == RLIMIT_RSS) return "RLIMIT_RSS";
if (resource == RLIMIT_DATA) return "RLIMIT_DATA";
if (resource == RLIMIT_CORE) return "RLIMIT_CORE";
if (resource == RLIMIT_STACK) return "RLIMIT_STACK";
if (resource == RLIMIT_SIGPENDING) return "RLIMIT_SIGPENDING";
if (resource == RLIMIT_MEMLOCK) return "RLIMIT_MEMLOCK";
if (resource == RLIMIT_LOCKS) return "RLIMIT_LOCKS";
if (resource == RLIMIT_MSGQUEUE) return "RLIMIT_MSGQUEUE";
if (resource == RLIMIT_NICE) return "RLIMIT_NICE";
if (resource == RLIMIT_RTPRIO) return "RLIMIT_RTPRIO";
if (resource == RLIMIT_RTTIME) return "RLIMIT_RTTIME";
if (resource == RLIMIT_SWAP) return "RLIMIT_SWAP";
if (resource == RLIMIT_SBSIZE) return "RLIMIT_SBSIZE";
if (resource == RLIMIT_NPTS) return "RLIMIT_NPTS";
}
FormatInt32(buf, resource);
return buf;
}
privileged const char *__strace_rlimit(char buf[64], size_t bufsize, int rc,
const struct rlimit *rlim) {
if (rc == -1) return "n/a";
if (!rlim) return "NULL";
ksnprintf(buf, bufsize, "{%'ld, %'ld}", rlim->rlim_cur, rlim->rlim_max);
return buf;
}

View file

@ -21,6 +21,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
@ -50,6 +51,6 @@ int symlinkat(const char *target, int newdirfd, const char *linkpath) {
rc = sys_symlinkat_nt(target, newdirfd, linkpath);
}
STRACE("symlinkat(%#s, %s, %#s) → %d% m", target,
__strace_dirfd(buf, newdirfd), linkpath);
DescribeDirfd(buf, newdirfd), linkpath);
return rc;
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -49,7 +50,7 @@ int unlinkat(int dirfd, const char *path, int flags) {
} else {
rc = sys_unlinkat_nt(dirfd, path, flags);
}
STRACE("unlinkat(%s, %#s, %#b) → %d% m", __strace_dirfd(buf, dirfd), path,
STRACE("unlinkat(%s, %#s, %#b) → %d% m", DescribeDirfd(buf, dirfd), path,
flags, rc);
return rc;
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/errfuns.h"
#include "libc/zipos/zipos.internal.h"
@ -49,10 +50,10 @@ int utimensat(int dirfd, const char *path, const struct timespec ts[2],
}
if (ts) {
STRACE("utimensat(%s, %#s, {{%,ld, %,ld}, {%,ld, %,ld}}, %#b) → %d% m",
__strace_dirfd(buf, dirfd), path, ts[0].tv_sec, ts[0].tv_nsec,
DescribeDirfd(buf, dirfd), path, ts[0].tv_sec, ts[0].tv_nsec,
ts[1].tv_sec, ts[1].tv_nsec, flags, rc);
} else {
STRACE("utimensat(%s, %#s, 0, %#b) → %d% m", __strace_dirfd(buf, dirfd),
STRACE("utimensat(%s, %#s, 0, %#b) → %d% m", DescribeDirfd(buf, dirfd),
path, flags, rc);
}
return rc;

View file

@ -22,6 +22,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/errno.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/sock/internal.h"
#include "libc/sysv/errfuns.h"
@ -74,13 +75,9 @@ ssize_t writev(int fd, const struct iovec *iov, int iovlen) {
#if defined(SYSDEBUG) && _DATATRACE
if (__strace > 0) {
if (rc == -1 && errno == EFAULT) {
STRACE("writev(%d, %p, %d) → %'zd% m", fd, iov, iovlen, rc);
} else {
kprintf(STRACE_PROLOGUE "writev(%d, ", fd);
__strace_iov(iov, iovlen, rc != -1 ? rc : 0);
kprintf(", %d) → %'ld% m\n", iovlen, rc);
}
kprintf(STRACE_PROLOGUE "writev(%d, ", fd);
DescribeIov(iov, iovlen, rc != -1 ? rc : 0);
kprintf(", %d) → %'ld% m\n", iovlen, rc);
}
#endif

View file

@ -1282,7 +1282,10 @@ void __asan_map_shadow(uintptr_t p, size_t n) {
int prot, flag;
struct DirectMap sm;
struct MemoryIntervals *m;
assert(!OverlapsShadowSpace((void *)p, n));
if (OverlapsShadowSpace((void *)p, n)) {
kprintf("error: %p size %'zu overlaps shadow space\n", p, n);
_Exit(1);
}
m = weaken(_mmi);
a = (0x7fff8000 + (p >> 3)) >> 16;
b = (0x7fff8000 + (p >> 3) + (n >> 3) + 0xffff) >> 16;

View file

@ -46,6 +46,7 @@ relegated wontreturn void __assert_fail(const char *expr, const char *file,
} else {
rc = 24;
}
if (weaken(__die)) weaken(__die)();
__restorewintty();
_Exit(rc);
}

View file

@ -16,11 +16,11 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/strace.internal.h"
#include "libc/fmt/itoa.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/sysv/consts/at.h"
privileged const char *__strace_dirfd(char buf[12], int dirfd) {
const char *DescribeDirfd(char buf[hasatleast 12], int dirfd) {
if (dirfd == AT_FDCWD) return "AT_FDCWD";
FormatInt32(buf, dirfd);
return buf;

View file

@ -1,5 +1,11 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_DESCRIBEFLAGS_INTERNAL_H_
#define COSMOPOLITAN_LIBC_INTRIN_DESCRIBEFLAGS_INTERNAL_H_
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/rlimit.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timespec.h"
#include "libc/nt/struct/securityattributes.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
@ -15,8 +21,15 @@ const char *DescribeFlags(char *, size_t, struct DescribeFlags *, size_t,
const char *DescribeMapFlags(int);
const char *DescribeProtFlags(int);
const char *DescribeRemapFlags(int);
const char *DescribeRlimitName(int);
const char *DescribeSeccompOperationFlags(int);
const char *DescribePollFlags(char *, size_t, int);
const char *DescribeStat(int, const struct stat *);
const char *DescribeDirfd(char[hasatleast 12], int);
const char *DescribeSigaction(char *, size_t, int, const struct sigaction *);
const char *DescribeSigset(char *, size_t, int, const sigset_t *);
const char *DescribeRlimit(char *, size_t, int, const struct rlimit *);
const char *DescribeTimespec(char *, size_t, int, const struct timespec *);
const char *DescribeNtPageFlags(uint32_t);
const char *DescribeNtStartFlags(uint32_t);
@ -35,6 +48,8 @@ const char *DescribeNtConsoleModeOutputFlags(uint32_t);
const char *DescribeNtFileFlagsAndAttributes(uint32_t);
const char *DescribeNtSecurityAttributes(struct NtSecurityAttributes *);
void DescribeIov(const struct iovec *, int, ssize_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_DESCRIBEFLAGS_INTERNAL_H_ */

View file

@ -16,12 +16,19 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h"
void __strace_iov(const struct iovec *iov, int iovlen, ssize_t rem) {
void DescribeIov(const struct iovec *iov, int iovlen, ssize_t rem) {
int i;
if ((!IsAsan() && kisdangerous(iov)) ||
(IsAsan() && !__asan_is_valid(iov, iovlen * sizeof(struct iovec)))) {
kprintf("%p", iov);
return;
}
kprintf("{");
for (i = 0; rem && i < MIN(5, iovlen); ++i) {
kprintf(

View file

@ -25,6 +25,7 @@
const char *DescribeMapFlags(int x) {
_Alignas(char) static char mapflags[256];
const struct DescribeFlags kMapFlags[] = {
{MAP_STACK, "STACK"}, // order matters
{MAP_ANONYMOUS, "ANONYMOUS"}, //
{MAP_PRIVATE, "PRIVATE"}, //
{MAP_SHARED, "SHARED"}, //
@ -37,7 +38,6 @@ const char *DescribeMapFlags(int x) {
{MAP_NORESERVE, "NORESERVE"}, //
{MAP_NONBLOCK, "NONBLOCK"}, //
{MAP_POPULATE, "POPULATE"}, //
{MAP_STACK, "STACK"}, // order matters
};
return DescribeFlags(mapflags, sizeof(mapflags), kMapFlags,
ARRAYLEN(kMapFlags), "MAP_", x);

View file

@ -28,6 +28,8 @@ static noasan char DescribeMapType(int flags) {
return 'p';
case MAP_SHARED:
return 's';
case MAP_STACK:
return 'S';
default:
return '?';
}
@ -46,7 +48,7 @@ noasan char *DescribeMapping(int prot, int flags, char p[hasatleast 8]) {
DescribeProt(prot, p);
p[3] = DescribeMapType(flags);
p[4] = (flags & MAP_ANONYMOUS) ? 'a' : '-';
p[5] = (flags & MAP_GROWSDOWN) ? 'S' : '-';
p[5] = (flags & MAP_GROWSDOWN) ? 'G' : '-';
p[6] = (flags & MAP_FIXED) ? 'F' : '-';
p[7] = 0;
return p;

View file

@ -17,12 +17,19 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
privileged const char *__strace_sigset(char buf[41], size_t bufsize, int rc,
const sigset_t *ss) {
const char *DescribeRlimit(char *buf, size_t bufsize, int rc,
const struct rlimit *rlim) {
if (rc == -1) return "n/a";
if (!ss) return "NULL";
ksnprintf(buf, bufsize, "{%#lx, %#lx}", ss->__bits[0], ss->__bits[1]);
if (!rlim) return "NULL";
if ((!IsAsan() && kisdangerous(rlim)) ||
(IsAsan() && !__asan_is_valid(rlim, sizeof(*rlim)))) {
ksnprintf(buf, sizeof(buf), "%p", rlim);
} else {
ksnprintf(buf, bufsize, "{%'ld, %'ld}", rlim->rlim_cur, rlim->rlim_max);
}
return buf;
}

View file

@ -0,0 +1,47 @@
/*-*- 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/strace.internal.h"
#include "libc/fmt/itoa.h"
#include "libc/sysv/consts/rlimit.h"
const char *DescribeRlimitName(int resource) {
static char buf[12];
if (resource == 127) return "n/a";
if (resource == RLIMIT_AS) return "RLIMIT_AS";
if (resource == RLIMIT_CPU) return "RLIMIT_CPU";
if (resource == RLIMIT_FSIZE) return "RLIMIT_FSIZE";
if (resource == RLIMIT_NPROC) return "RLIMIT_NPROC";
if (resource == RLIMIT_NOFILE) return "RLIMIT_NOFILE";
if (resource == RLIMIT_RSS) return "RLIMIT_RSS";
if (resource == RLIMIT_DATA) return "RLIMIT_DATA";
if (resource == RLIMIT_CORE) return "RLIMIT_CORE";
if (resource == RLIMIT_STACK) return "RLIMIT_STACK";
if (resource == RLIMIT_SIGPENDING) return "RLIMIT_SIGPENDING";
if (resource == RLIMIT_MEMLOCK) return "RLIMIT_MEMLOCK";
if (resource == RLIMIT_LOCKS) return "RLIMIT_LOCKS";
if (resource == RLIMIT_MSGQUEUE) return "RLIMIT_MSGQUEUE";
if (resource == RLIMIT_NICE) return "RLIMIT_NICE";
if (resource == RLIMIT_RTPRIO) return "RLIMIT_RTPRIO";
if (resource == RLIMIT_RTTIME) return "RLIMIT_RTTIME";
if (resource == RLIMIT_SWAP) return "RLIMIT_SWAP";
if (resource == RLIMIT_SBSIZE) return "RLIMIT_SBSIZE";
if (resource == RLIMIT_NPTS) return "RLIMIT_NPTS";
FormatInt32(buf, resource);
return buf;
}

View file

@ -0,0 +1,85 @@
/*-*- 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/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
const char *DescribeStat(int rc, const struct stat *st) {
_Alignas(char) static char buf[300];
int i, n;
if (rc == -1) return "n/a";
if (!st) return "NULL";
if ((!IsAsan() && kisdangerous(st)) ||
(IsAsan() && !__asan_is_valid(st, sizeof(*st)))) {
ksnprintf(buf, sizeof(buf), "%p", st);
return buf;
}
i = 0;
n = sizeof(buf);
i += ksnprintf(buf + i, n - i, "{.st_%s=%'ld", "size", st->st_size);
if (st->st_blocks) {
i +=
ksnprintf(buf + i, n - i, ", .st_blocks=%'lu/512", st->st_blocks * 512);
}
if (st->st_mode) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%#o", "mode", st->st_mode);
}
if (st->st_nlink != 1) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%'lu", "nlink", st->st_nlink);
}
if (st->st_uid) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%lu", "uid", st->st_uid);
}
if (st->st_gid) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%lu", "gid", st->st_gid);
}
if (st->st_ino) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%lu", "ino", st->st_ino);
}
if (st->st_gen) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%'lu", "gen", st->st_gen);
}
if (st->st_flags) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%lx", "flags", st->st_flags);
}
if (st->st_rdev) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%'lu", "rdev", st->st_rdev);
}
if (st->st_blksize != PAGESIZE) {
i += ksnprintf(buf + i, n - i, ", .st_%s=%'lu", "blksize", st->st_blksize);
}
buf[i++] = '}';
return buf;
}

View file

@ -16,14 +16,20 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/strace.internal.h"
#include "libc/calls/struct/timespec.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
privileged const char *__strace_timespec(char buf[45], size_t bufsize, int rc,
const struct timespec *ts) {
const char *DescribeTimespec(char *buf, size_t bufsize, int rc,
const struct timespec *ts) {
if (rc == -1) return "n/a";
if (!ts) return "NULL";
ksnprintf(buf, bufsize, "{%ld, %ld}", ts->tv_sec, ts->tv_nsec);
if ((!IsAsan() && kisdangerous(ts)) ||
(IsAsan() && !__asan_is_valid(ts, sizeof(*ts)))) {
ksnprintf(buf, bufsize, "%p", ts);
} else {
ksnprintf(buf, bufsize, "{%ld, %ld}", ts->tv_sec, ts->tv_nsec);
}
return buf;
}

View file

@ -68,17 +68,22 @@ o/$(MODE)/libc/intrin/tls.greg.o \
o/$(MODE)/libc/intrin/exit.greg.o \
o/$(MODE)/libc/intrin/exit1.greg.o \
o/$(MODE)/libc/intrin/gettid.greg.o \
o/$(MODE)/libc/intrin/getenv.greg.o \
o/$(MODE)/libc/intrin/createfile.greg.o \
o/$(MODE)/libc/intrin/assertfail.greg.o \
o/$(MODE)/libc/intrin/reopenfile.greg.o \
o/$(MODE)/libc/intrin/deletefile.greg.o \
o/$(MODE)/libc/intrin/createpipe.greg.o \
o/$(MODE)/libc/intrin/closehandle.greg.o \
o/$(MODE)/libc/intrin/describeiov.greg.o \
o/$(MODE)/libc/intrin/openprocess.greg.o \
o/$(MODE)/libc/intrin/createthread.greg.o \
o/$(MODE)/libc/intrin/describestat.greg.o \
o/$(MODE)/libc/intrin/findnextfile.greg.o \
o/$(MODE)/libc/intrin/createprocess.greg.o \
o/$(MODE)/libc/intrin/findfirstfile.greg.o \
o/$(MODE)/libc/intrin/describeflags.greg.o \
o/$(MODE)/libc/intrin/describerlimit.greg.o \
o/$(MODE)/libc/intrin/removedirectory.greg.o \
o/$(MODE)/libc/intrin/createnamedpipe.greg.o \
o/$(MODE)/libc/intrin/unmapviewoffile.greg.o \
@ -88,6 +93,7 @@ o/$(MODE)/libc/intrin/createdirectory.greg.o \
o/$(MODE)/libc/intrin/flushfilebuffers.greg.o \
o/$(MODE)/libc/intrin/terminateprocess.greg.o \
o/$(MODE)/libc/intrin/describemapflags.greg.o \
o/$(MODE)/libc/intrin/describetimespec.greg.o \
o/$(MODE)/libc/intrin/getfileattributes.greg.o \
o/$(MODE)/libc/intrin/getexitcodeprocess.greg.o \
o/$(MODE)/libc/intrin/waitforsingleobject.greg.o \
@ -104,6 +110,10 @@ o/$(MODE)/libc/intrin/ntconsolemode.o: \
-ffreestanding \
$(NO_MAGIC)
o/$(MODE)/libc/intrin/describeopenflags.greg.o: \
OVERRIDE_CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED
o/$(MODE)/libc/intrin/asan.o \
o/$(MODE)/libc/intrin/ubsan.o: \
OVERRIDE_CFLAGS += \

View file

@ -520,10 +520,13 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va,
type = 0;
goto FormatString;
} else {
if (p + 4 <= e) {
if (p + 7 <= e) {
*p++ = ' ';
*p++ = 'e';
*p++ = 'r';
*p++ = 'r';
*p++ = 'n';
*p++ = 'o';
*p++ = '=';
}
type = 0;
@ -568,7 +571,7 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va,
if (!__replstderr || __nocolor) {
break;
} else {
s = "\r\033[K";
s = "\r\e[K";
goto FormatString;
}

View file

@ -24,19 +24,20 @@ COSMOPOLITAN_C_START_
#define DCHECK_NOTNULL(X, ...) \
__DCHK(ne, !=, NULL, "NULL", X, #X, "" __VA_ARGS__)
#define CHECK_ALIGNED(BYTES, VAR) \
do { \
if (((uintptr_t)VAR & ((BYTES)-1u))) { \
__check_fail_aligned(BYTES, (uintptr_t)VAR); \
unreachable; \
} \
VAR = (typeof(VAR))__builtin_assume_aligned(VAR, BYTES); \
#define CHECK_ALIGNED(BYTES, VAR, ...) \
do { \
if (((uintptr_t)VAR & ((BYTES)-1u))) { \
__check_fail_aligned(BYTES, (uintptr_t)VAR, __FILE__, __LINE__, \
"" __VA_ARGS__); \
unreachable; \
} \
VAR = (typeof(VAR))__builtin_assume_aligned(VAR, BYTES); \
} while (0)
#define DCHECK_ALIGNED(BYTES, VAR) \
#define DCHECK_ALIGNED(BYTES, VAR, ...) \
do { \
if (((uintptr_t)VAR & ((BYTES)-1u))) { \
__DCHK_ALIGNED(BYTES, (uintptr_t)VAR); \
__DCHK_ALIGNED(BYTES, (uintptr_t)VAR, "" __VA_ARGS__); \
unreachable; \
} \
VAR = (typeof(VAR))__builtin_assume_aligned(VAR, BYTES); \
@ -51,7 +52,8 @@ COSMOPOLITAN_C_START_
__check_fail(#SUFFIX, #OP, (uint64_t)Want, (WANTSTR), (uint64_t)Got, \
(GOTSTR), __FILE__, __LINE__, __VA_ARGS__); \
} else { \
__check_fail_##SUFFIX((uint64_t)Want, (uint64_t)Got); \
__check_fail_##SUFFIX((uint64_t)Want, (uint64_t)Got, __FILE__, \
__LINE__, 0, __VA_ARGS__); \
} \
unreachable; \
} \
@ -72,22 +74,30 @@ COSMOPOLITAN_C_START_
#endif /* NDEBUG */
#ifdef NDEBUG
#define __DCHK_ALIGNED(BYTES, VAR)
#define __DCHK_ALIGNED(BYTES, VAR, ...)
#else
#define __DCHK_ALIGNED(BYTES, VAR) __check_fail_aligned(BYTES, VAR)
#define __DCHK_ALIGNED(BYTES, VAR, ...) \
__check_fail_aligned(BYTES, VAR, __FILE__, __LINE__, __VA_ARGS__)
#endif
void __check_fail(const char *, const char *, uint64_t, const char *, uint64_t,
const char *, const char *, int, const char *,
...) relegated wontreturn;
void __check_fail_eq(uint64_t, uint64_t) relegated wontreturn;
void __check_fail_ne(uint64_t, uint64_t) relegated wontreturn;
void __check_fail_le(uint64_t, uint64_t) relegated wontreturn;
void __check_fail_lt(uint64_t, uint64_t) relegated wontreturn;
void __check_fail_ge(uint64_t, uint64_t) relegated wontreturn;
void __check_fail_gt(uint64_t, uint64_t) relegated wontreturn;
void __check_fail_aligned(unsigned, uint64_t) relegated wontreturn;
void __check_fail_eq(uint64_t, uint64_t, const char *, int, const char *,
const char *, ...) relegated wontreturn;
void __check_fail_ne(uint64_t, uint64_t, const char *, int, const char *,
const char *, ...) relegated wontreturn;
void __check_fail_le(uint64_t, uint64_t, const char *, int, const char *,
const char *, ...) relegated wontreturn;
void __check_fail_lt(uint64_t, uint64_t, const char *, int, const char *,
const char *, ...) relegated wontreturn;
void __check_fail_ge(uint64_t, uint64_t, const char *, int, const char *,
const char *, ...) relegated wontreturn;
void __check_fail_gt(uint64_t, uint64_t, const char *, int, const char *,
const char *, ...) relegated wontreturn;
void __check_fail_aligned(unsigned, uint64_t, const char *, int, const char *,
...) relegated wontreturn;
#ifdef __VSCODE_INTELLISENSE__
#undef __CHK

View file

@ -18,14 +18,16 @@
*/
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/stdio/stdio.h"
void __check_fail_aligned(unsigned bytes, uint64_t ptr) {
void __check_fail_aligned(unsigned bytes, uint64_t ptr, const char *file,
int line, const char *fmt, ...) {
fflush(stderr);
if (!IsTiny()) memsummary(fileno(stderr));
(dprintf)(fileno(stderr), "%s%d%s%#p\n", "error: pointer not ", bytes,
"-byte aligned: ", ptr);
kprintf("%s:%d: error: pointer not %d-byte aligned: %p\n", file, line, bytes,
ptr);
__die();
}

View file

@ -16,12 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/errno.h"
#include "libc/bits/weaken.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
/**
* Handles failure of CHECK_xx() macros in -DNDEBUG mode.
@ -33,12 +33,22 @@
*
* @see libc/log/thunks/__check_fail_ndebug.S
*/
relegated void ___check_fail_ndebug(uint64_t want, uint64_t got,
const char *opchar) {
relegated wontreturn void __check_fail_ndebug(uint64_t want, uint64_t got,
const char *file, int line,
const char *opchar,
const char *fmt, ...) {
va_list va;
__restore_tty();
(fprintf)(stderr, "\n%serror: %s: check failed: 0x%x %s 0x%x (%s)\n",
!__nocolor ? "\e[J" : "", program_invocation_name, want, opchar,
got, strerror(errno));
kprintf("%rerror:%s:%d: check failed: %'ld %s %'ld% m", file, line, want,
opchar, got);
if (*fmt) {
kprintf(": ");
va_start(va, fmt);
kvprintf(fmt, va);
va_end(va);
}
kprintf("\n");
if (weaken(__die)) weaken(__die)();
__restorewintty();
_Exit(68);
}

View file

@ -201,7 +201,7 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
uname(&names);
p = buf;
errno = err;
kprintf("\n%serror%s: Uncaught %G (%s) on %s pid %d\n"
kprintf("\n%serror%s: Uncaught %G (%s) on %s pid %d tid %d\n"
" %s\n"
" %m\n"
" %s %s %s %s\n",
@ -210,8 +210,8 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE))
? "Stack Overflow"
: GetSiCodeName(sig, si->si_code),
host, getpid(), program_invocation_name, names.sysname, names.version,
names.nodename, names.release);
host, getpid(), gettid(), program_invocation_name, names.sysname,
names.version, names.nodename, names.release);
if (ctx) {
kprintf("\n");
ShowFunctionCalls(ctx);

View file

@ -19,6 +19,8 @@
#include "libc/calls/sigbits.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigaltstack.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/internal.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
@ -33,6 +35,10 @@ STATIC_YOINK("__get_symbol_by_addr"); /* for asan memory origin */
extern const unsigned char __oncrash_thunks[8][11];
static void FreeSigaltstack(void *p) {
free(p);
}
/**
* Installs crash signal handlers.
*
@ -67,7 +73,7 @@ void ShowCrashReports(void) {
ss.ss_flags = 0;
ss.ss_size = SIGSTKSZ;
ss.ss_sp = malloc(SIGSTKSZ);
__cxa_atexit(free, ss.ss_sp, 0);
__cxa_atexit(FreeSigaltstack, ss.ss_sp, 0);
sa.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
sigfillset(&sa.sa_mask);
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {

View file

@ -21,6 +21,10 @@
// Code-size saving thunk for CHECK_EQ() in NDEBUG mode.
__check_fail_eq:
loadstr "==",dx
lea .Lop(%rip),%r8
jmp __check_fail_ndebug
.endfn __check_fail_eq,globl
.rodata.str1.1
.Lop: .asciz "=="
.previous

View file

@ -21,6 +21,10 @@
// Code-size saving thunk for CHECK_GE() in NDEBUG mode.
__check_fail_ge:
loadstr ">=",dx
lea .Lop(%rip),%r8
jmp __check_fail_ndebug
.endfn __check_fail_ge,globl
.rodata.str1.1
.Lop: .asciz ">="
.previous

View file

@ -21,6 +21,10 @@
// Code-size saving thunk for CHECK_GT() in NDEBUG mode.
__check_fail_gt:
loadstr ">",dx
lea .Lop(%rip),%r8
jmp __check_fail_ndebug
.endfn __check_fail_gt,globl
.rodata.str1.1
.Lop: .asciz ">"
.previous

View file

@ -21,6 +21,10 @@
// Code-size saving thunk for CHECK_LE() in NDEBUG mode.
__check_fail_le:
loadstr "<=",dx
lea .Lop(%rip),%r8
jmp __check_fail_ndebug
.endfn __check_fail_le,globl
.rodata.str1.1
.Lop: .asciz "<="
.previous

View file

@ -21,6 +21,10 @@
// Code-size saving thunk for CHECK_LT() in NDEBUG mode.
__check_fail_lt:
loadstr "<",dx
lea .Lop(%rip),%r8
jmp __check_fail_ndebug
.endfn __check_fail_lt,globl
.rodata.str1.1
.Lop: .asciz "<"
.previous

View file

@ -1,27 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2020 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/macros.internal.h"
__check_fail_ndebug:
push %rbp
mov %rsp,%rbp
call ___check_fail_ndebug
pop %rbp
jmp __die # fewer elements in backtrace
.endfn __check_fail_ndebug,globl

View file

@ -21,6 +21,10 @@
// Code-size saving thunk for CHECK_NE() in NDEBUG mode.
__check_fail_ne:
loadstr "!=",dx
lea .Lop(%rip),%r8
jmp __check_fail_ndebug
.endfn __check_fail_ne,globl
.rodata.str1.1
.Lop: .asciz "!="
.previous

View file

@ -38,7 +38,6 @@ __nt2sysv:
push %rdi
push %rsi
pushf
ezlea _base,bx
lea -0x80(%rbp),%rdi
call _savexmm
mov %rcx,%rdi

View file

@ -16,12 +16,12 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/dce.h"
#include "libc/macros.internal.h"
#include "libc/notice.inc"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/map.h"
#include "libc/calls/strace.internal.h"
#include "libc/sysv/consts/map.h"
#include "libc/dce.h"
.text.startup
@ -76,6 +76,44 @@ cosmo: push %rbp
ret
.endfn cosmo,weak
#if !IsTiny()
.init.start 304,_init_stack
testb IsWindows()
jnz 9f
push %rdi
push %rsi
// allocate stack
movabs $ape_stack_vaddr,%rdi
mov $ape_stack_memsz,%esi
mov $ape_stack_prot,%edx
mov $MAP_STACK,%ecx
or MAP_ANONYMOUS,%ecx
or $-1,%r8
xor %r9d,%r9d
push %rsi
call mmap
pop %r8
pop %rsi
pop %rdi
cmp $-1,%rax
je 9f
// switch stacks
leave
pop %rcx
lea (%rax,%r8),%rsp
sub $ape_stack_align,%rsp # openbsd:stackbound
mov %rbp,(%rsp)
push %rcx
push %rbp
mov %rsp,%rbp
9: nop
.init.end 304,_init_stack
.weak ape_stack_prot
.weak ape_stack_vaddr
.weak ape_stack_memsz
.weak ape_stack_align
#endif
#ifdef __PG__
.init.start 306,_init_ftrace
push %rdi

View file

@ -122,6 +122,15 @@ static textwindows void ViewOrDie(int64_t h, uint32_t access, size_t pos,
}
}
static textwindows int OnForkCrash(struct NtExceptionPointers *ep) {
kprintf("error: fork() child crashed!%n"
"\tExceptionCode = %#x%n"
"\tRip = %x%n",
ep->ExceptionRecord->ExceptionCode,
ep->ContextRecord ? ep->ContextRecord->Rip : -1);
ExitProcess(73);
}
textwindows void WinMainForked(void) {
bool ok;
jmp_buf jb;
@ -129,9 +138,9 @@ textwindows void WinMainForked(void) {
char *addr, *shad;
struct DirectMap dm;
uint64_t size, upsize;
int64_t savetsc, savebir;
struct MemoryInterval *maps;
char16_t fvar[21 + 1 + 21 + 1];
int64_t oncrash, savetsc, savebir;
uint32_t i, varlen, oldprot, savepid;
long mapcount, mapcapacity, specialz;
extern uint64_t ts asm("kStartTsc");
@ -142,6 +151,9 @@ textwindows void WinMainForked(void) {
if (!varlen || varlen >= ARRAYLEN(fvar)) return;
NTTRACE("WinMainForked()");
SetEnvironmentVariable(u"_FORK", NULL);
#ifdef SYSDEBUG
oncrash = AddVectoredExceptionHandler(1, NT2SYSV(OnForkCrash));
#endif
ParseInt(fvar, &reader);
// read the cpu state from the parent process & plus
@ -167,7 +179,7 @@ textwindows void WinMainForked(void) {
for (i = 0; i < mapcount; ++i) {
addr = (char *)((uint64_t)maps[i].x << 16);
size = maps[i].size;
if (maps[i].flags & MAP_PRIVATE) {
if ((maps[i].flags & MAP_TYPE) != MAP_SHARED) {
upsize = ROUNDUP(size, FRAMESIZE);
// we don't need to close the map handle because sys_mmap_nt
// doesn't mark it inheritable across fork() for MAP_PRIVATE
@ -226,6 +238,9 @@ textwindows void WinMainForked(void) {
}
// restore the crash reporting stuff
#ifdef SYSDEBUG
RemoveVectoredExceptionHandler(oncrash);
#endif
if (weaken(__wincrash_nt)) {
if (!IsTiny()) {
RemoveVectoredExceptionHandler(__wincrashearly);
@ -292,7 +307,7 @@ textwindows int sys_fork_nt(void) {
(_mmi.i * sizeof(_mmi.p[0])) >> 3);
}
for (i = 0; i < _mmi.i && ok; ++i) {
if (_mmi.p[i].flags & MAP_PRIVATE) {
if ((_mmi.p[i].flags & MAP_TYPE) != MAP_SHARED) {
ok = WriteAll(writer, (void *)((uint64_t)_mmi.p[i].x << 16),
_mmi.p[i].size);
}

View file

@ -47,6 +47,12 @@
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
#define MAP_ANONYMOUS_linux 0x00000020
#define MAP_ANONYMOUS_openbsd 0x00001000
#define MAP_GROWSDOWN_linux 0x00000100
#define MAP_STACK_freebsd 0x00000400
#define MAP_STACK_openbsd 0x00004000
#define IP(X) (intptr_t)(X)
#define VIP(X) (void *)IP(X)
#define ALIGNED(p) (!(IP(p) & (FRAMESIZE - 1)))
@ -122,20 +128,9 @@ noasan static size_t GetMemtrackSize(struct MemoryIntervals *mm) {
return n;
}
static noasan void *MapMemory(void *addr, size_t size, int prot, int flags,
int fd, int64_t off, int f, int x, int n) {
struct DirectMap dm;
dm = sys_mmap(addr, size, prot, f, fd, off);
if (UNLIKELY(dm.addr == MAP_FAILED)) {
if (IsWindows() && (flags & MAP_FIXED)) {
OnUnrecoverableMmapError(
"can't recover from MAP_FIXED errors on Windows");
}
return MAP_FAILED;
}
if (UNLIKELY(dm.addr != addr)) {
OnUnrecoverableMmapError("KERNEL DIDN'T RESPECT MAP_FIXED");
}
static noasan void *FinishMemory(void *addr, size_t size, int prot, int flags,
int fd, int64_t off, int f, int x, int n,
struct DirectMap dm) {
if (!IsWindows() && (flags & MAP_FIXED)) {
if (UntrackMemoryIntervals(addr, size)) {
OnUnrecoverableMmapError("FIXED UNTRACK FAILED");
@ -154,6 +149,23 @@ static noasan void *MapMemory(void *addr, size_t size, int prot, int flags,
return addr;
}
static noasan void *MapMemory(void *addr, size_t size, int prot, int flags,
int fd, int64_t off, int f, int x, int n) {
struct DirectMap dm;
dm = sys_mmap(addr, size, prot, f, fd, off);
if (UNLIKELY(dm.addr == MAP_FAILED)) {
if (IsWindows() && (flags & MAP_FIXED)) {
OnUnrecoverableMmapError(
"can't recover from MAP_FIXED errors on Windows");
}
return MAP_FAILED;
}
if (UNLIKELY(dm.addr != addr)) {
OnUnrecoverableMmapError("KERNEL DIDN'T RESPECT MAP_FIXED");
}
return FinishMemory(addr, size, prot, flags, fd, off, f, x, n, dm);
}
/**
* Maps memory from system, one frame at a time.
*
@ -175,8 +187,8 @@ static textwindows dontinline noasan void *MapMemories(char *addr, size_t size,
sz = size - m;
dm = sys_mmap(addr + m, sz, prot, f, fd, oi);
if (dm.addr == MAP_FAILED) return MAP_FAILED;
iscow = (flags & MAP_PRIVATE) && fd != -1;
readonlyfile = (flags & MAP_SHARED) && fd != -1 &&
iscow = (flags & MAP_TYPE) != MAP_SHARED && fd != -1;
readonlyfile = (flags & MAP_TYPE) == MAP_SHARED && fd != -1 &&
(g_fds.p[fd].flags & O_ACCMODE) == O_RDONLY;
if (TrackMemoryInterval(&_mmi, x + (n - 1), x + (n - 1), dm.maphandle, prot,
flags, readonlyfile, iscow, oi, sz) == -1) {
@ -208,6 +220,7 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags,
}
#endif
char *p = addr;
bool needguard;
struct DirectMap dm;
size_t virtualused, virtualneed;
int a, b, i, f, m, n, x;
@ -311,19 +324,68 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags,
return VIP(enomem());
}
needguard = false;
p = (char *)ADDR(x);
if (IsOpenbsd() && (f & MAP_GROWSDOWN)) { /* openbsd:dubstack */
dm = sys_mmap(p, size, prot, f & ~MAP_GROWSDOWN, fd, off);
if (dm.addr == MAP_FAILED) {
return MAP_FAILED;
if ((f & MAP_TYPE) == MAP_STACK) {
if (~f & MAP_ANONYMOUS) {
STRACE("MAP_STACK must be anonymous");
return VIP(einval());
}
f &= ~MAP_TYPE;
f |= MAP_PRIVATE;
if (IsOpenbsd()) { // openbsd:dubstack
// on openbsd this is less about scalability of threads, and more
// about defining the legal intervals for the RSP register. sadly
// openbsd doesn't let us create a new fixed stack mapping. but..
// openbsd does allow us to overwrite existing fixed mappings, to
// authorize its usage as a stack.
if (sys_mmap(p, size, prot, f, fd, off).addr == MAP_FAILED) {
return MAP_FAILED;
}
f |= MAP_STACK_openbsd;
} else if (IsLinux()) {
// by default MAP_GROWSDOWN will auto-allocate 10mb of pages. it's
// supposed to stop growing if an adjacent allocation exists, to
// prevent your stacks from overlapping on each other. we're not
// able to easily assume a mapping beneath this one exists. even
// if we could, the linux kernel requires for muh security reasons
// that stacks be at least 1mb away from each other, so it's not
// possible to avoid this call if our goal is to have 60kb stacks
// with 4kb guards like a sane multithreaded production system.
// however this 1mb behavior oddly enough is smart enough to not
// apply if the mapping is a manually-created guard page.
if ((dm = sys_mmap(p + size - PAGESIZE, PAGESIZE, prot,
f | MAP_GROWSDOWN_linux, fd, off))
.addr == MAP_FAILED) {
return MAP_FAILED;
}
sys_mmap(p, PAGESIZE, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
dm.addr = p;
return FinishMemory(p, size, prot, flags, fd, off, f, x, n, dm);
} else {
if (IsFreebsd()) {
f |= MAP_STACK_freebsd;
}
needguard = true;
}
}
if (!IsWindows()) {
return MapMemory(p, size, prot, flags, fd, off, f, x, n);
p = MapMemory(p, size, prot, flags, fd, off, f, x, n);
} else {
return MapMemories(p, size, prot, flags, fd, off, f, x, n);
p = MapMemories(p, size, prot, flags, fd, off, f, x, n);
}
if (p != MAP_FAILED) {
if (needguard) {
if (IsWindows()) _spunlock(&_mmi.lock);
mprotect(p, PAGESIZE, PROT_NONE);
if (IsWindows()) _spinlock(&_mmi.lock);
}
}
return p;
}
/**

View file

@ -21,6 +21,7 @@
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/prot.h"

View file

@ -87,7 +87,7 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags) {
kprintf(".control=%#.*hhs, ", msg->msg_controllen, msg->msg_control);
if (msg->msg_flags) kprintf(".flags=%#x, ", msg->msg_flags);
kprintf(".iov=", fd);
__strace_iov(msg->msg_iov, msg->msg_iovlen, rc != -1 ? rc : 0);
DescribeIov(msg->msg_iov, msg->msg_iovlen, rc != -1 ? rc : 0);
kprintf("}], %#x) → %'ld% m\n", flags, rc);
}
}

View file

@ -22,6 +22,7 @@
#include "libc/calls/struct/iovec.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
@ -45,6 +46,7 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) {
int64_t rc;
char addr2[128];
struct msghdr msg2;
if (IsAsan() && !__asan_is_valid_msghdr(msg)) {
rc = efault();
} else if (!IsWindows()) {
@ -77,22 +79,26 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) {
} else {
rc = ebadf();
}
#if defined(SYSDEBUG) && _DATATRACE
if (__strace > 0) {
if (!msg || (rc == -1 && errno == EFAULT)) {
DATATRACE("sendmsg(%d, %p, %#x) → %'ld% m", fd, msg, flags, rc);
kprintf(STRACE_PROLOGUE "sendmsg(");
if ((!IsAsan() && kisdangerous(msg)) ||
(IsAsan() && !__asan_is_valid(msg, sizeof(*msg)))) {
kprintf("%p", msg);
} else {
kprintf(STRACE_PROLOGUE "sendmsg(%d, {");
if (msg->msg_namelen)
kprintf(".name=%#.*hhs, ", msg->msg_namelen, msg->msg_name);
kprintf("{");
kprintf(".name=%#.*hhs, ", msg->msg_namelen, msg->msg_name);
if (msg->msg_controllen)
kprintf(".control=%#.*hhs, ", msg->msg_controllen, msg->msg_control);
kprintf(", .control=%#.*hhs, ", msg->msg_controllen, msg->msg_control);
if (msg->msg_flags) kprintf(".flags=%#x, ", msg->msg_flags);
kprintf(".iov=", fd);
__strace_iov(msg->msg_iov, msg->msg_iovlen, rc != -1 ? rc : 0);
kprintf("}, %#x) → %'ld% m\n", flags, rc);
kprintf(", .iov=", fd);
DescribeIov(msg->msg_iov, msg->msg_iovlen, rc != -1 ? rc : 0);
kprintf("}");
}
kprintf(", %#x) → %'ld% m\n", flags, rc);
}
#endif
return rc;
}

View file

@ -221,20 +221,20 @@ syscon compat O_LARGEFILE 0 0 0 0 0 0 #
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_STACK 6 6 6 6 6 6 # our definition
syscon mmap MAP_TYPE 15 15 15 15 15 15 # mask for type of mapping
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 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_FIXED 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 # unix consensus; openbsd appears to forbid; faked nt
syscon mmap MAP_FIXED_NOREPLACE 0x08000000 0x08000000 0x08000000 0x08000000 0x08000000 0x08000000 # handled and defined by cosmo runtime; 0x100000 on linux 4.7+
syscon mmap MAP_ANONYMOUS 0x00000020 0x00001000 0x00001000 0x00001000 0x00001000 0x00000020 # bsd consensus; faked nt
syscon mmap MAP_GROWSDOWN 0x00000100 0 0 0 0 0 # use MAP_STACK; abstracted by MAP_STACK; may be passed to __sys_mmap() for low-level Linux fiddling
syscon mmap MAP_CONCEAL 0 0 0x00020000 0x00008000 0x00008000 0 # omit from core dumps; MAP_NOCORE on FreeBSD
syscon mmap MAP_LOCKED 0x00002000 0 0 0 0 0
syscon mmap MAP_NORESERVE 0x00004000 0x00000040 0 0 0x00000040 0 # Linux calls it "reserve"; NT calls it "commit"? which is default?
syscon mmap MAP_POPULATE 0x00008000 0 0 0 0 0 # can avoid madvise(MADV_WILLNEED) on private file mapping
syscon mmap MAP_NONBLOCK 0x00010000 0 0 0 0 0
syscon mmap MAP_HUGETLB 0x00040000 0 0 0 0 0x80000000 # kNtSecLargePages
syscon mmap MAP_HUGE_MASK 63 0 0 0 0 0
syscon mmap MAP_HUGE_SHIFT 26 0 0 0 0 0
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_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

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon mmap,MAP_ANONYMOUS,0x20,0x1000,0x0001000,0x1000,0x1000,0x20
.syscon mmap,MAP_ANONYMOUS,0x00000020,0x00001000,0x00001000,0x00001000,0x00001000,0x00000020

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon mmap,MAP_CONCEAL,0,0,0x0020000,0x8000,0x8000,0
.syscon mmap,MAP_CONCEAL,0,0,0x00020000,0x00008000,0x00008000,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon mmap,MAP_FIXED,0x0000010,0x0000010,0x0000010,0x0000010,0x0000010,0x0000010
.syscon mmap,MAP_FIXED,0x00000010,0x00000010,0x00000010,0x00000010,0x00000010,0x00000010

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon mmap,MAP_FIXED_NOREPLACE,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000,0x8000000
.syscon mmap,MAP_FIXED_NOREPLACE,0x08000000,0x08000000,0x08000000,0x08000000,0x08000000,0x08000000

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon mmap,MAP_GROWSDOWN,0x0100,0,0x0000400,0x4000,0x4000,0x100000
.syscon mmap,MAP_GROWSDOWN,0x00000100,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon mmap,MAP_HUGETLB,0x040000,0,0,0,0,0x80000000
.syscon mmap,MAP_HUGETLB,0x00040000,0,0,0,0,0x80000000

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon mmap,MAP_LOCKED,0x2000,0,0,0,0,0
.syscon mmap,MAP_LOCKED,0x00002000,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon mmap,MAP_NONBLOCK,0x10000,0,0,0,0,0
.syscon mmap,MAP_NONBLOCK,0x00010000,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon mmap,MAP_NORESERVE,0x4000,0x40,0,0,64,0
.syscon mmap,MAP_NORESERVE,0x00004000,0x00000040,0,0,0x00000040,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon mmap,MAP_POPULATE,0x8000,0,0,0,0,0
.syscon mmap,MAP_POPULATE,0x00008000,0,0,0,0,0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon mmap,MAP_STACK,0x0100,0,0x0000400,0x4000,0x2000,0x100000
.syscon mmap,MAP_STACK,6,6,6,6,6,6

View file

@ -7,6 +7,7 @@ COSMOPOLITAN_C_START_
extern const long MAP_32BIT;
extern const long MAP_ANON;
extern const long MAP_ANONYMOUS;
extern const long MAP_CONCEAL;
extern const long MAP_DENYWRITE;
extern const long MAP_EXECUTABLE;
extern const long MAP_FILE;
@ -21,7 +22,6 @@ extern const long MAP_NORESERVE;
extern const long MAP_POPULATE;
extern const long MAP_PRIVATE;
extern const long MAP_SHARED;
extern const long MAP_CONCEAL;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
@ -29,6 +29,7 @@ COSMOPOLITAN_C_END_
#define MAP_FILE 0
#define MAP_SHARED 1
#define MAP_PRIVATE 2
#define MAP_STACK 6
#define MAP_TYPE 15
#define MAP_FIXED 16
#define MAP_FIXED_NOREPLACE 0x8000000
@ -36,6 +37,7 @@ COSMOPOLITAN_C_END_
#define MAP_32BIT SYMBOLIC(MAP_32BIT)
#define MAP_ANONYMOUS SYMBOLIC(MAP_ANONYMOUS)
#define MAP_CONCEAL SYMBOLIC(MAP_CONCEAL)
#define MAP_CONCEAL SYMBOLIC(MAP_CONCEAL)
#define MAP_DENYWRITE SYMBOLIC(MAP_DENYWRITE)
#define MAP_EXECUTABLE SYMBOLIC(MAP_EXECUTABLE)
#define MAP_GROWSDOWN SYMBOLIC(MAP_GROWSDOWN)
@ -46,10 +48,8 @@ COSMOPOLITAN_C_END_
#define MAP_NONBLOCK SYMBOLIC(MAP_NONBLOCK)
#define MAP_NORESERVE SYMBOLIC(MAP_NORESERVE)
#define MAP_POPULATE SYMBOLIC(MAP_POPULATE)
#define MAP_CONCEAL SYMBOLIC(MAP_CONCEAL)
#define MAP_ANON MAP_ANONYMOUS
#define MAP_NOCORE MAP_CONCEAL
#define MAP_STACK MAP_GROWSDOWN
#endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_MAP_H_ */

View file

@ -20,9 +20,7 @@
#include "libc/dce.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/macros.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/prot.h"
/*
@ -355,107 +353,6 @@ _init_systemfive_pid:
.endfn _init_systemfive_pid
#endif
#if SupportsSystemv() && !defined(TINY)
// Create a stack with deterministic readable addresses.
// If ape_execve() already created us a stack that meets
// the requirements of STATIC_STACK_SIZE() then we skip.
_init_systemfive_stack:
#if SupportsWindows() || SupportsMetal() || SupportsOpenbsd()
testb $WINDOWS|METAL,__hostos(%rip)
jnz _init_systemfive_done
#endif
push %rdi
push %rsi
mov __NR_mmap,%eax
movabs $ape_stack_vaddr,%rdi
mov $ape_stack_memsz,%esi
mov $ape_stack_prot,%edx
mov $MAP_PRIVATE|MAP_FIXED,%r10d
or MAP_ANONYMOUS,%r10d
or $-1,%r8d
xor %r9d,%r9d
push %rdi # vaddr of stack
push %rsi # size of stack
push %r9 # openbsd:pad
push %r9 # openbsd:align
#if SupportsOpenbsd()
testb IsOpenbsd()
jz 0f
syscall # openbsd:dubstack
jc 1f
mov __NR_mmap,%eax
#endif
0: or MAP_GROWSDOWN,%r10d # openbsd:mapstack
clc
syscall
pop %r9
pop %r9
pop %r9 # size of stack
pop %r11 # vaddr of stack
jnc 2f
1: mov %eax,%edi
mov __NR_exit_group,%eax
syscall
2: test %rax,%rax
js 1b
// prevent operating system from auto-mapping stack
// we guarantee stack overflows are always detected
// so long as you never use -DSTACK_FRAME_UNLIMITED
// TODO: Why does this fail sometimes with FreeBSD?
testb IsFreebsd()
jnz 9f
push %rax
push %rdx
push %r11
mov __NR_mprotect,%eax
mov $PAGESIZE,%esi
xor %edx,%edx # PROT_NONE
syscall
pop %r11
pop %rdx
pop %rax
9:
// update the memory intervals
// m.i 0 4
// m.n 8 4
// m.p 16 8
// m.p[0].x 24 4
// m.p[0].y 28 4
// m.p[0].h 32 8
// m.p[0].prot 40 4
// m.p[0].flags 44 4
// m.p[0].offset 48 8
// m.p[0].size 56 8
.weak _mmi
ezlea _mmi,cx
test %rcx,%rcx
jz 3f
push %r9 # save the stack size
lea -1(%r11,%r9),%r9 # need incl. interval
shr $16,%r11 # for the stack range
shr $16,%r9
movb $1,(%rcx) # _mmi.i
mov %r11d,24(%rcx) # _mmi.s[0].x
mov %r9d,28(%rcx) # _mmi.s[0].y
orq $-1,32(%rcx) # _mmi.s[0].h
mov %edx,40(%rcx) # _mmi.s[0].prot
mov %r10d,44(%rcx) # _mmi.s[0].flags
pop %r9 # restore stack size
mov %r9,56(%rcx) # _mmi.s[0].size
3: pop %rsi
pop %rdi
leave
// switch stacks
pop %rcx
lea (%rax,%r9),%rsp
sub $ape_stack_align,%rsp # openbsd:stackbound
mov %rbp,(%rsp)
push %rcx
push %rbp
mov %rsp,%rbp
// 𝑠𝑙𝑖𝑑𝑒
_init_systemfive_syscall:
mov __NR_msyscall,%eax # syscall origin protect
cmp $0xfff,%ax # openbsd is pretty cool
@ -556,8 +453,3 @@ syscon_windows:/*
.asciz " %'u magnums loaded on %s\n"
.previous
#endif /* DEBUGSYS */
.weak ape_stack_prot
.weak ape_stack_vaddr
.weak ape_stack_memsz
.weak ape_stack_align

View file

@ -47,7 +47,7 @@
STATIC_YOINK("gettid"); // for kprintf()
#define __NR_thr_new 455
#define __NR_sys___tfork 8
#define __NR___tfork 8
#define __NR_clone_linux 56
#define __NR__lwp_create 309
#define __NR_getcontext_netbsd 307
@ -67,6 +67,7 @@ static struct Cloner {
} __cloner;
static textwindows uint32_t WinThreadMain(void *notused) {
intptr_t rdi, rdx;
int (*func)(void *);
void *arg, *stack;
struct WinThread *wt;
@ -82,16 +83,18 @@ static textwindows uint32_t WinThreadMain(void *notused) {
wt->pid = tid;
TlsSetValue(__winthread, wt);
if (flags & CLONE_CHILD_SETTID) *ctid = tid;
asm volatile("mov\t%%rbp,%%rbx\n\t"
asm volatile("push\t%%rbp\n\t"
"mov\t%%rsp,%%r15\n\t"
"xor\t%%ebp,%%ebp\n\t"
"xchg\t%%rax,%%rsp\n\t"
"call\t*%2\n\t"
"mov\t%%rbx,%%rbp\n\t"
"mov\t%%r15,%%rsp"
: "=a"(exitcode)
: "0"(stack), "d"(func), "D"(arg)
: "rbx", "r15", "memory");
"mov\t%%r15,%%rsp\n\t"
"pop\t%%rbp"
: "=a"(exitcode), "=D"(rdi), "=d"(rdx)
: "0"(stack), "1"(arg), "2"(func)
: "rbx", "rcx", "rsi", "r8", "r9", "r10", "r11", "r15",
"memory");
if (flags & CLONE_CHILD_CLEARTID) *ctid = 0;
__releasefd(tid);
free(wt);
@ -113,8 +116,7 @@ static textwindows int CloneWindows(int (*func)(void *), void *stk,
__cloner.ctid = ctid;
__cloner.flags = flags;
__cloner.stack = (char *)stk + stksz;
if (!(hand = CreateThread(&kNtIsInheritable, 0, NT2SYSV(WinThreadMain), 0, 0,
&wintid))) {
if (!(hand = CreateThread(0, 0, NT2SYSV(WinThreadMain), 0, 0, &wintid))) {
_spunlock(&__cloner.lock);
return -1;
}
@ -132,6 +134,7 @@ static dontinline wontreturn void BsdThreadMain(void *unused) {
void *arg;
int (*func)(void *);
int tid, flags, exitcode, *ctid;
asm("xor\t%ebp,%ebp");
tid = __cloner.tid;
arg = __cloner.arg;
func = __cloner.func;
@ -193,26 +196,24 @@ static privileged noasan int CloneOpenbsd(int (*func)(void *), char *stk,
asm volatile("" ::: "memory");
params.tf_tid = (int *)&__cloner.tid;
params.tf_tcb = flags & CLONE_SETTLS ? tls : 0;
params.tf_stack = stk + stksz;
// we need openbsd:stackbound because openbsd kernel enforces rsp must
// be on interval [stack, stack+size) thus the top address is an error
// furthermore this needs to be allocated using MAP_STACK OR GROWSDOWN
params.tf_stack = (void *)((intptr_t)((char *)stk + stksz - 1) & -16);
asm volatile(CFLAG_ASM("syscall")
: CFLAG_CONSTRAINT(failed), "=a"(ax)
: "1"(__NR_sys___tfork), "D"(&params), "S"(sizeof(params))
: "rcx", "r11", "memory", "cc");
if (!failed) {
if (!ax) {
// this is the child thread
// we probably can't access local variables anymore
asm volatile("" ::: "memory");
BsdThreadMain(0);
unreachable;
} else {
if (flags & CLONE_PARENT_SETTID) *ptid = ax;
return ax;
}
} else {
: "1"(__NR___tfork), "D"(&params), "S"(sizeof(params))
: "r11", "memory", "cc");
if (failed) {
errno = ax;
return -1;
}
if (ax) {
if (flags & CLONE_PARENT_SETTID) *ptid = ax;
return ax;
}
BsdThreadMain(0);
unreachable;
}
static privileged noasan int CloneNetbsd(int (*func)(void *), void *stk,
@ -231,8 +232,8 @@ static privileged noasan int CloneNetbsd(int (*func)(void *), void *stk,
errno = ax;
return -1;
}
stack = (void *)(((long)((char *)stk + stksz) & -16) - 8 * 3);
*(long *)stack = (long)_Exit1;
stack = (intptr_t *)((intptr_t)((char *)stk + stksz) & -16);
*--stack = (intptr_t)_Exit1;
ctx.uc_link = 0;
ctx.uc_mcontext.rip = (intptr_t)func;
ctx.uc_mcontext.rdi = (intptr_t)arg;
@ -265,14 +266,15 @@ static privileged int CloneLinux(int (*func)(void *), void *stk, size_t stksz,
size_t tlssz, int *ctid) {
int ax;
bool failed;
intptr_t *stack;
register int *r8 asm("r8") = tls;
register int (*r9)(void *) asm("r9") = func;
register int *r10 asm("r10") = ctid;
stk = (void *)(((long)((char *)stk + stksz) & -16) - 8);
*(long *)stk = (long)arg;
stack = (intptr_t *)((long)((char *)stk + stksz) & -16);
*--stack = (long)arg; // push 1
asm volatile("syscall"
: "=a"(ax)
: "0"(__NR_clone_linux), "D"(flags), "S"(stk), "d"(ptid),
: "0"(__NR_clone_linux), "D"(flags), "S"(stack), "d"(ptid),
"r"(r10), "r"(r8), "r"(r9)
: "rcx", "r11", "memory");
if (ax > -4096u) {
@ -281,8 +283,8 @@ static privileged int CloneLinux(int (*func)(void *), void *stk, size_t stksz,
}
if (ax) return ax;
asm volatile("xor\t%%ebp,%%ebp\n\t"
"pop\t%%rdi\n\t"
"call\t%0\n\t"
"pop\t%%rdi\n\t" // pop 1
"call\t*%0\n\t"
"xchg\t%%eax,%%edi\n\t"
"jmp\t_Exit1"
: /* no outputs */
@ -302,6 +304,8 @@ static privileged int CloneLinux(int (*func)(void *), void *stk, size_t stksz,
* @param func is your callback function
* @param stk points to the bottom of a caller allocated stack, which
* must be null when fork() and vfork() equivalent flags are used
* and furthermore this must be mmap()'d using MAP_STACK in order
* to work on OpenBSD
* @param stksz is the size of that stack in bytes which must be zero
* if the fork() or vfork() equivalent flags are used it's highly
* recommended that this value be GetStackSize(), or else kprintf
@ -350,7 +354,8 @@ privileged int clone(int (*func)(void *), void *stk, size_t stksz, int flags,
}
// polyfill fork() and vfork() use case on platforms w/o clone
else if (flags == (CLONE_VFORK | CLONE_VM | SIGCHLD)) {
else if ((SupportsWindows() || SupportsBsd()) &&
flags == (CLONE_VFORK | CLONE_VM | SIGCHLD)) {
if (IsTiny()) {
rc = einval();
} else if (!arg && !stksz) {
@ -358,7 +363,7 @@ privileged int clone(int (*func)(void *), void *stk, size_t stksz, int flags,
} else {
rc = einval();
}
} else if (flags == SIGCHLD) {
} else if ((SupportsWindows() || SupportsBsd()) && flags == SIGCHLD) {
if (IsTiny()) {
rc = eopnotsupp();
} else if (!arg && !stksz) {

View file

@ -46,6 +46,7 @@ $(LIBC_THREAD_A).pkg: \
$(LIBC_THREAD_A_OBJS) \
$(foreach x,$(LIBC_THREAD_A_DIRECTDEPS),$($(x)_A).pkg)
# no red zone because asm("call")
o/$(MODE)/libc/thread/clone.o: \
OVERRIDE_CFLAGS += \
-mno-red-zone

View file

@ -28,6 +28,8 @@
#include "libc/runtime/stack.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/clone.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/testlib/testlib.h"
@ -71,13 +73,10 @@ TEST(rand64, testLcg_doesntProduceIdenticalValues) {
}
TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) {
char *stack;
sigset_t ss, oldss;
void *stacks[THREADS];
int i, j, rc, ws, tid[THREADS];
if (IsXnu()) return;
if (IsNetbsd()) return; // still flaky :'(
if (IsOpenbsd()) return; // still flaky :'(
if (IsTiny() && IsWindows()) return; // todo(jart): wut
struct sigaction oldsa;
struct sigaction sa = {.sa_handler = OnChld, .sa_flags = SA_RESTART};
EXPECT_NE(-1, sigaction(SIGCHLD, &sa, &oldsa));
@ -90,8 +89,9 @@ TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) {
}
ready = false;
for (i = 0; i < THREADS; ++i) {
stack = gc(malloc(GetStackSize()));
tid[i] = clone(Thrasher, stack, GetStackSize(),
stacks[i] = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
tid[i] = clone(Thrasher, stacks[i], FRAMESIZE,
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
(void *)(intptr_t)i, 0, 0, 0, 0);
ASSERT_NE(-1, tid[i]);
@ -109,4 +109,7 @@ TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) {
EXPECT_NE(A[i], A[j], "i=%d j=%d", i, j);
}
}
for (i = 0; i < THREADS; ++i) {
EXPECT_SYS(0, 0, munmap(stacks[i], FRAMESIZE));
}
}

View file

@ -99,9 +99,8 @@ TEST(mmap, testMapFixed_destroysEverythingInItsPath) {
TEST(mmap, customStackMemory_isAuthorized) {
char *stack;
uintptr_t w, r;
ASSERT_NE(MAP_FAILED,
(stack = mmap(NULL, STACKSIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN, -1, 0)));
ASSERT_NE(MAP_FAILED, (stack = mmap(NULL, STACKSIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_STACK, -1, 0)));
asm("mov\t%%rsp,%0\n\t"
"mov\t%2,%%rsp\n\t"
"push\t%3\n\t"
@ -110,6 +109,7 @@ TEST(mmap, customStackMemory_isAuthorized) {
: "=&r"(w), "=&r"(r)
: "rm"(stack + STACKSIZE - 8), "i"(123));
ASSERT_EQ(123, r);
EXPECT_SYS(0, 0, munmap(stack, STACKSIZE));
}
TEST(mmap, fileOffset) {

View file

@ -20,6 +20,8 @@
#include "libc/dce.h"
#include "libc/intrin/spinlock.h"
#include "libc/sysv/consts/clone.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h"
#include "libc/testlib/testlib.h"
int x, thechilde;
@ -41,17 +43,18 @@ int thread(void *arg) {
TEST(clone, test) {
if (IsXnu()) return;
if (IsOpenbsd()) return; // still flaky :'(
int me, tid;
char *stack;
me = gettid();
_spinlock(&lock);
stack = _gc(valloc(STACKSIZE));
ASSERT_NE(-1, (tid = clone(thread, stack, STACKSIZE,
stack = mmap(0, FRAMESIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
ASSERT_NE(-1, (tid = clone(thread, stack, FRAMESIZE,
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
(void *)23, 0, 0, 0, 0)));
_spinlock(&lock);
ASSERT_EQ(42, x);
ASSERT_NE(me, tid);
ASSERT_EQ(tid, thechilde);
EXPECT_SYS(0, 0, munmap(stack, FRAMESIZE));
}

View file

@ -140,7 +140,6 @@
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/nomultics.internal.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
@ -2498,7 +2497,7 @@ char *linenoiseWithHistory(const char *prompt, const char *prog) {
fflush(stdout);
if ((path = linenoiseGetHistoryPath(prog))) {
if (linenoiseHistoryLoad(path) == -1) {
kprintf("%r%s: failed to load history: %m%n", path);
fprintf(stderr, "%s: failed to load history: %m\n", path);
free(path);
path = 0;
}

View file

@ -1485,7 +1485,7 @@ load_too_high (void)
}
}
/* If we got here, something went wrong. Give up on this method. */
/* If we 𝑔𝑜𝑡 𝑕𝑒𝑟𝑒, something went wrong. Give up on this method. */
if (r < 0)
DB (DB_JOBS, ("Failed to read " LOADAVG ": %s\n", strerror (errno)));

View file

@ -353,10 +353,7 @@
(add-hook 'asm-mode-hook 'cosmo-asm-supplemental-hook)
(setq asm-font-lock-keywords cosmo-asm-font-lock-keywords))
;; Make -*-unix-assembly-*- mode line work correctly.
;; TODO(jart): Would be nice to use GitHub's name instead of changing asm-mode.
(defun unix-assembly-mode ()
(interactive)
(asm-mode))
;; Make -*-unix-assembly-*- mode line work correctly like GitHub.
(define-derived-mode unix-assembly-mode asm-mode "UNIX Assembly")
(provide 'cosmo-asm-mode)

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