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

@ -60,7 +60,7 @@
# build/config.mk # build/config.mk
SHELL = /bin/sh SHELL = /bin/sh
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 xnu win7 win10 HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 xnu #win7 win10
SANITY := $(shell build/sanitycheck $$PPID) SANITY := $(shell build/sanitycheck $$PPID)
.SUFFIXES: .SUFFIXES:
@ -210,7 +210,7 @@ CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS))
bins: $(BINS) bins: $(BINS)
check: $(CHECKS) check: $(CHECKS)
test: $(TESTS) all test: $(TESTS)
depend: o/$(MODE)/depend depend: o/$(MODE)/depend
tags: TAGS HTAGS tags: TAGS HTAGS

View file

@ -1070,18 +1070,12 @@ str.error:
str.crlf: str.crlf:
.asciz "\r\n" .asciz "\r\n"
.endobj str.crlf .endobj str.crlf
str.cpuid:
.asciz "cpuid"
.endobj str.cpuid
str.oldskool:
.asciz "oldskool"
.endobj str.oldskool
str.e820: str.e820:
.asciz "e820" .asciz "e820"
.endobj str.e820 .endobj str.e820
str.long: str.oldcpu:
.asciz "nolong" .asciz "oldcpu"
.endobj str.long .endobj str.oldcpu
// Serial Line Configuration (8250 UART 16550) // Serial Line Configuration (8250 UART 16550)
// If it's hacked, it'll at least get hacked very slowly. // If it's hacked, it'll at least get hacked very slowly.
@ -1264,7 +1258,7 @@ longmodeloader:
lcheck: pushf # check for i8086 / i8088 / i80186 lcheck: pushf # check for i8086 / i8088 / i80186
pop %ax pop %ax
test $0x80,%ah # see intel manual volume 1 20.1.2 test $0x80,%ah # see intel manual volume 1 20.1.2
jnz 9f # we now assume 32bit is supported jnz 10f # we now assume 32bit is supported
pushfl # now check for i386 or early i486 pushfl # now check for i386 or early i486
pop %eax # test ability to change cpuid bit pop %eax # test ability to change cpuid bit
mov %eax,%ecx mov %eax,%ecx
@ -1275,7 +1269,7 @@ lcheck: pushf # check for i8086 / i8088 / i80186
pushfl pushfl
pop %eax pop %eax
cmp %eax,%ecx cmp %eax,%ecx
je 12f # we assume cpuid inst is available je 10f # we assume cpuid inst is available
or %ebx,%eax # puts cpuid bit in the on position or %ebx,%eax # puts cpuid bit in the on position
push %eax push %eax
popfl popfl
@ -1293,11 +1287,7 @@ lcheck: pushf # check for i8086 / i8088 / i80186
jne 10f jne 10f
xor %ax,%ax xor %ax,%ax
1: ret 1: ret
9: mov $REAL(str.oldskool),%di 10: mov $REAL(str.oldcpu),%di
jmp 20f
10: mov $REAL(str.long),%di
jmp 20f
12: mov $REAL(str.cpuid),%di
20: call rldie 20: call rldie
.endfn lcheck .endfn lcheck

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -301,6 +301,9 @@ OBJECTIFY.greg.c = \
-fno-instrument-functions \ -fno-instrument-functions \
-fno-optimize-sibling-calls \ -fno-optimize-sibling-calls \
-fno-sanitize=all \ -fno-sanitize=all \
-ffreestanding \
-mno-fentry \
-fwrapv \
-c -c
OBJECTIFY.ansi.c = $(CC) $(OBJECTIFY.c.flags) -ansi -Wextra -Werror -pedantic-errors -c OBJECTIFY.ansi.c = $(CC) $(OBJECTIFY.c.flags) -ansi -Wextra -Werror -pedantic-errors -c

View file

@ -72,7 +72,8 @@ static const float PLM_VIDEO_PIXEL_ASPECT_RATIO[] = {
0.6735, /* 3:4? */ 0.6735, /* 3:4? */
0.7031, /* MPEG-1 / MPEG-2 video encoding divergence? */ 0.7031, /* MPEG-1 / MPEG-2 video encoding divergence? */
0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815,
1.0255, 1.0695, 1.0950, 1.1575, 1.2051}; 1.0255, 1.0695, 1.0950, 1.1575, 1.2051,
};
static const float PLM_VIDEO_PICTURE_RATE[] = { static const float PLM_VIDEO_PICTURE_RATE[] = {
23.976, /* NTSC-Film */ 23.976, /* NTSC-Film */

View file

@ -101,7 +101,7 @@ struct SamplingSolution *ComputeSamplingSolution(long dn, long sn, double dar,
if (!off) off = (dar - 1) / 2; if (!off) off = (dar - 1) / 2;
f = dar < 1 ? 1 / dar : dar; f = dar < 1 ? 1 / dar : dar;
s = 3 * f + 4; s = 3 * f + 4;
fweights = gc(xcalloc(s, sizeof(double))); fweights = gc(xcalloc(s + /*xxx*/ 2, sizeof(double)));
res = NewSamplingSolution(dn, s); res = NewSamplingSolution(dn, s);
weights = res->weights; weights = res->weights;
indices = res->indices; indices = res->indices;

View file

@ -18,9 +18,12 @@
* make -j12 o//examples/auto-launch-gdb-on-crash.com * make -j12 o//examples/auto-launch-gdb-on-crash.com
* o//examples/auto-launch-gdb-on-crash.com * o//examples/auto-launch-gdb-on-crash.com
* *
* Backtrace is logged instead if run outside interactive terminal. * Backtrace is logged instead if run outside interactive terminal. We
* Environmental factors such as GDB, MAKEFLAGS, ADDR2LINE, TERM, and * also don't auto-launch GDB on non-Linux since the development tools
* isatty(STDERR_FILENO) should also be taken into consideration: * on other platforms generally can't be relied upon to correctly debug
* binaries built with a Linux toolchain. Environmental factors such as
* GDB, MAKEFLAGS, ADDR2LINE, TERM, and isatty(STDERR_FILENO) should
* also be taken into consideration:
* *
* $ export GDB=eoatuhshtuone * $ export GDB=eoatuhshtuone
* $ o//examples/auto-launch-gdb-on-crash.com * $ o//examples/auto-launch-gdb-on-crash.com

View file

@ -65,11 +65,26 @@
#define HeaderEqualCase(H, S) \ #define HeaderEqualCase(H, S) \
SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H)) SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
int sock;
static bool TuneSocket(int fd, int a, int b, int x) { static bool TuneSocket(int fd, int a, int b, int x) {
if (!b) return false; if (!b) return false;
return setsockopt(fd, a, b, &x, sizeof(x)) != -1; return setsockopt(fd, a, b, &x, sizeof(x)) != -1;
} }
static void Write(const void *p, size_t n) {
ssize_t rc;
rc = write(1, p, n);
if (rc == -1 && errno == EPIPE) {
close(sock);
exit(128 + SIGPIPE);
}
if (rc != n) {
fprintf(stderr, "write failed: %m\n");
exit(1);
}
}
static int TlsSend(void *c, const unsigned char *p, size_t n) { static int TlsSend(void *c, const unsigned char *p, size_t n) {
int rc; int rc;
NOISEF("begin send %zu", n); NOISEF("begin send %zu", n);
@ -107,7 +122,6 @@ static wontreturn void PrintUsage(FILE *f, int rc) {
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
if (!NoDebug()) showcrashreports(); if (!NoDebug()) showcrashreports();
xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
/* /*
* Read flags. * Read flags.
@ -258,7 +272,7 @@ int main(int argc, char *argv[]) {
/* /*
* Connect to server. * Connect to server.
*/ */
int ret, sock; int ret;
CHECK_NE(-1, (sock = GoodSocket(addr->ai_family, addr->ai_socktype, CHECK_NE(-1, (sock = GoodSocket(addr->ai_family, addr->ai_socktype,
addr->ai_protocol, false, addr->ai_protocol, false,
&(struct timeval){-60}))); &(struct timeval){-60})));
@ -283,6 +297,8 @@ int main(int argc, char *argv[]) {
CHECK_EQ(n, write(sock, request, n)); CHECK_EQ(n, write(sock, request, n));
} }
xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
/* /*
* Handle response. * Handle response.
*/ */
@ -330,7 +346,7 @@ int main(int argc, char *argv[]) {
break; break;
} }
if (method == kHttpHead) { if (method == kHttpHead) {
CHECK_EQ(hdrlen, write(1, p, hdrlen)); Write(p, hdrlen);
goto Finished; goto Finished;
} else if (msg.status == 204 || msg.status == 304) { } else if (msg.status == 204 || msg.status == 304) {
goto Finished; goto Finished;
@ -348,32 +364,32 @@ int main(int argc, char *argv[]) {
t = kHttpClientStateBodyLengthed; t = kHttpClientStateBodyLengthed;
paylen = rc; paylen = rc;
if (paylen > i - hdrlen) { if (paylen > i - hdrlen) {
CHECK_EQ(i - hdrlen, write(1, p + hdrlen, i - hdrlen)); Write(p + hdrlen, i - hdrlen);
} else { } else {
CHECK_EQ(paylen, write(1, p + hdrlen, paylen)); Write(p + hdrlen, paylen);
goto Finished; goto Finished;
} }
} else { } else {
t = kHttpClientStateBody; t = kHttpClientStateBody;
CHECK_EQ(i - hdrlen, write(1, p + hdrlen, i - hdrlen)); Write(p + hdrlen, i - hdrlen);
} }
} }
break; break;
case kHttpClientStateBody: case kHttpClientStateBody:
if (!g) goto Finished; if (!g) goto Finished;
CHECK_EQ(g, write(1, p + i - g, g)); Write(p + i - g, g);
break; break;
case kHttpClientStateBodyLengthed: case kHttpClientStateBodyLengthed:
CHECK(g); CHECK(g);
if (i - hdrlen > paylen) g = hdrlen + paylen - (i - g); if (i - hdrlen > paylen) g = hdrlen + paylen - (i - g);
CHECK_EQ(g, write(1, p + i - g, g)); Write(p + i - g, g);
if (i - hdrlen >= paylen) goto Finished; if (i - hdrlen >= paylen) goto Finished;
break; break;
case kHttpClientStateBodyChunked: case kHttpClientStateBodyChunked:
Chunked: Chunked:
CHECK_NE(-1, (rc = Unchunk(&u, p + hdrlen, i - hdrlen, &paylen))); CHECK_NE(-1, (rc = Unchunk(&u, p + hdrlen, i - hdrlen, &paylen)));
if (rc) { if (rc) {
CHECK_EQ(paylen, write(1, p + hdrlen, paylen)); Write(p + hdrlen, paylen);
goto Finished; goto Finished;
} }
break; break;

63
examples/datauri.c Normal file
View file

@ -0,0 +1,63 @@
#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/log.h"
#include "libc/runtime/gc.internal.h"
#include "libc/stdio/stdio.h"
#include "libc/x/x.h"
#include "net/http/escape.h"
#include "net/http/http.h"
#include "third_party/getopt/getopt.h"
#include "third_party/stb/stb_image.h"
#define USAGE \
" [FLAGS] FILE...\n\
Utility for printing data:base64 URIs.\n\
\n\
FLAGS\n\
\n\
-h Help\n"
void PrintUsage(int rc, FILE *f) {
fputs("Usage: ", f);
fputs(program_invocation_name, f);
fputs(USAGE, f);
exit(rc);
}
void PrintUri(const char *path) {
size_t n;
void *img, *src, *mime;
int opt, i;
if (!(img = gc(xslurp(path, &n)))) exit(2);
fputs("data:", stdout);
fputs(FindContentType(path, -1), stdout);
fputs(";base64,", stdout);
fputs(gc(EncodeBase64(img, n, 0)), stdout);
}
int main(int argc, char *argv[]) {
showcrashreports();
int i;
while ((i = getopt(argc, argv, "?h")) != -1) {
switch (i) {
case '?':
case 'h':
PrintUsage(0, stdout);
default:
PrintUsage(1, stderr);
}
}
if (optind == argc) {
PrintUsage(1, stderr);
}
for (i = optind; i < argc; ++i) {
PrintUri(argv[i]);
}
}

23
examples/forkexec.c Normal file
View file

@ -0,0 +1,23 @@
#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/stdio/stdio.h"
int main(int argc, char *argv[]) {
int pid;
if (argc < 3) {
fputs("USAGE: FORKEXEC.COM PROG ARGV₀ [ARGV₁...]\n", stderr);
return 1;
}
if (!fork()) {
execv(argv[1], argv + 2);
return 127;
}
}

25
examples/forkexecwait.c Normal file
View file

@ -0,0 +1,25 @@
#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/stdio/stdio.h"
int main(int argc, char *argv[]) {
int pid;
volatile void *p;
if (argc < 3) {
fputs("USAGE: FORKEXECWAIT.COM PROG ARGV₀ [ARGV₁...]\n", stderr);
return 1;
}
if (!fork()) {
execv(argv[1], argv + 2);
return 127;
}
wait(0);
}

View file

@ -7,23 +7,97 @@
http://creativecommons.org/publicdomain/zero/1.0/ │ http://creativecommons.org/publicdomain/zero/1.0/ │
*/ */
#endif #endif
#include "libc/log/log.h"
#include "libc/runtime/gc.internal.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/x/x.h" #include "libc/x/x.h"
#include "net/http/escape.h"
#include "net/http/http.h"
#include "third_party/getopt/getopt.h"
#include "third_party/stb/stb_image.h" #include "third_party/stb/stb_image.h"
/** #define USAGE \
* @fileoverview Utility for printing HTML <img> tags. " [FLAGS] IMG...\n\
*/ Utility for printing HTML <img> tags.\n\
\n\
FLAGS\n\
\n\
-h Help\n\
-a Wrap with <a> tag\n\
-u Embed data:base64 URI\n"
int scale;
bool linktag;
bool datauri;
bool sizeonly;
void PrintUsage(int rc, FILE *f) {
fputs("Usage: ", f);
fputs(program_invocation_name, f);
fputs(USAGE, f);
exit(rc);
}
void PrintImg(const char *path) {
size_t n;
int opt, i, yn, xn, cn, w, h;
void *img, *pix, *src, *mime;
if (!(img = gc(xslurp(path, &n)))) exit(2);
if (!(pix = gc(stbi_load_from_memory(img, n, &xn, &yn, &cn, 0)))) exit(3);
if (linktag) {
printf("<a href=\"%s\"\n >", path);
}
src = path;
if (datauri) {
src = xasprintf("data:%s;base64,%s", FindContentType(path, -1),
gc(EncodeBase64(img, n, &n)));
}
w = (xn + (1 << scale) / 2) >> scale;
h = (yn + (1 << scale) / 2) >> scale;
if (sizeonly) {
printf("width=\"%d\" height=\"%d\"", w, h);
} else {
printf("<img width=\"%d\" height=\"%d\" alt=\"[%s]\"\n src=\"%s\">", w,
h, path, src);
}
if (linktag) {
printf("</a>");
}
printf("\n");
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
void *p; showcrashreports();
size_t n; int i;
int yn, xn, cn; while ((i = getopt(argc, argv, "?huas01234")) != -1) {
if (argc != 2) return 1; switch (i) {
if (!(p = xslurp(argv[1], &n))) return 2; case '0':
if (!(p = stbi_load_from_memory(p, n, &xn, &yn, &cn, 0))) return 3; case '1':
printf("<img src=\"%s\" width=\"%d\" height=\"%d\"\n" case '2':
" alt=\"[%s]\">\n", case '3':
argv[1], (xn + 1) >> 1, (yn + 1) >> 1, argv[1]); case '4':
return 0; scale = i - '0';
break;
case 's':
sizeonly = true;
break;
case 'a':
linktag = true;
break;
case 'u':
datauri = true;
break;
case '?':
case 'h':
PrintUsage(0, stdout);
default:
PrintUsage(1, stderr);
}
}
if (optind == argc) {
PrintUsage(1, stderr);
}
for (i = optind; i < argc; ++i) {
PrintImg(argv[i]);
}
} }

