mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
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:
parent
2a938b3eaa
commit
b45d50b690
194 changed files with 4881 additions and 2966 deletions
4
Makefile
4
Makefile
|
@ -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
|
||||
|
||||
|
|
22
ape/ape.S
22
ape/ape.S
|
@ -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.
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
63
examples/datauri.c
Normal 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
23
examples/forkexec.c
Normal 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
25
examples/forkexecwait.c
Normal 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);
|
||||
}
|
100
examples/img.c
100
examples/img.c
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 ─╬─│┼
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 = {
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
58
libc/calls/sigwinch-nt.c
Normal 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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
26
libc/fmt/divmod10.internal.h
Normal file
26
libc/fmt/divmod10.internal.h
Normal 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_ */
|
|
@ -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 *);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
40
libc/fmt/strerror_long.greg.c
Normal file
40
libc/fmt/strerror_long.greg.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
38
libc/fmt/strerror_short.greg.c
Normal file
38
libc/fmt/strerror_short.greg.c
Normal 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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
28
libc/intrin/asancodes.h
Normal 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_ */
|
|
@ -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);
|
||||
}
|
|
@ -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.
|
||||
*
|
|
@ -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
798
libc/intrin/kprintf.greg.c
Normal 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
14
libc/intrin/kprintf.h
Normal 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_ */
|
|
@ -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
30
libc/intrin/nomultics.c
Normal 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;
|
21
libc/intrin/ntconsolemode.c
Normal file
21
libc/intrin/ntconsolemode.c
Normal 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];
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -18,6 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/log/log.h"
|
||||
|
||||
noasan const char *GetAddr2linePath(void) {
|
||||
const char *GetAddr2linePath(void) {
|
||||
return commandvenv("ADDR2LINE", "addr2line");
|
||||
}
|
||||
|
|
|
@ -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[]){
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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__)
|
||||
|
|
|
@ -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(¬possible, 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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
1
libc/nt/thunk/synchronization.inc
Normal file
1
libc/nt/thunk/synchronization.inc
Normal file
|
@ -0,0 +1 @@
|
|||
extern typeof(SleepEx) *const __imp_SleepEx __msabi;
|
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
83
libc/runtime/getinterpreterexecutablename.c
Normal file
83
libc/runtime/getinterpreterexecutablename.c
Normal 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;
|
||||
}
|
|
@ -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__));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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)();
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue