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
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)
.SUFFIXES:
@ -210,7 +210,7 @@ CHECKS = $(foreach x,$(PKGS),$($(x)_CHECKS))
bins: $(BINS)
check: $(CHECKS)
test: $(TESTS) all
test: $(TESTS)
depend: o/$(MODE)/depend
tags: TAGS HTAGS

View file

@ -1070,18 +1070,12 @@ str.error:
str.crlf:
.asciz "\r\n"
.endobj str.crlf
str.cpuid:
.asciz "cpuid"
.endobj str.cpuid
str.oldskool:
.asciz "oldskool"
.endobj str.oldskool
str.e820:
.asciz "e820"
.endobj str.e820
str.long:
.asciz "nolong"
.endobj str.long
str.oldcpu:
.asciz "oldcpu"
.endobj str.oldcpu
// Serial Line Configuration (8250 UART 16550)
// If it's hacked, it'll at least get hacked very slowly.
@ -1264,7 +1258,7 @@ longmodeloader:
lcheck: pushf # check for i8086 / i8088 / i80186
pop %ax
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
pop %eax # test ability to change cpuid bit
mov %eax,%ecx
@ -1275,7 +1269,7 @@ lcheck: pushf # check for i8086 / i8088 / i80186
pushfl
pop %eax
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
push %eax
popfl
@ -1293,11 +1287,7 @@ lcheck: pushf # check for i8086 / i8088 / i80186
jne 10f
xor %ax,%ax
1: ret
9: mov $REAL(str.oldskool),%di
jmp 20f
10: mov $REAL(str.long),%di
jmp 20f
12: mov $REAL(str.cpuid),%di
10: mov $REAL(str.oldcpu),%di
20: call rldie
.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-optimize-sibling-calls \
-fno-sanitize=all \
-ffreestanding \
-mno-fentry \
-fwrapv \
-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.7031, /* MPEG-1 / MPEG-2 video encoding divergence? */
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[] = {
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;
f = dar < 1 ? 1 / dar : dar;
s = 3 * f + 4;
fweights = gc(xcalloc(s, sizeof(double)));
fweights = gc(xcalloc(s + /*xxx*/ 2, sizeof(double)));
res = NewSamplingSolution(dn, s);
weights = res->weights;
indices = res->indices;

View file

@ -18,9 +18,12 @@
* make -j12 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.
* Environmental factors such as GDB, MAKEFLAGS, ADDR2LINE, TERM, and
* isatty(STDERR_FILENO) should also be taken into consideration:
* Backtrace is logged instead if run outside interactive terminal. We
* also don't auto-launch GDB on non-Linux since the development tools
* 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
* $ o//examples/auto-launch-gdb-on-crash.com

View file

@ -65,11 +65,26 @@
#define HeaderEqualCase(H, S) \
SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
int sock;
static bool TuneSocket(int fd, int a, int b, int x) {
if (!b) return false;
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) {
int rc;
NOISEF("begin send %zu", n);
@ -107,7 +122,6 @@ static wontreturn void PrintUsage(FILE *f, int rc) {
int main(int argc, char *argv[]) {
if (!NoDebug()) showcrashreports();
xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
/*
* Read flags.
@ -258,7 +272,7 @@ int main(int argc, char *argv[]) {
/*
* Connect to server.
*/
int ret, sock;
int ret;
CHECK_NE(-1, (sock = GoodSocket(addr->ai_family, addr->ai_socktype,
addr->ai_protocol, false,
&(struct timeval){-60})));
@ -283,6 +297,8 @@ int main(int argc, char *argv[]) {
CHECK_EQ(n, write(sock, request, n));
}
xsigaction(SIGPIPE, SIG_IGN, 0, 0, 0);
/*
* Handle response.
*/
@ -330,7 +346,7 @@ int main(int argc, char *argv[]) {
break;
}
if (method == kHttpHead) {
CHECK_EQ(hdrlen, write(1, p, hdrlen));
Write(p, hdrlen);
goto Finished;
} else if (msg.status == 204 || msg.status == 304) {
goto Finished;
@ -348,32 +364,32 @@ int main(int argc, char *argv[]) {
t = kHttpClientStateBodyLengthed;
paylen = rc;
if (paylen > i - hdrlen) {
CHECK_EQ(i - hdrlen, write(1, p + hdrlen, i - hdrlen));
Write(p + hdrlen, i - hdrlen);
} else {
CHECK_EQ(paylen, write(1, p + hdrlen, paylen));
Write(p + hdrlen, paylen);
goto Finished;
}
} else {
t = kHttpClientStateBody;
CHECK_EQ(i - hdrlen, write(1, p + hdrlen, i - hdrlen));
Write(p + hdrlen, i - hdrlen);
}
}
break;
case kHttpClientStateBody:
if (!g) goto Finished;
CHECK_EQ(g, write(1, p + i - g, g));
Write(p + i - g, g);
break;
case kHttpClientStateBodyLengthed:
CHECK(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;
break;
case kHttpClientStateBodyChunked:
Chunked:
CHECK_NE(-1, (rc = Unchunk(&u, p + hdrlen, i - hdrlen, &paylen)));
if (rc) {
CHECK_EQ(paylen, write(1, p + hdrlen, paylen));
Write(p + hdrlen, paylen);
goto Finished;
}
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/ │
*/
#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"
/**
* @fileoverview Utility for printing HTML <img> tags.
*/
#define USAGE \
" [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[]) {
void *p;
size_t n;
int yn, xn, cn;
if (argc != 2) return 1;
if (!(p = xslurp(argv[1], &n))) return 2;
if (!(p = stbi_load_from_memory(p, n, &xn, &yn, &cn, 0))) return 3;
printf("<img src=\"%s\" width=\"%d\" height=\"%d\"\n"
" alt=\"[%s]\">\n",
argv[1], (xn + 1) >> 1, (yn + 1) >> 1, argv[1]);
return 0;
showcrashreports();
int i;
while ((i = getopt(argc, argv, "?huas01234")) != -1) {
switch (i) {
case '0':
case '1':
case '2':
case '3':
case '4':
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"))) {
devnull = open("/dev/null", O_WRONLY | O_CLOEXEC);
pipe2(pipefds, O_CLOEXEC);
if (!(playpid_ = vfork())) {
if (!(playpid_ = fork())) {
const char* const args[] = {
"ffplay", "-nodisp", "-loglevel", "quiet", "-fflags",
"nobuffer", "-ac", "1", "-ar", "1789773",

View file

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

View file

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

View file

@ -27,6 +27,7 @@
#include "libc/x/x.h"
#define CTRL(C) ((C) ^ 0b01000000)
#define WRITE(FD, SLIT) write(FD, SLIT, strlen(SLIT))
#define ENABLE_SAFE_PASTE "\e[?2004h"
#define ENABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006h"
#define DISABLE_MOUSE_TRACKING "\e[?1000;1002;1015;1006l"
@ -46,7 +47,7 @@ void onkilled(int sig) {
}
void restoretty(void) {
write(1, DISABLE_MOUSE_TRACKING, strlen(DISABLE_MOUSE_TRACKING));
WRITE(1, DISABLE_MOUSE_TRACKING);
ioctl(1, TCSETS, &oldterm);
}
@ -72,9 +73,9 @@ int rawmode(void) {
t.c_cflag |= CS8;
t.c_iflag |= IUTF8;
ioctl(1, TCSETS, &t);
write(1, ENABLE_SAFE_PASTE, strlen(ENABLE_SAFE_PASTE));
write(1, ENABLE_MOUSE_TRACKING, strlen(ENABLE_MOUSE_TRACKING));
write(1, PROBE_DISPLAY_SIZE, strlen(PROBE_DISPLAY_SIZE));
WRITE(1, ENABLE_SAFE_PASTE);
WRITE(1, ENABLE_MOUSE_TRACKING);
WRITE(1, PROBE_DISPLAY_SIZE);
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;
p = data;
while (l <= r) {
m = (l + r) >> 1;
m = (l & r) + ((l ^ r) >> 1);
c = cmp(k, p + m * size, arg);
if (c > 0) {
l = m + 1;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -27,20 +27,21 @@
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
textwindows int ioctl_tiocgwinsz_nt(int fd, struct winsize *ws) {
int i, fds[3];
textwindows int ioctl_tiocgwinsz_nt(struct Fd *fd, struct winsize *ws) {
int i;
uint32_t mode;
struct Fd *fds[3];
struct NtStartupInfo startinfo;
struct NtConsoleScreenBufferInfoEx sbinfo;
if (!ws) return efault();
fds[0] = fd, fds[1] = 1, fds[2] = 0;
fds[0] = fd, fds[1] = g_fds.p + 1, fds[2] = g_fds.p + 0;
GetStartupInfo(&startinfo);
for (i = 0; i < ARRAYLEN(fds); ++i) {
if (__isfdkind(fds[i], kFdFile) || __isfdkind(fds[i], kFdConsole)) {
if (GetConsoleMode(g_fds.p[fds[i]].handle, &mode)) {
if (fds[i]->kind == kFdFile || fds[i]->kind == kFdConsole) {
if (GetConsoleMode(fds[i]->handle, &mode)) {
bzero(&sbinfo, sizeof(sbinfo));
sbinfo.cbSize = sizeof(sbinfo);
if (GetConsoleScreenBufferInfoEx(g_fds.p[fds[i]].handle, &sbinfo)) {
if (GetConsoleScreenBufferInfoEx(fds[i]->handle, &sbinfo)) {
ws->ws_col = sbinfo.srWindow.Right - sbinfo.srWindow.Left + 1;
ws->ws_row = sbinfo.srWindow.Bottom - sbinfo.srWindow.Top + 1;
ws->ws_xpixel = 0;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -22,6 +22,7 @@
#include "libc/calls/internal.h"
#include "libc/calls/sysdebug.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/mem/alloca.h"
@ -45,8 +46,17 @@
* Absolute path of executable.
*
* This variable is initialized automatically at startup. The path is
* guaranteed to exist, except on XNU and OpenBSD. It may be a symlink.
* It may be spoofed.
* basically `argv[0]` except some extra vetting is done to provide
* stronger assurance that the path can be counted upon to exist.
*
* For example, if your program is executed as a relative path and then
* your program calls `chdir()`, then `argv[0]` will be incorrect; but
* `program_executable_name` will work, because it prefixed `getcwd()`
* early in the initialization phase.
*
* @see GetInterpreterExecutableName()
* @see program_invocation_short_name
* @see program_invocation_name
*/
char program_executable_name[SIZE];
@ -75,45 +85,31 @@ static textwindows bool GetNtExePath(char executable[SIZE]) {
}
static textstartup void GetProgramExecutableName(char executable[SIZE],
char *p) {
char *t;
char *argv0, intptr_t *auxv) {
size_t m;
ssize_t n;
int cmd[4];
ssize_t n = 0;
char *p, *t;
if (IsWindows() && GetNtExePath(executable)) return;
if (fileexists(p)) {
for (p = 0; *auxv; auxv += 2) {
if (*auxv == AT_EXECFN) {
p = (char *)auxv[1];
break;
}
}
n = 0;
if (!p) p = argv0;
if (p) {
if (!_isabspath(p)) {
if (getcwd(executable, SIZE - 1)) {
n = strlen(executable);
executable[n++] = '/';
}
}
} else if ((n = sys_readlinkat(AT_FDCWD, "/proc/self/exe", executable,
SIZE - 1)) > 0) {
executable[n] = 0;
return;
} else if ((n = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", executable,
SIZE - 1)) > 0) {
executable[n] = 0;
return;
} else if (IsFreebsd() || IsNetbsd()) {
cmd[0] = CTL_KERN;
cmd[1] = KERN_PROC;
if (IsFreebsd()) {
cmd[2] = KERN_PROC_PATHNAME_FREEBSD;
} else {
cmd[2] = KERN_PROC_PATHNAME_NETBSD;
}
cmd[3] = -1;
m = SIZE;
if (sysctl(cmd, ARRAYLEN(cmd), executable, &m, 0, 0) != -1) {
return;
}
}
if (n < 0) n = 0;
for (; *p; ++p) {
if (n + 1 < SIZE) {
executable[n++] = *p;
for (; *p; ++p) {
if (n + 1 < SIZE) {
executable[n++] = *p;
}
}
}
executable[n] = 0;
@ -121,13 +117,15 @@ static textstartup void GetProgramExecutableName(char executable[SIZE],
textstartup void program_executable_name_init(int argc, char **argv,
char **envp, intptr_t *auxv) {
int e;
static bool once;
char executable[SIZE];
if (!cmpxchg(&once, 0, 1)) return;
__stpcpy(program_executable_name, argv[0]);
GetProgramExecutableName(executable, argv[0]);
e = errno;
GetProgramExecutableName(executable, argv[0], auxv);
errno = e;
__stpcpy(program_executable_name, executable);
SYSDEBUG("GetProgramExecutableName() -> %s", program_executable_name);
SYSDEBUG("program_executable_name → %#s", program_executable_name);
}
const void *const program_executable_name_init_ctor[] initarray = {

View file

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

View file

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

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

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

View file

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

View file

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

View file

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

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

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

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

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

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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