View file

@ -1703,7 +1703,7 @@ int PlayGame(const char* romfile, const char* opt_tasfile) {
if ((ffplay = commandvenv("FFPLAY", "ffplay"))) { if ((ffplay = commandvenv("FFPLAY", "ffplay"))) {
devnull = open("/dev/null", O_WRONLY | O_CLOEXEC); devnull = open("/dev/null", O_WRONLY | O_CLOEXEC);
pipe2(pipefds, O_CLOEXEC); pipe2(pipefds, O_CLOEXEC);
if (!(playpid_ = vfork())) { if (!(playpid_ = fork())) {
const char* const args[] = { const char* const args[] = {
"ffplay", "-nodisp", "-loglevel", "quiet", "-fflags", "ffplay", "-nodisp", "-loglevel", "quiet", "-fflags",
"nobuffer", "-ac", "1", "-ar", "1789773", "nobuffer", "-ac", "1", "-ar", "1789773",

View file

@ -8,10 +8,14 @@
*/ */
#endif #endif
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/runtime/gc.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/auxv.h"
@ -22,44 +26,53 @@ const struct AuxiliaryValue {
const char *name; const char *name;
const char *description; const char *description;
} kAuxiliaryValues[] = { } kAuxiliaryValues[] = {
{"%012lx", &AT_EXECFD, "AT_EXECFD", "file descriptor of program"}, {"%-14p", &AT_EXECFD, "AT_EXECFD", "file descriptor of program"},
{"%012lx", &AT_PHDR, "AT_PHDR", "address of elf program headers"}, {"%-14p", &AT_PHDR, "AT_PHDR", "address of elf program headers"},
{"%012lx", &AT_PHENT, "AT_PHENT", "size of program header entry"}, {"%-14p", &AT_PHENT, "AT_PHENT", "size of program header entry"},
{"%012lx", &AT_PHNUM, "AT_PHNUM", "number of program headers"}, {"%-14p", &AT_PHNUM, "AT_PHNUM", "number of program headers"},
{"%012lx", &AT_PAGESZ, "AT_PAGESZ", "system page size"}, {"%-14p", &AT_PAGESZ, "AT_PAGESZ", "system page size"},
{"%012lx", &AT_BASE, "AT_BASE", "base address of the program interpreter"}, {"%-14p", &AT_BASE, "AT_BASE", "base address of the program interpreter"},
{"%012lx", &AT_ENTRY, "AT_ENTRY", "entry address of executable"}, {"%-14p", &AT_ENTRY, "AT_ENTRY", "entry address of executable"},
{"%012lx", &AT_NOTELF, "AT_NOTELF", "set if not an elf"}, {"%-14p", &AT_NOTELF, "AT_NOTELF", "set if not an elf"},
{"%-12d", &AT_UID, "AT_UID", "real user id of thread"}, {"%-14d", &AT_UID, "AT_UID", "real user id of thread"},
{"%-12d", &AT_EUID, "AT_EUID", "effective user id of thread"}, {"%-14d", &AT_EUID, "AT_EUID", "effective user id of thread"},
{"%-12d", &AT_GID, "AT_GID", "real group id of thread"}, {"%-14d", &AT_GID, "AT_GID", "real group id of thread"},
{"%-12d", &AT_EGID, "AT_EGID", "effective group id of thread"}, {"%-14d", &AT_EGID, "AT_EGID", "effective group id of thread"},
{"%-12d", &AT_CLKTCK, "AT_CLKTCK", "frequency of times() counts"}, {"%-14d", &AT_CLKTCK, "AT_CLKTCK", "frequency of times() counts"},
{"%012lx", &AT_OSRELDATE, "AT_OSRELDATE", {"%-14d", &AT_OSRELDATE, "AT_OSRELDATE",
"freebsd release number, e.g. 1200086"}, "freebsd release number, e.g. 1200086"},
{"%012lx", &AT_PLATFORM, "AT_PLATFORM", {"%-14p", &AT_PLATFORM, "AT_PLATFORM",
"string identifying hardware platform"}, "string identifying hardware platform"},
{"%012lx", &AT_DCACHEBSIZE, "AT_DCACHEBSIZE", "data cache block size"}, {"%-14p", &AT_DCACHEBSIZE, "AT_DCACHEBSIZE", "data cache block size"},
{"%012lx", &AT_ICACHEBSIZE, "AT_ICACHEBSIZE", {"%-14p", &AT_ICACHEBSIZE, "AT_ICACHEBSIZE",
"instruction cache block size"}, "instruction cache block size"},
{"%012lx", &AT_UCACHEBSIZE, "AT_UCACHEBSIZE", "unified cache block size"}, {"%-14p", &AT_UCACHEBSIZE, "AT_UCACHEBSIZE", "unified cache block size"},
{"%012lx", &AT_SECURE, "AT_SECURE", {"%-14p", &AT_SECURE, "AT_SECURE",
"for set{u,g}id binz & security blankets"}, "for set{u,g}id binz & security blankets"},
{"%-12s", &AT_BASE_PLATFORM, "AT_BASE_PLATFORM", {"%-14s", &AT_BASE_PLATFORM, "AT_BASE_PLATFORM",
"string identifying real platform"}, "string identifying real platform"},
{"%012lx", &AT_RANDOM, "AT_RANDOM", "address of sixteen random bytes"}, {"%-14p", &AT_RANDOM, "AT_RANDOM", "address of sixteen random bytes"},
{"%-12s", &AT_EXECFN, "AT_EXECFN", "pathname used to execute program"}, {"%-14s (%p)", &AT_EXECFN, "AT_EXECFN", "pathname used to execute program"},
{"%012lx", &AT_SYSINFO_EHDR, "AT_SYSINFO_EHDR", {"%-14p", &AT_SYSINFO_EHDR, "AT_SYSINFO_EHDR",
"linux virtual dso page address"}, "linux virtual dso page address"},
{"%012lx", &AT_FLAGS, "AT_FLAGS", "unused?"}, {"%-14p", &AT_FLAGS, "AT_FLAGS", "unused?"},
{"%012lx", &AT_HWCAP, "AT_HWCAP", "cpu stuff"}, {"%-14p", &AT_HWCAP, "AT_HWCAP", "cpu stuff"},
{"%012lx", &AT_HWCAP2, "AT_HWCAP2", "more cpu stuff"}, {"%-14p", &AT_HWCAP2, "AT_HWCAP2", "more cpu stuff"},
{"%-14p", &AT_STACKBASE, "AT_STACKBASE", "NetBSD stack base"},
{"%-14p", &AT_CANARY, "AT_CANARY", "FreeBSD AT_CANARY"},
{"%-14p", &AT_CANARYLEN, "AT_CANARYLEN", "FreeBSD AT_CANARYLEN"},
{"%-14ld", &AT_NCPUS, "AT_NCPUS", "FreeBSD AT_NCPUS"},
{"%-14p", &AT_PAGESIZES, "AT_PAGESIZES", "FreeBSD AT_PAGESIZES"},
{"%-14d", &AT_PAGESIZESLEN, "AT_PAGESIZESLEN", "FreeBSD AT_PAGESIZESLEN"},
{"%-14p", &AT_TIMEKEEP, "AT_TIMEKEEP", "FreeBSD AT_TIMEKEEP"},
{"%-14p", &AT_STACKPROT, "AT_STACKPROT", "FreeBSD AT_STACKPROT"},
{"%-14p", &AT_EHDRFLAGS, "AT_EHDRFLAGS", "FreeBSD AT_EHDRFLAGS"},
}; };
const struct AuxiliaryValue *DescribeAuxv(unsigned long x) { const struct AuxiliaryValue *DescribeAuxv(unsigned long x) {
int i; int i;
for (i = 0; i < ARRAYLEN(kAuxiliaryValues); ++i) { for (i = 0; i < ARRAYLEN(kAuxiliaryValues); ++i) {
if (x == *kAuxiliaryValues[i].id) { if (*kAuxiliaryValues[i].id && x == *kAuxiliaryValues[i].id) {
return kAuxiliaryValues + i; return kAuxiliaryValues + i;
} }
} }
@ -68,33 +81,41 @@ const struct AuxiliaryValue *DescribeAuxv(unsigned long x) {
int main(int argc, char *argv[], char **envp) { int main(int argc, char *argv[], char **envp) {
long key; long key;
char **env;
unsigned i; unsigned i;
unsigned long *auxp; unsigned long *auxp;
char fmt[64], **env;
struct AuxiliaryValue *auxinfo; struct AuxiliaryValue *auxinfo;
uint32_t varlen; uint32_t varlen;
char16_t var[PATH_MAX]; char16_t var[PATH_MAX];
printf("\nArguments:\n"); kprintf("%nArguments:%n");
for (i = 0; i < __argc; ++i) { for (i = 0; i < __argc; ++i) {
printf(" ☼ %s\n", argv[i]); kprintf(" ☼ %s%n", argv[i]);
} }
printf("\nEnvironment:\n"); kprintf("%nEnvironment:%n");
for (env = envp; *env; ++env) { for (env = envp; *env; ++env) {
printf(" ☼ %s\n", *env); kprintf(" ☼ %s%n", *env);
} }
printf("\nAuxiliary Values:\n"); kprintf("%nAuxiliary Values:%n");
for (auxp = __auxv; *auxp; auxp += 2) { for (auxp = __auxv; *auxp; auxp += 2) {
if ((auxinfo = DescribeAuxv(auxp[0]))) { if ((auxinfo = DescribeAuxv(auxp[0]))) {
stpcpy(stpcpy(stpcpy(fmt, "%16s[%4ld] = "), auxinfo->fmt), " # %s\n"); kprintf(" ☼ %16s[%4ld] = ", auxinfo->name, auxp[0]);
printf(fmt, auxinfo->name, auxp[0], auxp[1], auxinfo->description); kprintf(auxinfo->fmt, auxp[1], auxp[1]);
kprintf(" # %s%n", auxinfo->description);
} else { } else {
printf("%16s[%4ld] = %012lx\n", "unknown", auxp[0], auxp[1]); kprintf(" ☼ %16s[%4ld] = %014p%n", "unknown", auxp[0], auxp[1]);
} }
} }
printf("\nSpecial Directories:\n"); kprintf("%nSpecial Parameters:%n");
printf(" ☼ kTmpPath = %`'s\n", kTmpPath); kprintf(" ☼ kTmpPath = %#s%n", kTmpPath);
printf(" ☼ kNtSystemDirectory = %`'s\n", kNtSystemDirectory); kprintf(" ☼ kNtSystemDirectory = %#s%n", kNtSystemDirectory);
printf(" ☼ kNtWindowsDirectory = %`'s\n", kNtWindowsDirectory); kprintf(" ☼ kNtWindowsDirectory = %#s%n", kNtWindowsDirectory);
printf(" ☼ program_executable_name = %`'s\n", program_executable_name); kprintf(" ☼ program_executable_name = %#s (%p)%n", program_executable_name,
program_executable_name);
kprintf(" ☼ GetInterpreterExecutableName() → %#s%n",
GetInterpreterExecutableName(_gc(malloc(1024)), 1024));
kprintf(" ☼ RSP → %p%n", __builtin_frame_address(0));
kprintf(" ☼ GetStackAddr() → %p%n", GetStackAddr(0));
kprintf(" ☼ GetStaticStackAddr() → %p%n", GetStaticStackAddr(0));
kprintf(" ☼ GetStackSize() → %p%n", GetStackSize());
return 0; return 0;
} }

View file

@ -101,7 +101,7 @@ int main(int argc, char *argv[]) {
sigaddset(&chldmask, SIGCHLD); sigaddset(&chldmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &chldmask, &savemask); sigprocmask(SIG_BLOCK, &chldmask, &savemask);
ts1 = nowl(); ts1 = nowl();
CHECK_NE(-1, (pid = vfork())); CHECK_NE(-1, (pid = fork()));
if (!pid) { if (!pid) {
sigaction(SIGINT, &dflt, 0); sigaction(SIGINT, &dflt, 0);
sigaction(SIGQUIT, &dflt, 0); sigaction(SIGQUIT, &dflt, 0);

View file

@ -27,6 +27,7 @@
#include "libc/x/x.h" #include "libc/x/x.h"
#define CTRL(C) ((C) ^ 0b01000000) #define CTRL(C) ((C) ^ 0b01000000)
#define WRITE(FD, SLIT) write(FD, SLIT, strlen(SLIT))
#define ENABLE_SAFE_PASTE "\e[?2004h" #define ENABLE_SAFE_PASTE "\e[?2004h"
#define ENABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006h" #define ENABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006h"
#define DISABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006l" #define DISABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006l"
@ -46,7 +47,7 @@ void onkilled(int sig) {
} }
void restoretty(void) { void restoretty(void) {
write(1, DISABLE_MOUSE_TRACKING, strlen(DISABLE_MOUSE_TRACKING)); WRITE(1, DISABLE_MOUSE_TRACKING);
ioctl(1, TCSETS, &oldterm); ioctl(1, TCSETS, &oldterm);
} }
@ -72,9 +73,9 @@ int rawmode(void) {
t.c_cflag |= CS8; t.c_cflag |= CS8;
t.c_iflag |= IUTF8; t.c_iflag |= IUTF8;
ioctl(1, TCSETS, &t); ioctl(1, TCSETS, &t);
write(1, ENABLE_SAFE_PASTE, strlen(ENABLE_SAFE_PASTE)); WRITE(1, ENABLE_SAFE_PASTE);
write(1, ENABLE_MOUSE_TRACKING, strlen(ENABLE_MOUSE_TRACKING)); WRITE(1, ENABLE_MOUSE_TRACKING);
write(1, PROBE_DISPLAY_SIZE, strlen(PROBE_DISPLAY_SIZE)); WRITE(1, PROBE_DISPLAY_SIZE);
return 0; return 0;
} }

View file

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

View file

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

View file

@ -40,13 +40,18 @@
* @asyncsignalsafe * @asyncsignalsafe
*/ */
int clock_gettime(int clockid, struct timespec *ts) { int clock_gettime(int clockid, struct timespec *ts) {
int rc; int rc, e;
axdx_t ad; axdx_t ad;
if (!ts) return efault(); if (!ts) {
if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) return efault(); rc = efault();
if (clockid == -1) return einval(); } else if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) {
if (!IsWindows()) { rc = efault();
if ((rc = sys_clock_gettime(clockid, ts)) == -1 && errno == ENOSYS) { } 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); ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL);
assert(ad.ax != -1); assert(ad.ax != -1);
if (SupportsXnu() && ad.ax) { if (SupportsXnu() && ad.ax) {
@ -56,8 +61,9 @@ int clock_gettime(int clockid, struct timespec *ts) {
ts->tv_nsec *= 1000; ts->tv_nsec *= 1000;
rc = 0; rc = 0;
} }
return rc;
} else { } 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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.internal.h" #include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.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/log/libfatal.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static noasan bool EndsWithIgnoreCase(const char *p, size_t n, const char *s) { static noasan bool IsExePath(const char *s, size_t n) {
size_t i, m; return n >= 4 && (READ32LE(s + n - 4) == READ32LE(".exe") ||
m = __strlen(s); READ32LE(s + n - 4) == READ32LE(".EXE"));
if (n >= m) {
for (i = n - m; i < n; ++i) {
if (kToLower[p[i] & 255] != (*s++ & 255)) {
return false;
} }
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"));
} }
return true;
} else { static noasan bool IsComDbgPath(const char *s, size_t n) {
return false; return n >= 8 && (READ64LE(s + n - 8) == READ64LE(".com.dbg") ||
} READ64LE(s + n - 8) == READ64LE(".COM.DBG"));
} }
static noasan bool AccessCommand(const char *name, static noasan bool AccessCommand(const char *name,
char path[hasatleast PATH_MAX], size_t namelen, 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; size_t suffixlen;
suffixlen = __strlen(suffix); suffixlen = strlen(suffix);
if (pathlen + 1 + namelen + suffixlen + 1 > PATH_MAX) return -1; if (pathlen + 1 + namelen + suffixlen + 1 > PATH_MAX) return false;
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) { if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) {
path[pathlen] = !IsWindows() ? '/' path[pathlen] = !IsWindows() ? '/'
: __memchr(path, '\\', pathlen) ? '\\' : memchr(path, '\\', pathlen) ? '\\'
: '/'; : '/';
pathlen++; pathlen++;
} }
__repmovsb(path + pathlen, name, namelen); memcpy(path + pathlen, name, namelen);
__repmovsb(path + pathlen + namelen, suffix, suffixlen + 1); memcpy(path + pathlen + namelen, suffix, suffixlen + 1);
return isexecutable(path); 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], 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; size_t i;
const char *p; 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 (;;) {
for (i = 0; p[i] && p[i] != ':' && p[i] != ';'; ++i) { for (i = 0; p[i] && p[i] != sep; ++i) {
if (i < PATH_MAX) { if (i < PATH_MAX) {
path[i] = p[i]; path[i] = p[i];
} }
} }
if (AccessCommand(name, path, namelen, suffix, i)) { if (AccessCommand(name, path, namelen, err, suffix, i)) {
return true; return true;
} }
if (p[i] == ':' || p[i] == ';') { if (p[i] == sep) {
p += i + 1; p += i + 1;
} else { } else {
break; break;
@ -80,19 +89,37 @@ static noasan bool SearchPath(const char *name, char path[hasatleast PATH_MAX],
static noasan bool FindCommand(const char *name, static noasan bool FindCommand(const char *name,
char pathbuf[hasatleast PATH_MAX], char pathbuf[hasatleast PATH_MAX],
size_t namelen, const char *suffix) { size_t namelen, bool priorityonly,
if (memchr(name, '/', namelen) || memchr(name, '\\', namelen)) { const char *suffix, int *err) {
if (priorityonly &&
(memchr(name, '/', namelen) || memchr(name, '\\', namelen))) {
pathbuf[0] = 0; pathbuf[0] = 0;
return AccessCommand(name, pathbuf, namelen, suffix, 0); return AccessCommand(name, pathbuf, namelen, err, suffix, 0);
} }
return ((IsWindows() && if (IsWindows() && priorityonly) {
(AccessCommand(name, pathbuf, namelen, suffix, return AccessCommand(name, pathbuf, namelen, err, suffix,
stpcpy(pathbuf, kNtSystemDirectory) - pathbuf) || stpcpy(pathbuf, kNtSystemDirectory) - pathbuf) ||
AccessCommand(name, pathbuf, namelen, suffix, AccessCommand(name, pathbuf, namelen, err, suffix,
stpcpy(pathbuf, kNtWindowsDirectory) - pathbuf) || stpcpy(pathbuf, kNtWindowsDirectory) - pathbuf);
AccessCommand(name, pathbuf, namelen, suffix, }
stpcpy(pathbuf, ".") - pathbuf))) || return (IsWindows() && AccessCommand(name, pathbuf, namelen, err, suffix,
SearchPath(name, pathbuf, namelen, 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 * @vforksafe
*/ */
noasan char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) { noasan char *commandv(const char *name, char pathbuf[hasatleast PATH_MAX]) {
int olderr; int e, f;
char *res;
size_t namelen; size_t namelen;
res = 0;
if (!name) { if (!name) {
efault(); efault();
return 0; } else if (!(namelen = strlen(name))) {
}
if (!(namelen = __strlen(name))) {
enoent(); enoent();
return 0; } else if (namelen + 1 > PATH_MAX) {
}
if (namelen + 1 > PATH_MAX) {
enametoolong(); 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 { } 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/internal.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/kprintf.h"
#include "libc/nt/createfile.h" #include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.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; int64_t inoffset, outoffset;
int rc, srcfd, dstfd, oflags, omode; int rc, srcfd, dstfd, oflags, omode;
rc = -1; rc = -1;
if ((srcfd = sys_openat(AT_FDCWD, src, O_RDONLY, 0)) != -1) { if ((srcfd = openat(AT_FDCWD, src, O_RDONLY, 0)) != -1) {
if (sys_fstat(srcfd, &st) != -1) { if (fstat(srcfd, &st) != -1) {
omode = st.st_mode & 0777; omode = st.st_mode & 0777;
oflags = O_WRONLY | O_CREAT; oflags = O_WRONLY | O_CREAT;
if (flags & COPYFILE_NOCLOBBER) oflags |= O_EXCL; 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; remaining = st.st_size;
ftruncate(dstfd, remaining); ftruncate(dstfd, remaining);
inoffset = 0; inoffset = 0;
@ -86,13 +87,13 @@ static int sys_copyfile(const char *src, const char *dst, int flags) {
if (flags & COPYFILE_PRESERVE_TIMESTAMPS) { if (flags & COPYFILE_PRESERVE_TIMESTAMPS) {
amtime[0] = st.st_atim; amtime[0] = st.st_atim;
amtime[1] = st.st_mtim; 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; 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 * @return 0 on success, or -1 w/ errno
*/ */
int copyfile(const char *src, const char *dst, int flags) { 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); return sys_copyfile(src, dst, flags);
} else { } else {
return sys_copyfile_nt(src, dst, flags); return sys_copyfile_nt(src, dst, flags);

View file

@ -21,6 +21,7 @@
#include "libc/calls/sysdebug.internal.h" #include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -47,17 +48,17 @@ int execve(const char *program, char *const argv[], char *const envp[]) {
return efault(); return efault();
} }
if (DEBUGSYS) { if (DEBUGSYS) {
__printf("SYS: execve(%s, {", program); kprintf("SYS: execve(%s, {", program);
for (i = 0; argv[i]; ++i) { for (i = 0; argv[i]; ++i) {
if (i) __printf(", "); if (i) kprintf(", ");
__printf("%s", argv[i]); kprintf("%s", argv[i]);
} }
__printf("}, {"); kprintf("}, {");
for (i = 0; envp[i]; ++i) { for (i = 0; envp[i]; ++i) {
if (i) __printf(", "); if (i) kprintf(", ");
__printf("%s", envp[i]); kprintf("%s", envp[i]);
} }
__printf("})\n"); kprintf("})\n");
} }
for (i = 3; i < g_fds.n; ++i) { for (i = 3; i < g_fds.n; ++i) {
if (g_fds.p[i].kind != kFdEmpty && (g_fds.p[i].flags & O_CLOEXEC)) { 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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/nt/process.h"
#include "libc/runtime/runtime.h"
static int __pid; extern int __pid;
static int __getpid(void) {
if (!IsWindows()) {
return sys_getpid().ax;
} else {
return GetCurrentProcessId();
}
}
static void __updatepid(void) {
__pid = __getpid();
}
/** /**
* Returns process id. * Returns process id.
@ -44,15 +27,11 @@ static void __updatepid(void) {
* @vforksafe * @vforksafe
*/ */
int getpid(void) { int getpid(void) {
static bool once; int rc;
if (__vforked) { if (!__vforked) {
return sys_getpid().ax; rc = __pid;
} else {
rc = sys_getpid().ax;
} }
if (!once) { return rc;
__updatepid();
if (cmpxchg(&once, false, true)) {
atfork(__updatepid, NULL);
}
}
return __pid;
} }

View file

@ -12,6 +12,7 @@
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timespec.h" #include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h" #include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/winsize.h"
#include "libc/calls/ucontext.h" #include "libc/calls/ucontext.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/limits.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_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_readlinkat_nt(int, const char *, char *, size_t) hidden;
ssize_t sys_write_nt(struct Fd *, const struct iovec *, size_t, ssize_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 cosmopolitan § syscalls » windows nt » support

View file

@ -25,6 +25,8 @@
#include "libc/sysv/consts/termios.h" #include "libc/sysv/consts/termios.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
extern bool __nomultics;
int ioctl_tcsets_nt(int, uint64_t, const struct termios *); int ioctl_tcsets_nt(int, uint64_t, const struct termios *);
static int ioctl_tcsets_metal(int fd, uint64_t request, 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, static inline void *__termios2host(union metatermios *mt,
const struct termios *lt) { const struct termios *lt) {
if (!IsXnu() && !IsFreebsd() && !IsOpenbsd() && !IsNetbsd()) { if (!IsXnu() && !IsFreebsd() && !IsOpenbsd() && !IsNetbsd()) {
return lt; return (/*unconst*/ void *)lt;
} else if (IsXnu()) { } else if (IsXnu()) {
COPY_TERMIOS(&mt->xnu, lt); COPY_TERMIOS(&mt->xnu, lt);
return &mt->xnu; 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 * @see ioctl(fd, TIOCGETA{,W,F}, tio) dispatches here
*/ */
int ioctl_tcsets(int fd, uint64_t request, ...) { int ioctl_tcsets(int fd, uint64_t request, ...) {
int rc;
va_list va; va_list va;
const struct termios *tio; const struct termios *tio;
va_start(va, request); va_start(va, request);
tio = va_arg(va, const struct termios *); tio = va_arg(va, const struct termios *);
va_end(va); va_end(va);
if (!tio) return efault(); if (!tio) {
if (fd >= 0) { rc = efault();
} else if (fd >= 0) {
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) { if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
return enotty(); rc = enotty();
} else if (IsMetal()) { } else if (IsMetal()) {
return ioctl_tcsets_metal(fd, request, tio); rc = ioctl_tcsets_metal(fd, request, tio);
} else if (!IsWindows()) { } else if (!IsWindows()) {
return ioctl_tcsets_sysv(fd, request, tio); rc = ioctl_tcsets_sysv(fd, request, tio);
} else { } else {
return ioctl_tcsets_nt(fd, request, tio); rc = ioctl_tcsets_nt(fd, request, tio);
} }
} else { } 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/str/str.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
textwindows int ioctl_tiocgwinsz_nt(int fd, struct winsize *ws) { textwindows int ioctl_tiocgwinsz_nt(struct Fd *fd, struct winsize *ws) {
int i, fds[3]; int i;
uint32_t mode; uint32_t mode;
struct Fd *fds[3];
struct NtStartupInfo startinfo; struct NtStartupInfo startinfo;
struct NtConsoleScreenBufferInfoEx sbinfo; struct NtConsoleScreenBufferInfoEx sbinfo;
if (!ws) return efault(); 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); GetStartupInfo(&startinfo);
for (i = 0; i < ARRAYLEN(fds); ++i) { for (i = 0; i < ARRAYLEN(fds); ++i) {
if (__isfdkind(fds[i], kFdFile) || __isfdkind(fds[i], kFdConsole)) { if (fds[i]->kind == kFdFile || fds[i]->kind == kFdConsole) {
if (GetConsoleMode(g_fds.p[fds[i]].handle, &mode)) { if (GetConsoleMode(fds[i]->handle, &mode)) {
bzero(&sbinfo, sizeof(sbinfo)); bzero(&sbinfo, sizeof(sbinfo));
sbinfo.cbSize = 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_col = sbinfo.srWindow.Right - sbinfo.srWindow.Left + 1;
ws->ws_row = sbinfo.srWindow.Bottom - sbinfo.srWindow.Top + 1; ws->ws_row = sbinfo.srWindow.Bottom - sbinfo.srWindow.Top + 1;
ws->ws_xpixel = 0; ws->ws_xpixel = 0;

View file

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

View file

@ -25,8 +25,6 @@
#include "libc/nt/thunk/msabi.h" #include "libc/nt/thunk/msabi.h"
#include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/nr.h"
extern __msabi typeof(VirtualProtect) *const __imp_VirtualProtect;
/** /**
* Modifies restrictions on virtual memory address range. * 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 -*-│ /*-*- 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 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 Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the 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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#define ShouldUseMsabiAttribute() 1
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/nexgen32e/nexgen32e.h" #include "libc/errno.h"
#include "libc/nt/enum/status.h" #include "libc/macros.internal.h"
#include "libc/nt/errors.h" #include "libc/nt/errors.h"
#include "libc/nt/nt/time.h" #include "libc/nt/nt/time.h"
#include "libc/nt/synchronization.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, textwindows noinstrument int sys_nanosleep_nt(const struct timespec *req,
struct timespec *rem) { struct timespec *rem) {
/* no function tracing because timing sensitive */
int64_t millis, hectonanos, relasleep; int64_t millis, hectonanos, relasleep;
if (rem) memcpy(rem, req, sizeof(*rem)); 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); hectonanos = MAX(1, hectonanos);
relasleep = -hectonanos; relasleep = -hectonanos;
if (NtError(NtDelayExecution(true, &relasleep))) { if (NtError(__imp_NtDelayExecution(true, &relasleep))) {
millis = div10000int64(hectonanos); millis = hectonanos / 10000;
millis = MAX(1, millis); millis = MAX(1, millis);
if (SleepEx(millis, true) == kNtWaitIoCompletion) { if (__imp_SleepEx(millis, true) == kNtWaitIoCompletion) {
return eintr(); errno = EINTR;
return -1;
} }
} }
if (rem) bzero(rem, sizeof(*rem)); if (rem) {
rem->tv_sec = 0;
rem->tv_nsec = 0;
}
return 0; return 0;
} }

View file

@ -84,7 +84,7 @@ textwindows int ntspawn(
(block = (block =
MapViewOfFileExNuma(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0, MapViewOfFileExNuma(handle, kNtFileMapRead | kNtFileMapWrite, 0, 0,
blocksize, NULL, kNtNumaNoPreferredNode))) { blocksize, NULL, kNtNumaNoPreferredNode))) {
if (mkntcmdline(block->cmdline, prog, argv) != -1 && if (mkntcmdline(block->cmdline, prog, argv + 1) != -1 &&
mkntenvblock(block->envvars, envp, extravar) != -1) { mkntenvblock(block->envvars, envp, extravar) != -1) {
if (CreateProcess(prog16, block->cmdline, opt_lpProcessAttributes, if (CreateProcess(prog16, block->cmdline, opt_lpProcessAttributes,
opt_lpThreadAttributes, bInheritHandles, 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. * NT, XNU, and 2007-era Linux don't support this system call.
*/ */
if (!once) { if (!__vforked && !once) {
err = errno; err = errno;
rc = sys_preadv(fd, iov, iovlen, off, off); rc = sys_preadv(fd, iov, iovlen, off, off);
if (rc == -1 && errno == ENOSYS) { if (rc == -1 && errno == ENOSYS) {

View file

@ -22,6 +22,7 @@
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h" #include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h"
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/alloca.h" #include "libc/mem/alloca.h"
@ -45,8 +46,17 @@
* Absolute path of executable. * Absolute path of executable.
* *
* This variable is initialized automatically at startup. The path is * This variable is initialized automatically at startup. The path is
* guaranteed to exist, except on XNU and OpenBSD. It may be a symlink. * basically `argv[0]` except some extra vetting is done to provide
* It may be spoofed. * 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]; char program_executable_name[SIZE];
@ -75,59 +85,47 @@ static textwindows bool GetNtExePath(char executable[SIZE]) {
} }
static textstartup void GetProgramExecutableName(char executable[SIZE], static textstartup void GetProgramExecutableName(char executable[SIZE],
char *p) { char *argv0, intptr_t *auxv) {
char *t;
size_t m; size_t m;
ssize_t n;
int cmd[4]; int cmd[4];
ssize_t n = 0; char *p, *t;
if (IsWindows() && GetNtExePath(executable)) return; 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 (!_isabspath(p)) {
if (getcwd(executable, SIZE - 1)) { if (getcwd(executable, SIZE - 1)) {
n = strlen(executable); n = strlen(executable);
executable[n++] = '/'; 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) { for (; *p; ++p) {
if (n + 1 < SIZE) { if (n + 1 < SIZE) {
executable[n++] = *p; executable[n++] = *p;
} }
} }
}
executable[n] = 0; executable[n] = 0;
} }
textstartup void program_executable_name_init(int argc, char **argv, textstartup void program_executable_name_init(int argc, char **argv,
char **envp, intptr_t *auxv) { char **envp, intptr_t *auxv) {
int e;
static bool once; static bool once;
char executable[SIZE]; char executable[SIZE];
if (!cmpxchg(&once, 0, 1)) return; if (!cmpxchg(&once, 0, 1)) return;
__stpcpy(program_executable_name, argv[0]); e = errno;
GetProgramExecutableName(executable, argv[0]); GetProgramExecutableName(executable, argv[0], auxv);
errno = e;
__stpcpy(program_executable_name, executable); __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 = { const void *const program_executable_name_init_ctor[] initarray = {

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/errno.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; ssize_t rc;
uint32_t size; uint32_t size;
size_t i, total; size_t i, total;
if (weaken(_check_sigwinch) && weaken(_check_sigwinch)(fd)) return eintr();
while (iovlen && !iov[0].iov_len) iov++, iovlen--; while (iovlen && !iov[0].iov_len) iov++, iovlen--;
if (iovlen) { if (iovlen) {
for (total = i = 0; i < iovlen; ++i) { 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) { 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) { if ((i = GetFirstIov(iov, iovlen)) != -1) {
while (!IsDataAvailable(fd)) asm("pause"); while (!IsDataAvailable(fd)) asm("pause");
i = 0; ((char *)iov[i].iov_base)[0] = inb(fd->handle);
j = 0; return 1;
do { } else {
++got; return 0;
((char *)iov[i].iov_base)[j] = inb(fd->handle);
if (++j == iov[i].iov_len) {
j = 0;
if (++i == iovlen) {
break;
} }
} }
} while (IsDataAvailable(fd));
}
return got;
}

View file

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

View file

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

View file

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

View file

@ -28,12 +28,21 @@
// @note FreeBSD is special (see freebsd/lib/csu/amd64/...) // @note FreeBSD is special (see freebsd/lib/csu/amd64/...)
// @noreturn // @noreturn
_start: _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() #if SupportsFreebsd()
test %rdi,%rdi test %rdi,%rdi
cmovnz %rdi,%rsp cmovnz %rdi,%rsp
jz 0f jz 0f
movb $FREEBSD,__hostos(%rip) movb $FREEBSD,__hostos(%rip)
#endif #endif
0: mov (%rsp),%ebx # argc 0: mov (%rsp),%ebx # argc
lea 8(%rsp),%rsi # argv lea 8(%rsp),%rsi # argv
lea 16(%rsp,%rbx,8),%rdx # envp lea 16(%rsp,%rbx,8),%rdx # envp

View file

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

View file

@ -24,6 +24,7 @@ char *GetElfStringTable(const Elf64_Ehdr *elf, size_t mapsize) {
char *name; char *name;
Elf64_Half i; Elf64_Half i;
Elf64_Shdr *shdr; Elf64_Shdr *shdr;
if (elf->e_shentsize) {
for (i = 0; i < elf->e_shnum; ++i) { for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, mapsize, i); shdr = GetElfSectionHeaderAddress(elf, mapsize, i);
if (shdr->sh_type == SHT_STRTAB) { if (shdr->sh_type == SHT_STRTAB) {
@ -34,5 +35,6 @@ char *GetElfStringTable(const Elf64_Ehdr *elf, size_t mapsize) {
} }
} }
} }
}
return NULL; return NULL;
} }

View file

@ -23,6 +23,7 @@ Elf64_Sym *GetElfSymbolTable(const Elf64_Ehdr *elf, size_t mapsize,
Elf64_Xword *out_count) { Elf64_Xword *out_count) {
Elf64_Half i; Elf64_Half i;
Elf64_Shdr *shdr; Elf64_Shdr *shdr;
if (elf->e_shentsize) {
for (i = elf->e_shnum; i > 0; --i) { for (i = elf->e_shnum; i > 0; --i) {
shdr = GetElfSectionHeaderAddress(elf, mapsize, i - 1); shdr = GetElfSectionHeaderAddress(elf, mapsize, i - 1);
if (shdr->sh_type == SHT_SYMTAB) { if (shdr->sh_type == SHT_SYMTAB) {
@ -31,5 +32,6 @@ Elf64_Sym *GetElfSymbolTable(const Elf64_Ehdr *elf, size_t mapsize,
return GetElfSectionAddress(elf, mapsize, shdr); return GetElfSectionAddress(elf, mapsize, shdr);
} }
} }
}
return NULL; 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 *, int vcscanf(int (*)(void *), int (*)(int, void *), void *, const char *,
va_list); va_list);
int strerror_r(int, char *, size_t) nothrow nocallback; 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; int __fmt(void *, void *, const char *, va_list) hidden;
char *itoa(int, char *, int) compatfn; char *itoa(int, char *, int) compatfn;
char *fcvt(double, int, int *, int *); char *fcvt(double, int, int *, int *);

View file

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

View file

@ -29,155 +29,90 @@
.section .rodata .section .rodata
.align 4 .align 4
kErrorNamesLong: kErrorNamesLong:
.e EPIPE,"EPIPE[Broken pipe]" .e EINVAL,"Invalid argument"
.e ENODEV,"ENODEV[No such device]" .e ENOSYS,"Function not implemented"
.e EINVAL,"EINVAL[Invalid argument]" .e EPERM,"Operation not permitted"
.e EINTR,"EINTR[Interrupted system call]" .e ENOENT,"No such file or directory"
.e ENOTBLK,"ENOTBLK[Block device required]" .e ESRCH,"No such process"
.e ENOSYS,"ENOSYS[Function not implemented]" .e EINTR,"Interrupted system call"
.e EHOSTUNREACH,"EHOSTUNREACH[No route to host]" .e EIO,"I/O error"
.e ESRCH,"ESRCH[No such process]" .e ENXIO,"No such device or address"
.e EUSERS,"EUSERS[Too many users]" .e E2BIG,"Arg list too long"
.e EXDEV,"EXDEV[Cross-device link]" .e ENOEXEC,"Exec format error"
.e E2BIG,"E2BIG[Arg list too long]" .e EBADF,"Bad file number"
.e EREMOTE,"EREMOTE[Object is remote]" .e ECHILD,"No child processes"
.e ECHILD,"ECHILD[No child processes]" .e EAGAIN,"Try again"
.e EMSGSIZE,"EMSGSIZE[Message too long]" .e ENOMEM,"Out of memory"
.e ENOTEMPTY,"ENOTEMPTY[Directory not empty]" .e EACCES,"Permission denied"
.e ENOBUFS,"ENOBUFS[No buffer space available]" .e EFAULT,"Bad address"
.e ELOOP,"ELOOP[Too many symbolic links encountered]" .e ENOTBLK,"Block device required"
.e EAFNOSUPPORT,"EAFNOSUPPORT[Address family not supported by protocol]" .e EBUSY,"Device or resource busy"
.e EHOSTDOWN,"EHOSTDOWN[Host is down]" .e EEXIST,"File exists"
.e EPFNOSUPPORT,"EPFNOSUPPORT[Protocol family not supported]" .e EXDEV,"Cross-device link"
.e ENOPROTOOPT,"ENOPROTOOPT[Protocol not available]" .e ENODEV,"No such device"
.e EBUSY,"EBUSY[Device or resource busy]" .e ENOTDIR,"Not a directory"
.e EWOULDBLOCK,"EWOULDBLOCK[Operation would block]" .e EISDIR,"Is a directory"
.e EBADFD,"EBADFD[File descriptor in bad state]" .e ENFILE,"File table overflow"
.e EISCONN,"EISCONN[Transport endpoint is already connected]" .e EMFILE,"Too many open files"
.e ESHUTDOWN,"ESHUTDOWN[Cannot send after transport endpoint shutdown]" .e ENOTTY,"Not a typewriter"
.e ENONET,"ENONET[Machine is not on the network]" .e ETXTBSY,"Text file busy"
.e EBADE,"EBADE[Invalid exchange]" .e EFBIG,"File too large"
.e EBADF,"EBADF[Bad file number]" .e ENOSPC,"No space left on device"
.e EMULTIHOP,"EMULTIHOP[Multihop attempted]" .e EDQUOT,"Quota exceeded"
.e EIO,"EIO[I/O error]" .e ESPIPE,"Illegal seek"
.e EUNATCH,"EUNATCH[Protocol driver not attached]" .e EROFS,"Read-only file system"
.e EPROTOTYPE,"EPROTOTYPE[Protocol wrong type for socket]" .e EMLINK,"Too many links"
.e ENOSPC,"ENOSPC[No space left on device]" .e EPIPE,"Broken pipe"
.e ENOEXEC,"ENOEXEC[Exec format error]" .e EDOM,"Math argument out of domain of func"
.e EALREADY,"EALREADY[Operation already in progress]" .e ERANGE,"Math result not representable"
.e ENETDOWN,"ENETDOWN[Network is down]" .e EDEADLK,"Resource deadlock would occur"
.e ENOTNAM,"ENOTNAM[Not a XENIX named type file]" .e ENAMETOOLONG,"File name too long"
.e EACCES,"EACCES[Permission denied]" .e ENOLCK,"No record locks available"
.e ELNRNG,"ELNRNG[Link number out of range]" .e ENOTEMPTY,"Directory not empty"
.e EILSEQ,"EILSEQ[Illegal byte sequence]" .e ELOOP,"Too many symbolic links encountered"
.e ENOTDIR,"ENOTDIR[Not a directory]" .e ENOMSG,"No message of desired type"
.e ENOTUNIQ,"ENOTUNIQ[Name not unique on network]" .e EIDRM,"Identifier removed"
.e EPERM,"EPERM[Operation not permitted]" .e ETIME,"Timer expired"
.e EDOM,"EDOM[Math argument out of domain of func]" .e EPROTO,"Protocol error"
.e EXFULL,"EXFULL[Exchange full]" .e EOVERFLOW,"Value too large for defined data type"
.e ECONNREFUSED,"ECONNREFUSED[Connection refused]" .e EILSEQ,"Illegal byte sequence"
.e EISDIR,"EISDIR[Is a directory]" .e EUSERS,"Too many users"
.e EPROTONOSUPPORT,"EPROTONOSUPPORT[Protocol not supported]" .e ENOTSOCK,"Socket operation on non-socket"
.e EROFS,"EROFS[Read-only file system]" .e EDESTADDRREQ,"Destination address required"
.e EADDRNOTAVAIL,"EADDRNOTAVAIL[Cannot assign requested address]" .e EMSGSIZE,"Message too long"
.e EIDRM,"EIDRM[Identifier removed]" .e EPROTOTYPE,"Protocol wrong type for socket"
.e ECOMM,"ECOMM[Communication error on send]" .e ENOPROTOOPT,"Protocol not available"
.e ESRMNT,"ESRMNT[Srmount error]" .e EPROTONOSUPPORT,"Protocol not supported"
.e EREMOTEIO,"EREMOTEIO[Remote I/O error]" .e ESOCKTNOSUPPORT,"Socket type not supported"
.e EL3RST,"EL3RST[Level 3 reset]" .e ENOTSUP,"Operation not supported"
.e EBADMSG,"EBADMSG[Not a data message]" .e EOPNOTSUPP,"Operation not supported on transport endpoint"
.e ENFILE,"ENFILE[File table overflow]" .e EPFNOSUPPORT,"Protocol family not supported"
.e ELIBMAX,"ELIBMAX[Attempting to link in too many shared libraries]" .e EAFNOSUPPORT,"Address family not supported by protocol"
.e ESPIPE,"ESPIPE[Illegal seek]" .e EADDRINUSE,"Address already in use"
.e ENOLINK,"ENOLINK[Link has been severed]" .e EADDRNOTAVAIL,"Cannot assign requested address"
.e ENETRESET,"ENETRESET[Network dropped connection because of reset]" .e ENETDOWN,"Network is down"
.e ETIMEDOUT,"ETIMEDOUT[Connection timed out]" .e ENETUNREACH,"Network is unreachable"
.e ENOENT,"ENOENT[No such file or directory]" .e ENETRESET,"Network dropped connection because of reset"
.e EEXIST,"EEXIST[File exists]" .e ECONNABORTED,"Software caused connection abort"
.e EDQUOT,"EDQUOT[Quota exceeded]" .e ECONNRESET,"Connection reset by peer"
.e ENOSTR,"ENOSTR[Device not a stream]" .e ENOBUFS,"No buffer space available"
.e EBADSLT,"EBADSLT[Invalid slot]" .e EISCONN,"Transport endpoint is already connected"
.e EBADRQC,"EBADRQC[Invalid request code]" .e ENOTCONN,"Transport endpoint is not connected"
.e ELIBACC,"ELIBACC[Can not access a needed shared library]" .e ESHUTDOWN,"Cannot send after transport endpoint shutdown"
.e EFAULT,"EFAULT[Bad address]" .e ETOOMANYREFS,"Too many references: cannot splice"
.e EFBIG,"EFBIG[File too large]" .e ETIMEDOUT,"Connection timed out"
.e EDEADLK,"EDEADLK[Resource deadlock would occur]" .e ECONNREFUSED,"Connection refused"
.e ENOTCONN,"ENOTCONN[Transport endpoint is not connected]" .e EHOSTDOWN,"Host is down"
.e EDESTADDRREQ,"EDESTADDRREQ[Destination address required]" .e EHOSTUNREACH,"No route to host"
.e ELIBSCN,"ELIBSCN[.lib section in a.out corrupted]" .e EALREADY,"Operation already in progress"
.e ENOLCK,"ENOLCK[No record locks available]" .e EINPROGRESS,"Operation now in progress"
.e EISNAM,"EISNAM[Is a named type file]" .e ESTALE,"Stale NFS file handle"
.e ECONNABORTED,"ECONNABORTED[Software caused connection abort]" .e EREMOTE,"Object is remote"
.e ENETUNREACH,"ENETUNREACH[Network is unreachable]" .e EBADMSG,"Not a data message"
.e ESTALE,"ESTALE[Stale NFS file handle]" .e ECANCELED,"Operation Canceled"
.e ENOSR,"ENOSR[Out of streams resources]" .e EOWNERDEAD,"Owner died"
.e ENOMEM,"ENOMEM[Out of memory]" .e ENOTRECOVERABLE,"State not recoverable"
.e ENOTSOCK,"ENOTSOCK[Socket operation on non-socket]" .e ENONET,"Machine is not on the network"
.e ESTRPIPE,"ESTRPIPE[Streams pipe error]" .e ERESTART,"Interrupted system call should be restarted"
.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]"
.long 0 .long 0
.endobj kErrorNamesLong,globl,hidden .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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#define ShouldUseMsabiAttribute() 1
#include "libc/bits/safemacros.internal.h" #include "libc/bits/safemacros.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nexgen32e/bsr.h" #include "libc/nexgen32e/bsr.h"
@ -32,93 +34,48 @@
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/str/tpenc.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"); STATIC_YOINK("__dos2errno");
#endif #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. * Converts errno value to string.
*
* @param err is error number or zero if unknown
* @return 0 on success, or error code * @return 0 on success, or error code
*/ */
noasan int strerror_r(int err, char *buf, size_t size) { privileged int strerror_r(int err, char *buf, size_t size) {
uint64_t w; /* kprintf() weakly depends on this function */
int c, i, n; int c, n, winerr;
char *p, *e; char16_t winmsg[256];
const char *s; const char *sym, *msg;
char16_t *ws = 0; sym = firstnonnull(strerror_short(err), "EUNKNOWN");
p = buf; msg = firstnonnull(strerror_long(err), "No error information");
e = p + size; if (IsTiny()) {
err &= 0xFFFF; if (!sym) sym = "EUNKNOWN";
s = IsTiny() ? GetErrorName(err) : GetErrorNameLong(err); for (; (c = *sym++); --size)
while ((c = *s++)) { if (size > 1) *buf++ = c;
if (p + 1 + 1 <= e) *p++ = 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);
} }
if (!IsTiny()) { __imp_SetLastError(winerr);
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++ = ']';
}
}
}
if (p + 1 <= e) *p = 0;
return 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/likely.h"
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/backtrace.internal.h" #include "libc/log/backtrace.internal.h"
#include "libc/log/internal.h" #include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
@ -92,7 +93,8 @@ STATIC_YOINK("_init_asan");
#define REQUIRE(FUNC) \ #define REQUIRE(FUNC) \
do { \ do { \
if (!weaken(FUNC)) { \ if (!weaken(FUNC)) { \
__asan_die("error: asan needs " #FUNC "\n")(); \ kprintf("error: asan needs %s%n", #FUNC); \
__asan_die()(); \
__asan_unreachable(); \ __asan_unreachable(); \
} \ } \
} while (0) } while (0)
@ -139,6 +141,7 @@ struct AsanMorgue {
}; };
bool __asan_noreentry; bool __asan_noreentry;
extern bool __nomultics;
static struct AsanMorgue __asan_morgue; static struct AsanMorgue __asan_morgue;
static wontreturn void __asan_unreachable(void) { 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) { static void *__asan_mempcpy(void *dst, const void *src, size_t n) {
size_t i; size_t i;
char *d, *s; char *d;
const char *s;
uint64_t a, b; uint64_t a, b;
d = dst; d = dst;
s = src; s = src;
@ -303,14 +307,13 @@ static char *__asan_hexcpy(char *p, uint64_t x, uint8_t k) {
} }
static void __asan_exit(void) { static void __asan_exit(void) {
__printf("your asan runtime needs\n" kprintf("your asan runtime needs%n"
"\tSTATIC_YOINK(\"__die\");\n" "\tSTATIC_YOINK(\"__die\");%n"
"in order to show you backtraces\n"); "in order to show you backtraces%n");
_Exit(99); _Exit(99);
} }
nodiscard static __asan_die_f *__asan_die(const char *msg) { nodiscard static __asan_die_f *__asan_die(void) {
__printf("%s", msg);
if (weaken(__die)) { if (weaken(__die)) {
return weaken(__die); return weaken(__die);
} else { } else {
@ -358,7 +361,7 @@ static bool __asan_is_mapped(int x) {
struct MemoryIntervals *m; struct MemoryIntervals *m;
m = weaken(_mmi); m = weaken(_mmi);
i = FindMemoryInterval(m, x); 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) { 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) { 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) { 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) { static struct AsanFault __asan_checka(const signed char *s, long ndiv8) {
intptr_t a; intptr_t a;
uint64_t w; uint64_t w;
signed char c, *e = s + ndiv8; const signed char *e = s + ndiv8;
for (; ((intptr_t)s & 7) && s < e; ++s) { for (; ((intptr_t)s & 7) && s < e; ++s) {
if (*s) return __asan_fault(s - 1, kAsanHeapOverrun); if (*s) return __asan_fault(s - 1, kAsanHeapOverrun);
} }
for (; s + 8 <= e; s += 8) { for (; s + 8 <= e; s += 8) {
if (UNLIKELY(!((a = (intptr_t)s) & 0xffff))) { if (UNLIKELY(!((a = (intptr_t)s) & 0xffff))) {
if (!__asan_is_mapped(a >> 16)) { if (kisdangerous((void *)a)) {
return (struct AsanFault){kAsanUnmapped, s}; 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) { struct AsanFault __asan_check(const void *p, long n) {
intptr_t a; intptr_t a;
uint64_t w;
struct AsanFault f; struct AsanFault f;
signed char c, k, *s; signed char c, k, *s;
if (n > 0) { if (n > 0) {
@ -431,7 +433,7 @@ struct AsanFault __asan_check(const void *p, long n) {
s = (signed char *)a; s = (signed char *)a;
if (OverlapsShadowSpace(p, n)) { if (OverlapsShadowSpace(p, n)) {
return (struct AsanFault){kAsanProtected, s}; return (struct AsanFault){kAsanProtected, s};
} else if (IsLegalPointer(a) && !__asan_is_mapped(a >> 16)) { } else if (kisdangerous((void *)a)) {
return (struct AsanFault){kAsanUnmapped, s}; return (struct AsanFault){kAsanUnmapped, s};
} }
if (UNLIKELY(k)) { 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) { wint_t __asan_symbolize_access_poison(signed char kind) {
switch (kind) { switch (kind) {
case kAsanNullPage: case kAsanNullPage:
@ -544,6 +533,10 @@ wint_t __asan_symbolize_access_poison(signed char kind) {
return L'G'; return L'G';
case kAsanGlobalGone: case kAsanGlobalGone:
return L'𝐺'; return L'𝐺';
case kAsanGlobalUnderrun:
return L'μ';
case kAsanGlobalOverrun:
return L'Ω';
default: default:
return L'?'; return L'?';
} }
@ -589,16 +582,19 @@ const char *__asan_describe_access_poison(signed char kind) {
return "global redzone"; return "global redzone";
case kAsanGlobalGone: case kAsanGlobalGone:
return "global gone"; return "global gone";
case kAsanGlobalUnderrun:
return "global underrun";
case kAsanGlobalOverrun:
return "global overrun";
default: default:
return "poisoned"; return "poisoned";
} }
} }
nodiscard static __asan_die_f *__asan_report_invalid_pointer(void *addr) { nodiscard static __asan_die_f *__asan_report_invalid_pointer(const void *addr) {
__printf("\r\n%sasan error%s: this corruption at 0x%p shadow 0x%p\r\n", kprintf("%n\e[J\e[1;31masan error\e[0m: this corruption at %p shadow %p%n",
!g_isterminalinarticulate ? "\e[J\e[1;91m" : "", addr, SHADOW(addr));
!g_isterminalinarticulate ? "\e[0m" : "", addr, SHADOW(addr)); return __asan_die();
return __asan_die("");
} }
static char *__asan_format_interval(char *p, intptr_t a, intptr_t b) { 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; return p;
} }
static char *__asan_format_section(char *p, void *p1, void *p2, static char *__asan_format_section(char *p, const void *p1, const void *p2,
const char *name, void *addr) { const char *name, const void *addr) {
intptr_t a, b; intptr_t a, b;
if ((a = (intptr_t)p1) < (b = (intptr_t)p2)) { if ((a = (intptr_t)p1) < (b = (intptr_t)p2)) {
p = __asan_format_interval(p, a, b), *p++ = ' '; 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) { if (a <= (intptr_t)addr && (intptr_t)addr <= b) {
p = __stpcpy(p, " ←address"); p = __stpcpy(p, " ←address");
} }
*p++ = '\r', *p++ = '\n'; if (__nomultics) *p++ = '\r';
*p++ = '\n';
} }
return p; 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, const char *message,
signed char kind) { signed char kind) {
int i;
wint_t c; wint_t c;
int i, cc;
signed char t; signed char t;
uint64_t x, y, z; uint64_t x, y, z;
char *p, *q, *base; char *p, *q, *base;
struct MemoryIntervals *m; struct MemoryIntervals *m;
p = __fatalbuf; p = __fatalbuf;
__printf("\r\n%sasan error%s: %s %d-byte %s at 0x%p shadow 0x%p\r\n", kprintf("%n\e[J\e[1;31masan error\e[0m: %s %d-byte %s at %p shadow %p%n%s%n",
!g_isterminalinarticulate ? "\e[J\e[1;91m" : "",
!g_isterminalinarticulate ? "\e[0m" : "",
__asan_describe_access_poison(kind), size, message, addr, __asan_describe_access_poison(kind), size, message, addr,
SHADOW(addr)); SHADOW(addr), __argv[0]);
if (0 < size && size < 80) { if (0 < size && size < 80) {
base = (char *)addr - ((80 >> 1) - (size >> 1)); base = (char *)addr - ((80 >> 1) - (size >> 1));
for (i = 0; i < 80; ++i) { for (i = 0; i < 80; ++i) {
@ -649,30 +644,32 @@ nodiscard static __asan_die_f *__asan_report(void *addr, int size,
*p++ = ' '; *p++ = ' ';
} }
} }
*p++ = '\r', *p++ = '\n'; if (__nomultics) *p++ = '\r';
*p++ = '\n';
for (c = i = 0; i < 80; ++i) { for (c = i = 0; i < 80; ++i) {
if (!(t = __asan_check(base + i, 1).kind)) { if (!(t = __asan_check(base + i, 1).kind)) {
if (!g_isterminalinarticulate && c != 32) { if (c != 32) {
p = __stpcpy(p, "\e[32m"); p = __stpcpy(p, "\e[32m");
c = 32; c = 32;
} }
*p++ = '.'; *p++ = '.';
} else { } else {
if (!g_isterminalinarticulate && c != 31) { if (c != 31) {
p = __stpcpy(p, "\e[31m"); p = __stpcpy(p, "\e[31m");
c = 31; c = 31;
} }
p = __asan_utf8cpy(p, __asan_symbolize_access_poison(t)); p = __asan_utf8cpy(p, __asan_symbolize_access_poison(t));
} }
} }
if (!g_isterminalinarticulate) p = __stpcpy(p, "\e[39m"); p = __stpcpy(p, "\e[39m");
*p++ = '\r', *p++ = '\n'; if (__nomultics) *p++ = '\r';
*p++ = '\n';
for (i = 0; (intptr_t)(base + i) & 7; ++i) *p++ = ' '; for (i = 0; (intptr_t)(base + i) & 7; ++i) *p++ = ' ';
for (; i + 8 <= 80; i += 8) { for (; i + 8 <= 80; i += 8) {
q = p + 8; q = p + 8;
*p++ = '|'; *p++ = '|';
z = ((intptr_t)(base + i) >> 3) + 0x7fff8000; z = ((intptr_t)(base + i) >> 3) + 0x7fff8000;
if (__asan_is_mapped(z >> 16)) { if (!kisdangerous((void *)z)) {
p = __intcpy(p, *(signed char *)z); p = __intcpy(p, *(signed char *)z);
} else { } else {
*p++ = '!'; *p++ = '!';
@ -682,13 +679,15 @@ nodiscard static __asan_die_f *__asan_report(void *addr, int size,
} }
} }
for (; i < 80; ++i) *p++ = ' '; for (; i < 80; ++i) *p++ = ' ';
*p++ = '\r', *p++ = '\n'; if (__nomultics) *p++ = '\r';
*p++ = '\n';
for (i = 0; i < 80; ++i) { for (i = 0; i < 80; ++i) {
p = __asan_utf8cpy(p, __asan_exists(base + i) p = __asan_utf8cpy(p, __asan_exists(base + i)
? kCp437[((unsigned char *)base)[i]] ? kCp437[((unsigned char *)base)[i]]
: L''); : 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, _base, _etext, ".text", addr);
p = __asan_format_section(p, _etext, _edata, ".data", 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"); if (x <= z && z <= y) p = __stpcpy(p, " ←address");
z = (((intptr_t)addr >> 3) + 0x7fff8000) >> 16; z = (((intptr_t)addr >> 3) + 0x7fff8000) >> 16;
if (x <= z && z <= y) p = __stpcpy(p, " ←shadow"); if (x <= z && z <= y) p = __stpcpy(p, " ←shadow");
*p++ = '\r', *p++ = '\n'; if (__nomultics) *p++ = '\r';
*p++ = '\n';
} }
*p = 0; *p = 0;
return __asan_die(__fatalbuf); kprintf("%s", __fatalbuf);
return __asan_die();
} }
void __asan_verify(const void *p, size_t n) { 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); __asan_fault(SHADOW(addr), -128).kind);
} }
const void *__asan_morgue_add(void *p) { void *__asan_morgue_add(void *p) {
void *r; void *r;
int i, j; int i, j;
for (;;) { for (;;) {
@ -785,6 +786,17 @@ static bool __asan_read48(uint64_t value, uint64_t *x) {
return cookie == ('J' | 'T' << 8); 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) { static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
int f1, f2; int f1, f2;
size_t i, gi; size_t i, gi;
@ -792,10 +804,9 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
struct Garbages *garbage; struct Garbages *garbage;
garbage = weaken(__garbage); garbage = weaken(__garbage);
gi = garbage ? garbage->i : 0; 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) { for (f1 = -1, i = 0; bp && i < ARRAYLEN(bt->p); ++i, bp = bp->next) {
if (f1 != (f2 = ((intptr_t)bp >> 16))) { if (f1 != (f2 = ((intptr_t)bp >> 16))) {
if (!__asan_is_mapped(f2)) break; if (kisdangerous(bp)) break;
f1 = f2; f1 = f2;
} }
if (!__asan_checka(SHADOW(bp), sizeof(*bp) >> 3).kind) { if (!__asan_checka(SHADOW(bp), sizeof(*bp) >> 3).kind) {
@ -809,7 +820,12 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
break; 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, static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
struct AsanTrace *bt) { struct AsanTrace *bt) {
@ -830,17 +846,14 @@ static void *__asan_allocate(size_t a, size_t n, int underrun, int overrun,
return p; 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; int f;
long x, n; long x, n;
struct AsanExtra *e; struct AsanExtra *e;
if ((0 < (intptr_t)p && (intptr_t)p < 0x800000000000) && f = (intptr_t)p >> 16;
__asan_is_mapped((f = (intptr_t)p >> 16)) && if (!kisdangerous(p) && (n = weaken(dlmalloc_usable_size)(p)) > sizeof(*e) &&
(LIKELY(f == (int)(((intptr_t)p - 16) >> 16)) ||
__asan_is_mapped(((intptr_t)p - 16) >> 16)) &&
(n = weaken(dlmalloc_usable_size)(p)) > sizeof(*e) &&
!__builtin_add_overflow((intptr_t)p, n, &x) && x <= 0x800000000000 && !__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)) || (LIKELY(f == (int)((x = x - sizeof(*e)) >> 16)) ||
__asan_is_mapped(x >> 16)) && __asan_is_mapped(x >> 16)) &&
!(x & (alignof(struct AsanExtra) - 1))) { !(x & (alignof(struct AsanExtra) - 1))) {
@ -882,24 +895,22 @@ static size_t __asan_malloc_usable_size(const void *p) {
} }
int __asan_print_trace(void *p) { int __asan_print_trace(void *p) {
intptr_t x;
size_t c, i, n; size_t c, i, n;
const char *name;
struct AsanExtra *e; struct AsanExtra *e;
if (!(e = __asan_get_extra(p, &c))) { if (!(e = __asan_get_extra(p, &c))) {
__printf(" bad pointer"); kprintf(" bad pointer");
return einval(); return einval();
} }
if (!__asan_read48(e->size, &n)) { if (!__asan_read48(e->size, &n)) {
__printf(" bad cookie"); kprintf(" bad cookie");
return -1; return -1;
} }
__printf(" %,d used", n); kprintf(" %'zu used", n);
if (!__asan_is_mapped((((intptr_t)p >> 3) + 0x7fff8000) >> 16)) { 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) { for (i = 0; i < ARRAYLEN(e->bt.p) && e->bt.p[i]; ++i) {
__printf("\n%*x %s", 12, e->bt.p[i], kprintf("%n%*lx %s", 12, e->bt.p[i],
weaken(__get_symbol_by_addr) weaken(__get_symbol_by_addr)
? weaken(__get_symbol_by_addr)(e->bt.p[i]) ? weaken(__get_symbol_by_addr)(e->bt.p[i])
: "please STATIC_YOINK(\"__get_symbol_by_addr\")"); : "please STATIC_YOINK(\"__get_symbol_by_addr\")");
@ -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) { void __asan_report_load(uint8_t *addr, int size) {
if (cmpxchg(&__asan_noreentry, false, true)) { if (cmpxchg(&__asan_noreentry, false, true)) {
if (!__vforked) {
__asan_report_memory_fault(addr, size, "load")(); __asan_report_memory_fault(addr, size, "load")();
__asan_unreachable(); __asan_unreachable();
} else { } else {
__printf("WARNING: ASAN error reporting had an ASAN error\r\n"); __asan_evil(addr, size, "vfork()", "load");
}
} else {
__asan_evil(addr, size, "ASAN Reporting", "load");
} }
} }
void __asan_report_store(uint8_t *addr, int size) { void __asan_report_store(uint8_t *addr, int size) {
if (cmpxchg(&__asan_noreentry, false, true)) { if (cmpxchg(&__asan_noreentry, false, true)) {
if (!__vforked) {
__asan_report_memory_fault(addr, size, "store")(); __asan_report_memory_fault(addr, size, "store")();
__asan_unreachable(); __asan_unreachable();
} else { } else {
__printf("WARNING: ASAN error reporting had an ASAN error\r\n"); __asan_evil(addr, size, "vfork()", "store");
}
} else {
__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 __asan_map_shadow(uintptr_t p, size_t n) {
void *addr; void *addr;
int i, a, b;
size_t size; size_t size;
int prot, flag; int prot, flag;
int i, x, a, b;
struct DirectMap sm; struct DirectMap sm;
struct MemoryIntervals *m; struct MemoryIntervals *m;
SYSDEBUG("__asan_map_shadow(0x%p, 0x%x)", p, n);
assert(!OverlapsShadowSpace((void *)p, n)); assert(!OverlapsShadowSpace((void *)p, n));
m = weaken(_mmi); m = weaken(_mmi);
a = (0x7fff8000 + (p >> 3)) >> 16; a = (0x7fff8000 + (p >> 3)) >> 16;
@ -1167,7 +1192,8 @@ void __asan_map_shadow(uintptr_t p, size_t n) {
weaken(TrackMemoryInterval)( weaken(TrackMemoryInterval)(
m, a, a + i - 1, sm.maphandle, PROT_READ | PROT_WRITE, m, a, a + i - 1, sm.maphandle, PROT_READ | PROT_WRITE,
MAP_PRIVATE | *weaken(MAP_ANONYMOUS) | MAP_FIXED) == -1) { 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(); __asan_unreachable();
} }
__repstosb((void *)(intptr_t)((int64_t)((uint64_t)a << 32) >> 16), __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 *)); __asan_map_shadow((uintptr_t)list, (i + 1) * sizeof(char *));
} }
static textstartup void __asan_shadow_existing_mappings(void) { static textstartup void __asan_shadow_mapping(struct MemoryIntervals *m,
size_t i; size_t i) {
struct MemoryIntervals m; uintptr_t x, y;
__asan_memcpy(&m, weaken(_mmi), sizeof(m)); if (i < m->i) {
for (i = 0; i < m.i; ++i) { x = m->p[i].x;
__asan_map_shadow((uintptr_t)m.p[i].x << 16, y = m->p[i].y;
(uintptr_t)(m.p[i].y - m.p[i].x + 1) << 16); __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) { static textstartup void __asan_shadow_existing_mappings(void) {
return weaken(_mmi) && weaken(sys_mmap) && weaken(MAP_ANONYMOUS) && __asan_shadow_mapping(&_mmi, 0);
weaken(TrackMemoryInterval); __asan_map_shadow(GetStackAddr(0), GetStackSize());
__asan_poison(GetStackAddr(0), PAGESIZE, kAsanStackOverflow);
} }
textstartup void __asan_init(int argc, char **argv, char **envp, 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; static bool once;
if (!cmpxchg(&once, false, true)) return; if (!cmpxchg(&once, false, true)) return;
if (IsWindows() && NtGetVersion() < kNtVersionWindows10) { 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 */ _Exit(0); /* So `make MODE=dbg test` passes w/ Windows7 */
} }
REQUIRE(_mmi); REQUIRE(_mmi);
@ -1241,7 +1268,7 @@ textstartup void __asan_init(int argc, char **argv, char **envp,
__asan_map_shadow(0, 4096); __asan_map_shadow(0, 4096);
__asan_poison(0, PAGESIZE, kAsanNullPage); __asan_poison(0, PAGESIZE, kAsanNullPage);
if (!IsWindows()) { 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(argv);
__asan_shadow_string_list(envp); __asan_shadow_string_list(envp);

View file

@ -1,29 +1,10 @@
#ifndef COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ #ifndef COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
#define COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ #define COSMOPOLITAN_LIBC_INTRIN_ASAN_H_
#include "libc/calls/struct/iovec.h" #include "libc/calls/struct/iovec.h"
#include "libc/intrin/asancodes.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#define kAsanScale 3 COSMOPOLITAN_C_START_
#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 SHADOW(x) ((signed char *)(((intptr_t)(x) >> kAsanScale) + kAsanMagic)) #define SHADOW(x) ((signed char *)(((intptr_t)(x) >> kAsanScale) + kAsanMagic))
#define UNSHADOW(x) ((void *)(MAX(0, (intptr_t)(x)-kAsanMagic) << kAsanScale)) #define UNSHADOW(x) ((void *)(MAX(0, (intptr_t)(x)-kAsanMagic) << kAsanScale))
@ -32,7 +13,7 @@ typedef void __asan_die_f(void);
struct AsanFault { struct AsanFault {
signed char kind; signed char kind;
signed char *shadow; const signed char *shadow;
}; };
extern bool __asan_noreentry; extern bool __asan_noreentry;
@ -58,4 +39,6 @@ void *__asan_memalign(size_t, size_t);
size_t __asan_get_heap_size(const void *); size_t __asan_get_heap_size(const void *);
void *__asan_realloc_in_place(void *, size_t); void *__asan_realloc_in_place(void *, size_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_INTRIN_ASAN_H_ */ #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/assert.h"
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/log/libfatal.internal.h" #include "libc/intrin/kprintf.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
@ -29,12 +29,12 @@
relegated wontreturn void __assert_fail(const char *expr, const char *file, relegated wontreturn void __assert_fail(const char *expr, const char *file,
int line) { int line) {
static bool noreentry; 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 (cmpxchg(&noreentry, false, true)) {
if (weaken(__die)) { if (weaken(__die)) {
weaken(__die)(); weaken(__die)();
} else { } 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); quick_exit(23);
} }

View file

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

View file

@ -57,6 +57,12 @@ o/$(MODE)/libc/intrin/asan.o: \
-finline \ -finline \
-finline-functions -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/asan.o \
o/$(MODE)/libc/intrin/ubsan.o: \ o/$(MODE)/libc/intrin/ubsan.o: \
OVERRIDE_CFLAGS += \ 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 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi 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 Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the 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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/macros.internal.h"
// Stores CPU Timestamp Counter at startup. /**
// * Timestamp of process start.
// It can be useful as an added source of seeding information. *
// * @see libc/runtime/winmain.greg.h
// @note rdtsc is a 25 cycle instruction * @see libc/crt/crt.S
.initbss 200,_init_kStartTsc */
kStartTsc: uint64_t 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__

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

View file

@ -21,6 +21,7 @@
#include "libc/bits/weaken.h" #include "libc/bits/weaken.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/internal.h" #include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
#include "libc/log/log.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, void __ubsan_abort(const struct UbsanSourceLocation *loc,
const char *description) { 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)(); if (weaken(__die)) weaken(__die)();
_Exit(134); _Exit(134);
} }
@ -258,7 +259,7 @@ void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *info,
p = __stpcpy(p, " align "); p = __stpcpy(p, " align ");
p = __intcpy(p, info->alignment); p = __intcpy(p, info->alignment);
} else { } else {
p = __stpcpy(p, "insufficient size\r\n\t"); p = __stpcpy(p, "insufficient size%n\t");
p = __stpcpy(p, kind); p = __stpcpy(p, kind);
p = __stpcpy(p, " address 0x"); p = __stpcpy(p, " address 0x");
p = __fixcpy(p, pointer, sizeof(pointer) * CHAR_BIT); p = __fixcpy(p, pointer, sizeof(pointer) * CHAR_BIT);

View file

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

View file

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

View file

@ -27,6 +27,7 @@
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/backtrace.internal.h" #include "libc/log/backtrace.internal.h"
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
#include "libc/log/log.h" #include "libc/log/log.h"
@ -46,8 +47,7 @@
#define kBacktraceMaxFrames 128 #define kBacktraceMaxFrames 128
#define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (18 + 1)) #define kBacktraceBufSize ((kBacktraceMaxFrames - 1) * (18 + 1))
static noasan int PrintBacktraceUsingAddr2line(int fd, static int PrintBacktraceUsingAddr2line(int fd, const struct StackFrame *bp) {
const struct StackFrame *bp) {
ssize_t got; ssize_t got;
intptr_t addr; intptr_t addr;
size_t i, j, gi; size_t i, j, gi;
@ -57,10 +57,32 @@ static noasan int PrintBacktraceUsingAddr2line(int fd,
const struct StackFrame *frame; const struct StackFrame *frame;
char *debugbin, *p1, *p2, *p3, *addr2line; char *debugbin, *p1, *p2, *p3, *addr2line;
char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames]; char buf[kBacktraceBufSize], *argv[kBacktraceMaxFrames];
if (IsOpenbsd()) return -1;
if (IsWindows()) return -1; if (!(debugbin = FindDebugBinary())) {
if (!(debugbin = FindDebugBinary())) return -1; if (IsLinux()) {
if (!(addr2line = GetAddr2linePath())) return -1; 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; i = 0;
j = 0; j = 0;
argv[i++] = "addr2line"; argv[i++] = "addr2line";
@ -92,8 +114,8 @@ static noasan int PrintBacktraceUsingAddr2line(int fd,
if (!(pid = vfork())) { if (!(pid = vfork())) {
sigprocmask(SIG_SETMASK, &savemask, NULL); sigprocmask(SIG_SETMASK, &savemask, NULL);
dup2(pipefds[1], 1); dup2(pipefds[1], 1);
close(pipefds[0]); if (pipefds[0] != 1) close(pipefds[0]);
close(pipefds[1]); if (pipefds[1] != 1) close(pipefds[1]);
execvp(addr2line, argv); execvp(addr2line, argv);
_exit(127); _exit(127);
} }
@ -101,36 +123,6 @@ static noasan int PrintBacktraceUsingAddr2line(int fd,
while ((got = read(pipefds[0], buf, kBacktraceBufSize)) > 0) { while ((got = read(pipefds[0], buf, kBacktraceBufSize)) > 0) {
p1 = buf; p1 = buf;
p3 = p1 + got; 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 * remove racist output from gnu tooling, that can't be disabled
* otherwise, since it breaks other tools like emacs that aren't * 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 (!IsTiny()) {
if (PrintBacktraceUsingAddr2line(fd, bp) != -1) { if (PrintBacktraceUsingAddr2line(fd, bp) != -1) {
return 0; return 0;
@ -174,21 +166,23 @@ static noasan int PrintBacktrace(int fd, const struct StackFrame *bp) {
return PrintBacktraceUsingSymbols(fd, bp, GetSymbolTable()); 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__ #ifdef __FNO_OMIT_FRAME_POINTER__
/* asan runtime depends on this function */ /* asan runtime depends on this function */
static bool noreentry; static bool noreentry;
++g_ftrace; --g_ftrace;
if (!bp) bp = __builtin_frame_address(0); if (!bp) bp = __builtin_frame_address(0);
if (!noreentry) { if (!noreentry) {
noreentry = true; noreentry = true;
PrintBacktrace(fd, bp); PrintBacktrace(fd, bp);
noreentry = false; noreentry = false;
} else {
kprintf("warning: re-entered ShowBackTrace()%n");
} }
--g_ftrace; ++g_ftrace;
#else #else
__printf("ShowBacktrace() needs these flags to show C backtrace:\n" kprintf("ShowBacktrace() needs these flags to show C backtrace:%n"
"\t-D__FNO_OMIT_FRAME_POINTER__\n" "\t-D__FNO_OMIT_FRAME_POINTER__%n"
"\t-fno-omit-frame-pointer\n"); "\t-fno-omit-frame-pointer%n");
#endif #endif
} }

View file

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

View file

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

View file

@ -18,10 +18,10 @@ COSMOPOLITAN_C_START_
extern volatile int g_gdbsync; extern volatile int g_gdbsync;
int gdbexec(const char *); int gdbexec(const char *);
int attachdebugger(intptr_t); int AttachDebugger(intptr_t);
#define attachdebugger(CONTINUE_TO_ADDR) /* shorten backtraces */ \ #define AttachDebugger(CONTINUE_TO_ADDR) /* shorten backtraces */ \
SYNCHRONIZE_DEBUGGER((attachdebugger)(CONTINUE_TO_ADDR)) SYNCHRONIZE_DEBUGGER((AttachDebugger)(CONTINUE_TO_ADDR))
#define SYNCHRONIZE_DEBUGGER(PID) \ #define SYNCHRONIZE_DEBUGGER(PID) \
({ \ ({ \
@ -49,7 +49,7 @@ int attachdebugger(intptr_t);
: "=a"(WaAx) \ : "=a"(WaAx) \
: "0"(__NR_wait4), "D"(PID), "S"(OPT_OUT_WSTATUS), \ : "0"(__NR_wait4), "D"(PID), "S"(OPT_OUT_WSTATUS), \
"d"(OPTIONS), "g"(OPT_OUT_RUSAGE) \ "d"(OPTIONS), "g"(OPT_OUT_RUSAGE) \
: "rcx", "r10", "r11", "cc", "memory"); \ : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"); \
} else { \ } else { \
WaAx = sys_wait4_nt(PID, OPT_OUT_WSTATUS, OPTIONS, OPT_OUT_RUSAGE); \ WaAx = sys_wait4_nt(PID, OPT_OUT_WSTATUS, OPTIONS, OPT_OUT_RUSAGE); \
} \ } \

View file

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

View file

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

View file

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

View file

@ -90,15 +90,6 @@ __oncrash_sigbus:
ret ret
.endfn __oncrash_sigbus,globl .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 // </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c
.endobj __oncrash_thunks,globl .endobj __oncrash_thunks,globl

View file

@ -17,7 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
#include "libc/log/libfatal.internal.h" #include "libc/intrin/kprintf.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/nexgen32e/gc.internal.h" #include "libc/nexgen32e/gc.internal.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
@ -30,19 +30,19 @@ void PrintGarbage(void) {
size_t i; size_t i;
char name[19]; char name[19];
const char *symbol; const char *symbol;
__printf("\n"); kprintf("%n");
__printf(" SHADOW STACK @ 0x%p\n", __builtin_frame_address(0)); kprintf(" SHADOW STACK @ %p%n", __builtin_frame_address(0));
__printf("garbage entry parent frame original ret callback arg \n"); kprintf("garbage ent. parent frame original ret callback arg %n");
__printf("-------------- -------------- ------------------ ------------------ ------------------\n"); kprintf("------------ ------------ ------------------ ------------------ ------------------%n");
if (__garbage.i) { if (__garbage.i) {
for (i = __garbage.i; i--;) { for (i = __garbage.i; i--;) {
symbol = __get_symbol_by_addr(__garbage.p[i].ret); symbol = __get_symbol_by_addr(__garbage.p[i].ret);
if (symbol) { if (symbol) {
snprintf(name, sizeof(name), "%s", symbol); ksnprintf(name, sizeof(name), "%s", symbol);
} else { } 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", kprintf("%12lx %12lx %18s %18s %#18lx%n",
__garbage.p + i, __garbage.p + i,
__garbage.p[i].frame, __garbage.p[i].frame,
name, name,
@ -50,7 +50,7 @@ void PrintGarbage(void) {
__garbage.p[i].arg); __garbage.p[i].arg);
} }
} else { } 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[4] = SIGTRAP; /* bad system call */
kCrashSigs[5] = SIGABRT; /* abort() called */ kCrashSigs[5] = SIGABRT; /* abort() called */
kCrashSigs[6] = SIGBUS; /* misaligned, noncanonical ptr, etc. */ kCrashSigs[6] = SIGBUS; /* misaligned, noncanonical ptr, etc. */
kCrashSigs[7] = SIGPIPE; /* write to closed thing */
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */ /* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
bzero(&sa, sizeof(sa)); bzero(&sa, sizeof(sa));
ss.ss_flags = 0; ss.ss_flags = 0;

View file

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

View file

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

View file

@ -3,6 +3,8 @@
#define FlushViewOfFile(...) __imp_FlushViewOfFile(__VA_ARGS__) #define FlushViewOfFile(...) __imp_FlushViewOfFile(__VA_ARGS__)
#define UnmapViewOfFile(...) __imp_UnmapViewOfFile(__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(UnmapViewOfFile) *const __imp_UnmapViewOfFile __msabi;
extern typeof(FlushViewOfFile) *const __imp_FlushViewOfFile __msabi; extern typeof(FlushViewOfFile) *const __imp_FlushViewOfFile __msabi;
extern typeof(MapViewOfFileExNuma) *const __imp_MapViewOfFileExNuma __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__) #define CreateProcess(...) __imp_CreateProcessW(__VA_ARGS__)
extern typeof(CreateProcess) *const __imp_CreateProcessW __msabi; 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__) #define GetModuleFileName(...) __imp_GetModuleFileNameW(__VA_ARGS__)
extern typeof(GetModuleFileName) *const __imp_GetModuleFileNameW __msabi; 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) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
bool IsAtLeastWindows10(void) pureconst;
bool32 GetVersionEx(struct NtOsVersionInfo *lpVersionInformation); 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_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_NT_VERSION_H_ */ #endif /* COSMOPOLITAN_LIBC_NT_VERSION_H_ */

View file

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

View file

@ -17,9 +17,14 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/nt/process.h"
extern int __pid;
/** /**
* Creates new process. * Creates new process.
@ -29,7 +34,7 @@
*/ */
int fork(void) { int fork(void) {
axdx_t ad; axdx_t ad;
int ax, dx; int ax, dx, parent;
if (!IsWindows()) { if (!IsWindows()) {
ad = sys_fork(); ad = sys_fork();
ax = ad.ax; ax = ad.ax;
@ -43,7 +48,19 @@ int fork(void) {
ax = sys_fork_nt(); ax = sys_fork_nt();
} }
if (!ax) { 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; return ax;
} }

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/bits/safemacros.internal.h" #include "libc/bits/safemacros.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/rdtsc.h"
@ -91,7 +92,7 @@ privileged noinstrument noasan noubsan void ftracer(void) {
if ((symbol = __get_symbol(g_symbols, frame->addr)) != -1 && if ((symbol = __get_symbol(g_symbols, frame->addr)) != -1 &&
symbol != g_lastsymbol) { symbol != g_lastsymbol) {
g_lastsymbol = symbol; g_lastsymbol = symbol;
__printf("+ %*s%s %d\r\n", GetNestingLevel(frame) * 2, "", kprintf("+ %*s%s %d\r\n", GetNestingLevel(frame) * 2, "",
__get_symbol_name(g_symbols, symbol), __get_symbol_name(g_symbols, symbol),
(long)(unsignedsubtract(stamp, laststamp) / 3.3)); (long)(unsignedsubtract(stamp, laststamp) / 3.3));
laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc(); laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
@ -110,9 +111,9 @@ textstartup void ftrace_install(void) {
ftrace_enabled = 1; ftrace_enabled = 1;
__hook(ftrace_hook, g_symbols); __hook(ftrace_hook, g_symbols);
} else { } else {
__printf("error: --ftrace failed to open symbol table\r\n"); kprintf("error: --ftrace failed to open symbol table\r\n");
} }
} else { } 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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h"
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/bits/pushpop.h"
#include "libc/bits/safemacros.internal.h" #include "libc/bits/safemacros.internal.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -32,25 +30,23 @@ struct DosArgv {
wint_t wc; 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; wint_t x, y;
for (;;) { for (;;) {
if (!(x = *(*s)++)) break; if (!(x = *st->s++)) break;
if (IsUtf16Cont(x)) continue; if (!IsUcs2(x)) {
if (IsUcs2(x)) { if ((y = *st->s++)) {
return x; x = MergeUtf16(x, y);
} else { } else {
if ((y = *(*s)++)) { x = 0;
return MergeUtf16(x, y);
} else {
return 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; uint64_t w;
w = tpenc(wc); w = tpenc(wc);
do { do {
@ -59,6 +55,16 @@ static textwindows noasan void AppendDosArgv(struct DosArgv *st, wint_t wc) {
} while (w >>= 8); } 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 * Tokenizes and transcodes Windows NT CLI args, thus avoiding
* CommandLineToArgv() schlepping in forty megs of dependencies. * 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, textwindows noasan int GetDosArgv(const char16_t *cmdline, char *buf,
size_t size, char **argv, size_t max) { size_t size, char **argv, size_t max) {
bool inquote; bool inquote;
size_t i, argc, slashes, quotes; int i, argc, slashes, quotes, ignore;
struct DosArgv st; static struct DosArgv st_;
st.s = cmdline; struct DosArgv *st = &st_;
st.p = buf; asm("" : "=g"(ignore));
st.pe = buf + size; asm("" : "+r"(st));
st->s = cmdline;
st->p = buf;
st->pe = buf + size;
argc = 0; argc = 0;
st.wc = DecodeDosArgv(&st.s); DecodeDosArgv(ignore, st);
while (st.wc) { while (st->wc) {
while (st.wc && (st.wc == ' ' || st.wc == '\t')) { while (st->wc && (st->wc == ' ' || st->wc == '\t')) {
st.wc = DecodeDosArgv(&st.s); DecodeDosArgv(ignore, st);
} }
if (!st.wc) break; if (!st->wc) break;
if (++argc < max) { 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; inquote = false;
while (st.wc) { while (st->wc) {
if (!inquote && (st.wc == ' ' || st.wc == '\t')) break; if (!inquote && (st->wc == ' ' || st->wc == '\t')) break;
if (st.wc == '"' || st.wc == '\\') { if (st->wc == '"' || st->wc == '\\') {
slashes = 0; slashes = Count('\\', st);
quotes = 0; quotes = Count('"', st);
while (st.wc == '\\') st.wc = DecodeDosArgv(&st.s), slashes++;
while (st.wc == '"') st.wc = DecodeDosArgv(&st.s), quotes++;
if (!quotes) { if (!quotes) {
while (slashes--) AppendDosArgv(&st, '\\'); while (slashes--) {
AppendDosArgv('\\', st);
}
} else { } else {
while (slashes >= 2) AppendDosArgv(&st, '\\'), slashes -= 2; while (slashes >= 2) {
if (slashes) AppendDosArgv(&st, '"'), quotes--; AppendDosArgv('\\', st);
slashes -= 2;
}
if (slashes) {
AppendDosArgv('"', st);
quotes--;
}
if (quotes > 0) { if (quotes > 0) {
if (!inquote) quotes--; 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); inquote = (quotes % 3 == 0);
} }
} }
} else { } else {
AppendDosArgv(&st, st.wc); AppendDosArgv(st->wc, st);
st.wc = DecodeDosArgv(&st.s); DecodeDosArgv(ignore, st);
} }
} }
AppendDosArgv(&st, '\0'); AppendDosArgv('\0', st);
} }
AppendDosArgv(&st, '\0'); AppendDosArgv('\0', st);
if (size) buf[min(st.p - buf, size - 1)] = '\0'; if (size) buf[min(st->p - buf, size - 1)] = '\0';
if (max) argv[min(argc, max - 1)] = NULL; if (max) argv[min(argc, max - 1)] = NULL;
return argc; return argc;
} }

View file

@ -32,7 +32,6 @@ static textwindows noasan noinstrument axdx_t Recode16to8(char *dst,
wint_t x, y; wint_t x, y;
for (v = r.ax = 0, r.dx = 0;;) { for (v = r.ax = 0, r.dx = 0;;) {
if (!(x = src[r.dx++])) break; if (!(x = src[r.dx++])) break;
if (IsUtf16Cont(x)) continue;
if (!IsUcs2(x)) { if (!IsUcs2(x)) {
y = src[r.dx++]; y = src[r.dx++];
x = MergeUtf16(x, y); 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) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
extern uint32_t __ntconsolemode; extern uint32_t __ntconsolemode[2];
extern const char v_ntsubsystem[] __attribute__((__weak__)); extern const char v_ntsubsystem[] __attribute__((__weak__));
extern const uintptr_t __fini_array_end[] __attribute__((__weak__)); extern const uintptr_t __fini_array_end[] __attribute__((__weak__));
extern const uintptr_t __fini_array_start[] __attribute__((__weak__)); extern const uintptr_t __fini_array_start[] __attribute__((__weak__));

View file

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

View file

@ -17,7 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/log/libfatal.internal.h" #include "libc/intrin/kprintf.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/runtime/memtrack.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) { for (i = 0; i < mm->i; ++i) {
frames = mm->p[i].y + 1 - mm->p[i].x; frames = mm->p[i].y + 1 - mm->p[i].x;
maptally += frames; maptally += frames;
__printf("%012x-%012x %s %,*dx%s", ADDR(mm->p[i].x), ADDR(mm->p[i].y + 1), 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, DescribeMapping(mm->p[i].prot, mm->p[i].flags, mode), w, frames,
DescribeFrame(mm->p[i].x)); DescribeFrame(mm->p[i].x));
if (i + 1 < _mmi.i) { if (i + 1 < _mmi.i) {
frames = mm->p[i + 1].x - mm->p[i].y - 1; frames = mm->p[i + 1].x - mm->p[i].y - 1;
if (frames && IsNoteworthyHole(i, mm)) { if (frames && IsNoteworthyHole(i, mm)) {
gaptally += frames; gaptally += frames;
__printf(" w/ %,d frame hole", frames); kprintf(" w/ %'ld frame hole", frames);
} }
} }
if (mm->p[i].h != -1) { 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); void ftrace_install(void);
long GetResourceLimit(int); long GetResourceLimit(int);
long GetMaxFd(void); long GetMaxFd(void);
char *GetInterpreterExecutableName(char *, size_t);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

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

View file

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

View file

@ -17,7 +17,9 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nt/struct/pollfd.h" #include "libc/nt/struct/pollfd.h"
#include "libc/nt/winsock.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 (;;) { for (;;) {
if (cmpxchg(&__interrupted, true, false)) return eintr(); 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 */ waitfor = MIN(1000, ms); /* for ctrl+c */
if ((got = WSAPoll(ntfds, nfds, waitfor)) != -1) { if ((got = WSAPoll(ntfds, nfds, waitfor)) != -1) {
if (!got && (ms -= waitfor) > 0) continue; if (!got && (ms -= waitfor) > 0) continue;

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