From feed0d2b0edab83bb1299a5bfb33ea8fb7c8a159 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Tue, 27 Oct 2020 03:39:46 -0700 Subject: [PATCH] Add minor improvements and cleanup --- Makefile | 1 - ape/lib/pc.h | 3 +- build/realify.sed | 26 +- dsp/tty/itoa8.c | 15 +- dsp/tty/ttyraster.c | 93 +-- dsp/tty/ttyraw.c | 1 - examples/ctrlc.c | 1 + examples/findprime.c | 1 + examples/subprocess.c | 2 +- examples/unbourne.c | 118 +-- libc/calls/calls.h | 10 +- libc/calls/fcntl-nt.c | 13 +- libc/calls/fcntl.c | 7 +- libc/calls/fixntmagicpath.ncabi.c | 40 -- libc/calls/internal.h | 16 +- libc/calls/mkntpath.ncabi.c | 32 +- libc/calls/setitimer-nt.c | 2 +- libc/calls/thunks/onntconsoleevent.S | 2 +- libc/calls/thunks/onwincrash.S | 8 +- libc/calls/thunks/{onntalarm.S => winalarm.S} | 8 +- libc/calls/{onntalarm.c => winalarm.c} | 4 +- libc/calls/{onwincrash.c => wincrash.c} | 2 +- .../{onwincrash_init.S => wincrash_init.S} | 6 +- libc/crt/crt.S | 5 +- libc/dns/getaddrinfo.c | 2 +- libc/errno.h | 262 +++---- libc/escape/aescape.c | 47 -- libc/escape/cunescape.c | 64 -- libc/escape/escape.h | 22 - libc/escape/escape.mk | 57 -- libc/escape/escapesh.c | 73 -- libc/fmt/palandprintf.c | 3 +- libc/fmt/stoa.c | 1 - libc/fmt/strerror_r.c | 2 +- libc/log/asan.c | 24 +- libc/log/checkfail.c | 25 +- libc/log/checkfail_ndebug.c | 2 +- libc/log/color.h | 20 + libc/log/internal.h | 26 +- libc/log/log.h | 1 - libc/log/log.mk | 1 - libc/log/oncrash.c | 13 +- libc/log/oncrashthunks.S | 46 +- libc/log/perror.c | 1 + libc/log/showcrashreports.c | 4 +- libc/log/startfatal.c | 13 +- libc/log/startfatal_ndebug.c | 8 +- libc/log/ubsan.c | 4 +- libc/log/verr.c | 1 + libc/log/verrx.c | 1 + libc/log/vflogf.c | 5 +- libc/log/vwarn.c | 1 + libc/log/vwarnx.c | 1 + libc/{x/xaescapeshq.c => mem/malloc_trim.c} | 14 +- libc/nexgen32e/nt2sysv.S | 5 +- libc/nexgen32e/strsak.S | 11 +- libc/rand/rand.mk | 1 + libc/stdio/g_stderr_init.S | 8 +- libc/stdio/g_stdin_init.S | 8 +- libc/stdio/g_stdout_init.S | 8 +- libc/stdio/stdio.mk | 1 - libc/stdio/system.c | 1 - libc/str/endswith.c | 13 +- libc/{escape => str}/escapedos.c | 1 - libc/str/getkvlin.c | 8 +- libc/str/indexdoublenulstring.c | 13 +- libc/str/internal.h | 19 +- libc/str/isascii.c | 1 + libc/str/isnotplaintext.c | 64 -- libc/str/ktpdecoderring.S | 56 -- libc/str/startswith.c | 4 +- libc/str/stpcpy.c | 45 +- libc/str/str.h | 28 +- libc/str/str.mk | 1 + libc/str/strclen.c | 18 +- libc/str/strcpy.c | 31 +- libc/{x/xaescape.c => str/strlen.c} | 38 +- libc/str/thompike.h | 4 +- libc/stubs/sysv2nt.S | 2 +- libc/sysv/calls/vfork.s | 2 - libc/sysv/consts.sh | 11 +- libc/sysv/consts/MAP_FIXED.s | 2 +- libc/sysv/consts/MAP_NONBLOCK.s | 2 +- libc/sysv/consts/__NR_vfork.s | 2 + libc/sysv/syscalls.sh | 2 +- libc/sysv/systemfive.S | 6 +- libc/sysv/sysv.mk | 2 + libc/{escape/aescapesh.c => sysv/vfork.S} | 40 +- libc/testlib/showerror.c | 1 + libc/testlib/showerror_.c | 1 + libc/time/dsleep.c | 2 - .../{escape/escapec.c => unicode/strnwidth.c} | 91 ++- libc/unicode/strwidth.c | 58 +- libc/unicode/unicode.h | 33 - libc/unicode/wcwidth.c | 5 + libc/x/x.h | 5 - libc/x/x.mk | 1 - libc/x/xaescapec.c | 31 - libc/x/xaescapesh.c | 34 - net/http/http.mk | 1 + test/libc/fmt/palandprintf_test.c | 1 - test/libc/mem/malloc_test.c | 1 + test/libc/nexgen32e/cescapec_test.c | 2 +- test/libc/str/str_test.c | 4 +- .../{isnotplaintext_test.c => strcpy_test.c} | 32 +- test/libc/str/strlen_test.c | 14 + .../libc/unicode/strwidth_test.c | 13 +- test/libc/unicode/wcwidth_test.c | 4 - test/tool/build/lib/machine_test.c | 16 +- test/tool/build/lib/pty_test.c | 37 +- third_party/dlmalloc/dlmalloc.h | 1 + third_party/dlmalloc/malloc_trim.c | 2 +- third_party/regex/regerror.c | 2 +- third_party/xed/xederror.c | 2 +- tool/build/blinkenlights.c | 443 +++++++----- tool/build/calculator.c | 1 + tool/build/emubin/emubin.mk | 15 + tool/build/emubin/lisp.c | 178 +++-- tool/build/emubin/lisp.h | 14 +- tool/build/emubin/lisp.lds | 2 +- tool/build/emubin/lisp.lisp | 131 +++- tool/build/emubin/lispelf.S | 23 + tool/build/emubin/lispstart.S | 26 - tool/build/lib/alu.c | 9 - tool/build/lib/alu.h | 1 - tool/build/lib/buffer.c | 9 +- tool/build/lib/buffer.h | 2 +- tool/build/lib/buildlib.mk | 4 + tool/build/lib/cpuid.c | 4 +- tool/build/lib/dis.c | 2 +- tool/build/lib/dis.h | 2 +- tool/build/lib/disarg.c | 21 +- tool/build/lib/diself.c | 141 ++-- tool/build/lib/flags.c | 9 + tool/build/lib/flags.h | 1 + tool/build/lib/loader.c | 24 +- tool/build/lib/machine.c | 61 +- tool/build/lib/machine.h | 16 +- tool/build/lib/memory.c | 82 ++- tool/build/lib/memorymalloc.c | 106 ++- tool/build/lib/modrm.c | 4 + tool/build/lib/modrm.h | 3 +- tool/build/lib/op101.c | 160 +++++ tool/build/lib/op101.h | 11 + tool/build/lib/panel.h | 8 +- tool/build/lib/pml4tfmt.c | 1 + tool/build/lib/pty.c | 679 +++++++++--------- tool/build/lib/pty.h | 88 +-- tool/build/lib/ssemov.c | 19 +- tool/build/lib/stats.c | 2 +- tool/build/lib/stats.h | 2 +- tool/build/lib/syscall.c | 103 ++- tool/build/lib/throw.c | 3 +- tool/build/tinyemu.c | 26 +- tool/viz/basicidea.c | 1 - tool/viz/cpuid.c | 4 +- tool/viz/deathstar.c | 64 +- tool/viz/derasterize.c | 1 - tool/viz/magikarp.c | 1 - tool/viz/printimage.c | 1 - tool/viz/printpixel.c | 2 +- tool/viz/printvideo.c | 7 +- tool/viz/xterm256info.c | 2 +- 163 files changed, 2286 insertions(+), 2245 deletions(-) delete mode 100644 libc/calls/fixntmagicpath.ncabi.c rename libc/calls/thunks/{onntalarm.S => winalarm.S} (95%) rename libc/calls/{onntalarm.c => winalarm.c} (94%) rename libc/calls/{onwincrash.c => wincrash.c} (98%) rename libc/calls/{onwincrash_init.S => wincrash_init.S} (95%) delete mode 100644 libc/escape/aescape.c delete mode 100644 libc/escape/cunescape.c delete mode 100644 libc/escape/escape.h delete mode 100644 libc/escape/escape.mk delete mode 100644 libc/escape/escapesh.c create mode 100644 libc/log/color.h rename libc/{x/xaescapeshq.c => mem/malloc_trim.c} (86%) rename libc/{escape => str}/escapedos.c (99%) delete mode 100644 libc/str/isnotplaintext.c delete mode 100644 libc/str/ktpdecoderring.S rename libc/{x/xaescape.c => str/strlen.c} (74%) delete mode 100644 libc/sysv/calls/vfork.s create mode 100644 libc/sysv/consts/__NR_vfork.s rename libc/{escape/aescapesh.c => sysv/vfork.S} (71%) rename libc/{escape/escapec.c => unicode/strnwidth.c} (58%) delete mode 100644 libc/x/xaescapec.c delete mode 100644 libc/x/xaescapesh.c rename test/libc/str/{isnotplaintext_test.c => strcpy_test.c} (73%) rename libc/escape/aescapec.c => test/libc/unicode/strwidth_test.c (86%) create mode 100644 tool/build/emubin/lispelf.S create mode 100644 tool/build/lib/op101.c create mode 100644 tool/build/lib/op101.h diff --git a/Makefile b/Makefile index 51822b24..624be011 100644 --- a/Makefile +++ b/Makefile @@ -117,7 +117,6 @@ include libc/ohmyplus/ohmyplus.mk # │ include libc/zipos/zipos.mk # │ include third_party/dtoa/dtoa.mk # │ include libc/time/time.mk # │ -include libc/escape/escape.mk # │ include libc/alg/alg.mk # │ include libc/calls/hefty/hefty.mk # │ include libc/stdio/stdio.mk # │ diff --git a/ape/lib/pc.h b/ape/lib/pc.h index b8a4fc63..5b04a341 100644 --- a/ape/lib/pc.h +++ b/ape/lib/pc.h @@ -128,7 +128,7 @@ /* Long Mode Paging @see Intel Manual V.3A §4.1 §4.5 IsValid (ignored on CR3) V┐ - ┌Block Instr. Fetches (if NXE) IsWritable (ignored on CR3) RW┐│ + ┌XD:No Inst. Fetches (if NXE) IsWritable (ignored on CR3) RW┐│ │ Permit User-Mode Access - u┐││ │ Page-level Write-Through - PWT┐│││ │ Page-level Cache Disable - PCD┐││││ @@ -147,7 +147,6 @@ ││ ││ ││├──────────────────┐ │ ││ ││││││││││ ││ ││ │││ Phys. Addr. 1GB │ │ ││ ││││││││││ ││ ││ │││ │ │ ││ ││││││││││ - 0b00000000000011111111111111111111111111111111111111000000000000 6666555555555544444444443333333333222222222211111111110000000000 3210987654321098765432109876543210987654321098765432109876543210*/ #define PAGE_V /* */ 0b000000001 diff --git a/build/realify.sed b/build/realify.sed index 0bb2dcab..92a0f359 100644 --- a/build/realify.sed +++ b/build/realify.sed @@ -15,22 +15,22 @@ # remove comments s/[ \t][ \t]*#.*// -#s/leave\(q\|\)/leavew/ -#s/call\(q\|\)/callw/ -#s/ret\(q\|\)/retw/ -#s/popq\t%rbp/pop\t%bp/ -#s/pushq\t%rbp/push\t%bp/ -#s/pushq\t\(.*\)/sub $6,%sp\n\tpush \1/ -#s/popq\t\(.*\)/pop \1\n\tadd $6,%sp/ - -# preserve hardcoded stack offsets -# bloats code size 13% -s/leave\(q\|\)/leavew\n\tadd\t$6,%sp/ -s/call\(q\|\)\t/sub\t$6,%sp\n\tcallw\t/ -s/ret\(q\|\)/retw\t$6/ +s/leave\(q\|\)/leavew/ +s/call\(q\|\)/callw/ +s/ret\(q\|\)/retw/ +s/popq\t%rbp/pop\t%bp/ +s/pushq\t%rbp/push\t%bp/ s/pushq\t\(.*\)/sub\t$6,%sp\n\tpush\t\1/ s/popq\t\(.*\)/pop\t\1\n\tadd\t$6,%sp/ +# # preserve hardcoded stack offsets +# # bloats code size 13% +# s/leave\(q\|\)/leavew\n\tadd\t$6,%sp/ +# s/call\(q\|\)\t/sub\t$6,%sp\n\tcallw\t/ +# s/ret\(q\|\)/retw\t$6/ +# s/pushq\t\(.*\)/sub\t$6,%sp\n\tpush\t\1/ +# s/popq\t\(.*\)/pop\t\1\n\tadd\t$6,%sp/ + s/, /,/g # 32-bitify diff --git a/dsp/tty/itoa8.c b/dsp/tty/itoa8.c index 1cfc4069..6eb84f4b 100644 --- a/dsp/tty/itoa8.c +++ b/dsp/tty/itoa8.c @@ -27,24 +27,21 @@ struct Itoa8 kItoa8; static textstartup void itoa8_init(void) { int i; uint8_t z; - char p[4]; + uint32_t w; for (i = 0; i < 256; ++i) { - memset(p, 0, sizeof(p)); if (i < 10) { z = 1; - p[0] = '0' + i; + w = '0' + i; } else if (i < 100) { z = 2; - p[0] = '0' + i / 10; - p[1] = '0' + i % 10; + w = ('0' + i / 10) | ('0' + i % 10) << 8; } else { z = 3; - p[0] = '0' + i / 100; - p[1] = '0' + i % 100 / 10; - p[2] = '0' + i % 100 % 10; + w = ('0' + i / 100) | ('0' + i % 100 / 10) << 8 | + ('0' + i % 100 % 10) << 16; } kItoa8.size[i] = z; - memcpy(&kItoa8.data[i], p, sizeof(p)); + kItoa8.data[i] = w; } } diff --git a/dsp/tty/ttyraster.c b/dsp/tty/ttyraster.c index 3064f2a0..6d64657c 100644 --- a/dsp/tty/ttyraster.c +++ b/dsp/tty/ttyraster.c @@ -240,9 +240,10 @@ static const struct Pick kPicksMixBlock[32] = { {TL, TR, 9}, /* ▓ */ }; -static unsigned short bdist(struct TtyRgb a, struct TtyRgb b, struct TtyRgb c, - struct TtyRgb d, struct TtyRgb w, struct TtyRgb x, - struct TtyRgb y, struct TtyRgb z) { +static unsigned short GetBlockDist(struct TtyRgb a, struct TtyRgb b, + struct TtyRgb c, struct TtyRgb d, + struct TtyRgb w, struct TtyRgb x, + struct TtyRgb y, struct TtyRgb z) { unsigned short dist; dist = 0; dist += ABS(a.r - w.r); @@ -260,7 +261,7 @@ static unsigned short bdist(struct TtyRgb a, struct TtyRgb b, struct TtyRgb c, return dist; } -static uint16_t *mixblock(uint16_t *p, struct TtyRgb ttl, struct TtyRgb ttr, +static uint16_t *MixBlock(uint16_t *p, struct TtyRgb ttl, struct TtyRgb ttr, struct TtyRgb tbl, struct TtyRgb tbr, struct TtyRgb qtl, struct TtyRgb qtr, struct TtyRgb qbl, struct TtyRgb qbr) { @@ -465,15 +466,15 @@ static uint16_t *mixblock(uint16_t *p, struct TtyRgb ttl, struct TtyRgb ttr, return p; } -static struct TtyRgb getquant(struct TtyRgb rgb) { +static struct TtyRgb GetQuant(struct TtyRgb rgb) { return g_ansi2rgb_[rgb.xt]; } -static uint16_t *pickunicode(uint16_t *p, struct TtyRgb tl, struct TtyRgb tr, +static uint16_t *PickUnicode(uint16_t *p, struct TtyRgb tl, struct TtyRgb tr, struct TtyRgb bl, struct TtyRgb br, struct TtyRgb tl2, struct TtyRgb tr2, struct TtyRgb bl2, struct TtyRgb br2) { -#define PICK(A, B, C, D) *p++ = bdist(tl, tr, bl, br, A, B, C, D) +#define PICK(A, B, C, D) *p++ = GetBlockDist(tl, tr, bl, br, A, B, C, D) PICK(bl2, bl2, bl2, bl2); /* k=0 bg=bl fg=NULL */ PICK(bl2, bl2, bl2, br2); /* ▗ k=4 bg=bl fg=br */ PICK(bl2, bl2, bl2, tl2); /* ▗ k=4 bg=bl fg=tl */ @@ -566,11 +567,11 @@ static uint16_t *pickunicode(uint16_t *p, struct TtyRgb tl, struct TtyRgb tr, return p; } -static uint16_t *pickcp437(uint16_t *p, struct TtyRgb tl, struct TtyRgb tr, +static uint16_t *PickCp437(uint16_t *p, struct TtyRgb tl, struct TtyRgb tr, struct TtyRgb bl, struct TtyRgb br, struct TtyRgb tl2, struct TtyRgb tr2, struct TtyRgb bl2, struct TtyRgb br2) { -#define PICK(A, B, C, D) *p++ = bdist(tl, tr, bl, br, A, B, C, D) +#define PICK(A, B, C, D) *p++ = GetBlockDist(tl, tr, bl, br, A, B, C, D) PICK(bl2, bl2, bl2, bl2); /* k=0 bg=bl fg=NULL */ PICK(bl2, bl2, br2, br2); /* ▄ k=1 bg=bl fg=br */ PICK(bl2, bl2, tl2, tl2); /* ▄ k=1 bg=bl fg=tl */ @@ -603,30 +604,30 @@ static uint16_t *pickcp437(uint16_t *p, struct TtyRgb tl, struct TtyRgb tr, return p; } -static struct Pick pickblock_unicode_ansi(struct TtyRgb tl, struct TtyRgb tr, - struct TtyRgb bl, struct TtyRgb br) { - struct TtyRgb tl2 = getquant(tl); - struct TtyRgb tr2 = getquant(tr); - struct TtyRgb bl2 = getquant(bl); - struct TtyRgb br2 = getquant(br); +static struct Pick PickBlockUnicodeAnsi(struct TtyRgb tl, struct TtyRgb tr, + struct TtyRgb bl, struct TtyRgb br) { + struct TtyRgb tl2 = GetQuant(tl); + struct TtyRgb tr2 = GetQuant(tr); + struct TtyRgb bl2 = GetQuant(bl); + struct TtyRgb br2 = GetQuant(br); unsigned i, p1, p2; uint16_t picks1[96] aligned(32); uint16_t picks2[32] aligned(32); memset(picks1, 0x79, sizeof(picks1)); memset(picks2, 0x79, sizeof(picks2)); - pickunicode(picks1, tl, tr, bl, br, tl2, tr2, bl2, br2); - mixblock(picks2, tl, tr, bl, br, tl2, tr2, bl2, br2); + PickUnicode(picks1, tl, tr, bl, br, tl2, tr2, bl2, br2); + MixBlock(picks2, tl, tr, bl, br, tl2, tr2, bl2, br2); p1 = windex(picks1, 96); p2 = windex(picks2, 32); return picks1[p1] <= picks2[p2] ? kPicksUnicode[p1] : kPicksMixBlock[p2]; } -static struct Pick pickblock_unicode_true(struct TtyRgb tl, struct TtyRgb tr, - struct TtyRgb bl, struct TtyRgb br) { +static struct Pick PickBlockUnicodeTrue(struct TtyRgb tl, struct TtyRgb tr, + struct TtyRgb bl, struct TtyRgb br) { unsigned i; uint16_t picks[96] aligned(32); memset(picks, 0x79, sizeof(picks)); - pickunicode(picks, tl, tr, bl, br, tl, tr, bl, br); + PickUnicode(picks, tl, tr, bl, br, tl, tr, bl, br); i = windex(picks, 96); if (i >= 88) { unsigned j; @@ -640,39 +641,39 @@ static struct Pick pickblock_unicode_true(struct TtyRgb tl, struct TtyRgb tr, return kPicksUnicode[i]; } -static struct Pick pickblock_cp437_ansi(struct TtyRgb tl, struct TtyRgb tr, - struct TtyRgb bl, struct TtyRgb br) { - struct TtyRgb tl2 = getquant(tl); - struct TtyRgb tr2 = getquant(tr); - struct TtyRgb bl2 = getquant(bl); - struct TtyRgb br2 = getquant(br); +static struct Pick PickBlockCp437Ansi(struct TtyRgb tl, struct TtyRgb tr, + struct TtyRgb bl, struct TtyRgb br) { + struct TtyRgb tl2 = GetQuant(tl); + struct TtyRgb tr2 = GetQuant(tr); + struct TtyRgb bl2 = GetQuant(bl); + struct TtyRgb br2 = GetQuant(br); unsigned i, p1, p2; uint16_t picks1[32] aligned(32); uint16_t picks2[32] aligned(32); memset(picks1, 0x79, sizeof(picks1)); memset(picks2, 0x79, sizeof(picks2)); - pickcp437(picks1, tl, tr, bl, br, tl2, tr2, bl2, br2); - mixblock(picks2, tl, tr, bl, br, tl2, tr2, bl2, br2); + PickCp437(picks1, tl, tr, bl, br, tl2, tr2, bl2, br2); + MixBlock(picks2, tl, tr, bl, br, tl2, tr2, bl2, br2); p1 = windex(picks1, 32); p2 = windex(picks2, 32); return picks1[p1] <= picks2[p2] ? kPicksCp437[p1] : kPicksMixBlock[p2]; } -static struct Pick pickblock_cp437_true(struct TtyRgb tl, struct TtyRgb tr, - struct TtyRgb bl, struct TtyRgb br) { +static struct Pick PickBlockCp437True(struct TtyRgb tl, struct TtyRgb tr, + struct TtyRgb bl, struct TtyRgb br) { unsigned i; uint16_t picks[32] aligned(32); memset(picks, 0x79, sizeof(picks)); - pickcp437(picks, tl, tr, bl, br, tl, tr, bl, br); + PickCp437(picks, tl, tr, bl, br, tl, tr, bl, br); return kPicksCp437[windex(picks, 32)]; } -static char *copyglyph(char *v, struct Glyph glyph) { +static char *CopyGlyph(char *v, struct Glyph glyph) { memcpy(v, &glyph, 4); return v + glyph.len; } -static char *copyblock(char *v, const struct TtyRgb chunk[hasatleast 4], +static char *CopyBlock(char *v, const struct TtyRgb chunk[hasatleast 4], struct Pick pick, struct TtyRgb *bg, struct TtyRgb *fg, struct Glyph *glyph) { unsigned i; @@ -721,16 +722,16 @@ static char *copyblock(char *v, const struct TtyRgb chunk[hasatleast 4], } else if (!ttyeq(*bg, chunk[pick.bg])) { v = setbg(v, (*bg = chunk[pick.bg])); } - return copyglyph(v, (*glyph = kGlyphs[i][pick.k])); + return CopyGlyph(v, (*glyph = kGlyphs[i][pick.k])); } -static bool chunkeq(struct TtyRgb c[hasatleast 4], +static bool ChunkEq(struct TtyRgb c[hasatleast 4], struct TtyRgb c2[hasatleast 4]) { return ttyeq(c[TL], c[TR]) && ttyeq(c[BL], c[BR]) && ttyeq(c2[TL], c2[TR]) && ttyeq(c2[BL], c2[BR]); } -static struct TtyRgb *copychunk(struct TtyRgb chunk[hasatleast 4], +static struct TtyRgb *CopyChunk(struct TtyRgb chunk[hasatleast 4], const struct TtyRgb *c, size_t n) { chunk[TL] = c[0 + 0]; chunk[TR] = c[0 + 1]; @@ -739,7 +740,7 @@ static struct TtyRgb *copychunk(struct TtyRgb chunk[hasatleast 4], return chunk; } -static noinline char *copyrun(char *v, size_t n, +static noinline char *CopyRun(char *v, size_t n, struct TtyRgb lastchunk[hasatleast 4], const struct TtyRgb **c, size_t *x, struct TtyRgb *bg, struct TtyRgb *fg, @@ -752,12 +753,12 @@ static noinline char *copyrun(char *v, size_t n, *glyph = kGlyphs[0][0]; } do { - v = copyglyph(v, *glyph); + v = CopyGlyph(v, *glyph); *x += 2; *c += 2; if (*x >= n) break; - copychunk(chunk, *c, n); - } while (chunkeq(chunk, lastchunk)); + CopyChunk(chunk, *c, n); + } while (ChunkEq(chunk, lastchunk)); *x -= 2; *c -= 2; return v; @@ -776,21 +777,21 @@ char *ttyraster(char *v, const struct TtyRgb *c, size_t yn, size_t n, for (y = 0; y < yn; y += 2, c += n) { if (y) *v++ = '\r', *v++ = '\n'; for (x = 0; x < n; x += 2, c += 2) { - copychunk(chun, c, n); + CopyChunk(chun, c, n); if (ttyquant()->alg == kTtyQuantTrue) { if (ttyquant()->blocks == kTtyBlocksCp437) { - p = pickblock_cp437_true(chun[TL], chun[TR], chun[BL], chun[BR]); + p = PickBlockCp437True(chun[TL], chun[TR], chun[BL], chun[BR]); } else { - p = pickblock_unicode_true(chun[TL], chun[TR], chun[BL], chun[BR]); + p = PickBlockUnicodeTrue(chun[TL], chun[TR], chun[BL], chun[BR]); } } else { if (ttyquant()->blocks == kTtyBlocksCp437) { - p = pickblock_cp437_ansi(chun[TL], chun[TR], chun[BL], chun[BR]); + p = PickBlockCp437Ansi(chun[TL], chun[TR], chun[BL], chun[BR]); } else { - p = pickblock_unicode_ansi(chun[TL], chun[TR], chun[BL], chun[BR]); + p = PickBlockUnicodeAnsi(chun[TL], chun[TR], chun[BL], chun[BR]); } } - v = copyblock(v, chun, p, &bg, &fg, &glyph); + v = CopyBlock(v, chun, p, &bg, &fg, &glyph); memcpy(lastchunk, chun, sizeof(chun)); } } diff --git a/dsp/tty/ttyraw.c b/dsp/tty/ttyraw.c index 54451d0e..ffa7c409 100644 --- a/dsp/tty/ttyraw.c +++ b/dsp/tty/ttyraw.c @@ -158,6 +158,5 @@ textstartup int ttyraw(enum TtyRawFlags flags) { } else { rc = ttyraw_disable(); } - cancolor(); return rc; } diff --git a/examples/ctrlc.c b/examples/ctrlc.c index 2bbf4290..1fa699e6 100644 --- a/examples/ctrlc.c +++ b/examples/ctrlc.c @@ -9,6 +9,7 @@ #endif #include "libc/calls/calls.h" #include "libc/log/check.h" +#include "libc/log/color.h" #include "libc/log/log.h" #include "libc/mem/mem.h" #include "libc/runtime/gc.h" diff --git a/examples/findprime.c b/examples/findprime.c index fcc75417..c2e7b323 100644 --- a/examples/findprime.c +++ b/examples/findprime.c @@ -13,6 +13,7 @@ #include "libc/conv/conv.h" #include "libc/limits.h" #include "libc/log/check.h" +#include "libc/log/color.h" #include "libc/log/log.h" #include "libc/math.h" #include "libc/runtime/runtime.h" diff --git a/examples/subprocess.c b/examples/subprocess.c index 3696eb46..42fa2862 100644 --- a/examples/subprocess.c +++ b/examples/subprocess.c @@ -26,7 +26,7 @@ int main(int argc, char *argv[]) { * * 1. gc() automates calling free() on return. * 2. xasprintf("foo %s", "bar") is our version of "foo %s" % ("bar") - * 3. Demonstrates correct escaping for bourne shell cf. xaescapeshq() + * 3. Demonstrates correct escaping for bourne shell */ if (!fileexists(kProgram)) { system(gc(xasprintf("%s '%s'", "make -j4", diff --git a/examples/unbourne.c b/examples/unbourne.c index 03adad57..ba715e4d 100644 --- a/examples/unbourne.c +++ b/examples/unbourne.c @@ -620,12 +620,12 @@ #define octtobin(c) ((c) - '0') #define scopy(s1, s2) ((void)strcpy(s2, s1)) -/* #define TRACE(param) */ -#define TRACE(param) \ - do { \ - printf("TRACE: "); \ - printf param; \ - } while (0) +#define TRACE(param) +/* #define TRACE(param) \ */ +/* do { \ */ +/* printf("TRACE: "); \ */ +/* printf param; \ */ +/* } while (0) */ #define TRACEV(param) #define digit_val(c) ((c) - '0') @@ -634,8 +634,6 @@ #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) #define is_special(c) ((is_type + SYNBASE)[(signed char)(c)] & (ISSPECL | ISDIGIT)) -/* #define likely(x) __builtin_expect(!!(x), 1) */ -/* #define unlikely(x) __builtin_expect(!!(x), 0) */ #define uninitialized_var(x) x = x /* suppress uninitialized warning w/o code */ @@ -643,9 +641,7 @@ * Shell variables. */ #define vifs varinit[0] -#define vmail (&vifs)[1] -#define vmpath (&vmail)[1] -#define vpath (&vmpath)[1] +#define vpath (&vifs)[1] #define vps1 (&vpath)[1] #define vps2 (&vps1)[1] #define vps4 (&vps2)[1] @@ -1497,46 +1493,48 @@ enum token { enum token_types { UNOP, BINOP, BUNOP, BBINOP, PAREN }; -static struct t_op const ops[] = {{"-r", FILRD, UNOP}, - {"-w", FILWR, UNOP}, - {"-x", FILEX, UNOP}, - {"-e", FILEXIST, UNOP}, - {"-f", FILREG, UNOP}, - {"-d", FILDIR, UNOP}, - {"-c", FILCDEV, UNOP}, - {"-b", FILBDEV, UNOP}, - {"-p", FILFIFO, UNOP}, - {"-u", FILSUID, UNOP}, - {"-g", FILSGID, UNOP}, - {"-k", FILSTCK, UNOP}, - {"-s", FILGZ, UNOP}, - {"-t", FILTT, UNOP}, - {"-z", STREZ, UNOP}, - {"-n", STRNZ, UNOP}, - {"-h", FILSYM, UNOP}, /* for backwards compat */ - {"-O", FILUID, UNOP}, - {"-G", FILGID, UNOP}, - {"-L", FILSYM, UNOP}, - {"-S", FILSOCK, UNOP}, - {"=", STREQ, BINOP}, - {"!=", STRNE, BINOP}, - {"<", STRLT, BINOP}, - {">", STRGT, BINOP}, - {"-eq", INTEQ, BINOP}, - {"-ne", INTNE, BINOP}, - {"-ge", INTGE, BINOP}, - {"-gt", INTGT, BINOP}, - {"-le", INTLE, BINOP}, - {"-lt", INTLT, BINOP}, - {"-nt", FILNT, BINOP}, - {"-ot", FILOT, BINOP}, - {"-ef", FILEQ, BINOP}, - {"!", UNOT, BUNOP}, - {"-a", BAND, BBINOP}, - {"-o", BOR, BBINOP}, - {"(", LPAREN, PAREN}, - {")", RPAREN, PAREN}, - {0, 0, 0}}; +static struct t_op const ops[] = { + {"-r", FILRD, UNOP}, + {"-w", FILWR, UNOP}, + {"-x", FILEX, UNOP}, + {"-e", FILEXIST, UNOP}, + {"-f", FILREG, UNOP}, + {"-d", FILDIR, UNOP}, + {"-c", FILCDEV, UNOP}, + {"-b", FILBDEV, UNOP}, + {"-p", FILFIFO, UNOP}, + {"-u", FILSUID, UNOP}, + {"-g", FILSGID, UNOP}, + {"-k", FILSTCK, UNOP}, + {"-s", FILGZ, UNOP}, + {"-t", FILTT, UNOP}, + {"-z", STREZ, UNOP}, + {"-n", STRNZ, UNOP}, + {"-h", FILSYM, UNOP}, /* for backwards compat */ + {"-O", FILUID, UNOP}, + {"-G", FILGID, UNOP}, + {"-L", FILSYM, UNOP}, + {"-S", FILSOCK, UNOP}, + {"=", STREQ, BINOP}, + {"!=", STRNE, BINOP}, + {"<", STRLT, BINOP}, + {">", STRGT, BINOP}, + {"-eq", INTEQ, BINOP}, + {"-ne", INTNE, BINOP}, + {"-ge", INTGE, BINOP}, + {"-gt", INTGT, BINOP}, + {"-le", INTLE, BINOP}, + {"-lt", INTLT, BINOP}, + {"-nt", FILNT, BINOP}, + {"-ot", FILOT, BINOP}, + {"-ef", FILEQ, BINOP}, + {"!", UNOT, BUNOP}, + {"-a", BAND, BBINOP}, + {"-o", BOR, BBINOP}, + {"(", LPAREN, PAREN}, + {")", RPAREN, PAREN}, + {0, 0, 0}, +}; /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § the unbourne shell » text ─╬─│┼ @@ -3644,7 +3642,7 @@ static int evalcommand(union node *cmd, int flags) { } /* Now locate the command. */ if (cmdentry.cmdtype != CMDBUILTIN || !(cmdentry.u.cmd->flags & BUILTIN_REGULAR)) { - path = unlikely(path != NULL) ? path : pathval(); + path = unlikely(path != NULL) ? path : pathval(); /* wut */ find_command(argv[0], &cmdentry, cmd_flag | DO_ERR, path); } jp = NULL; @@ -4213,21 +4211,21 @@ static void hashcd(void) { * Called with interrupts off. */ static void changepath(const char *newval) { - const char *new; int idx; int bltin; - new = newval; + const char *neu; + neu = newval; idx = 0; bltin = -1; for (;;) { - if (*new == '%' && prefix(new + 1, "builtin")) { + if (*neu == '%' && prefix(neu + 1, "builtin")) { bltin = idx; break; } - new = strchr(new, ':'); - if (!new) break; + neu = strchr(neu, ':'); + if (!neu) break; idx++; - new ++; + neu++; } builtinloc = bltin; clearcmdentry(); @@ -9603,6 +9601,9 @@ static char *conv_escape(char *str, int *conv_ch) { case 'f': value = '\f'; break; /* form-feed */ + case 'e': + value = '\e'; + break; /* escape */ case 'n': value = '\n'; break; /* newline */ @@ -10787,6 +10788,7 @@ static int exitcmd(int argc, char **argv) { */ int main(int argc, char **argv) { showcrashreports(); + unsetenv("PS1"); char *shinit; volatile int state; struct jmploc jmploc; diff --git a/libc/calls/calls.h b/libc/calls/calls.h index 213537bc..ac13bf8e 100644 --- a/libc/calls/calls.h +++ b/libc/calls/calls.h @@ -111,7 +111,7 @@ int fchmod(int, uint32_t) nothrow; int fchmodat(int, const char *, uint32_t, uint32_t); int fchown(int, uint32_t, uint32_t); int fchownat(int, const char *, uint32_t, uint32_t, uint32_t); -int fcntl(); +int fcntl(int, int, ...); int fdatasync(int); int filecmp(const char *, const char *); int flock(int, int); @@ -189,7 +189,7 @@ int uname(struct utsname *); int unlink(const char *); int unlink_s(const char **); int unlinkat(int, const char *, int); -int vfork(void); +int vfork(void) returnstwice; int wait(int *); int wait3(int *, int, struct rusage *); int wait4(int, int *, int, struct rusage *); @@ -242,7 +242,7 @@ int vdprintf(int, const char *, va_list) paramsnonnull(); #if defined(__GNUC__) && !defined(__STRICT_ANSI__) void _init_onntconsoleevent(void); -void _init_onwincrash(void); +void _init_wincrash(void); #define __SIGACTION(FN, SIG, ...) \ ({ \ @@ -260,14 +260,14 @@ void _init_onwincrash(void); case SIGSEGV: \ case SIGABRT: \ case SIGFPE: \ - YOINK(_init_onwincrash); \ + YOINK(_init_wincrash); \ break; \ default: \ break; \ } \ } else { \ YOINK(_init_onntconsoleevent); \ - YOINK(_init_onwincrash); \ + YOINK(_init_wincrash); \ } \ } \ (FN)(SIG, __VA_ARGS__); \ diff --git a/libc/calls/fcntl-nt.c b/libc/calls/fcntl-nt.c index 5eeaf72e..d8ea9889 100644 --- a/libc/calls/fcntl-nt.c +++ b/libc/calls/fcntl-nt.c @@ -24,16 +24,17 @@ #include "libc/sysv/errfuns.h" textwindows int fcntl$nt(int fd, int cmd, unsigned arg) { + uint32_t flags; if (!isfdkind(fd, kFdFile)) return ebadf(); switch (cmd) { case F_GETFD: - return GetHandleInformation(g_fds.p[fd].handle, &arg) ? (arg ^ FD_CLOEXEC) - : -1; + if (!GetHandleInformation(g_fds.p[fd].handle, &flags)) return -1; + arg = (flags & FD_CLOEXEC) ^ FD_CLOEXEC; + return arg; case F_SETFD: - return SetHandleInformation(g_fds.p[fd].handle, FD_CLOEXEC, - arg ^ FD_CLOEXEC) - ? 0 - : -1; + arg ^= FD_CLOEXEC; + if (!SetHandleInformation(g_fds.p[fd].handle, FD_CLOEXEC, arg)) return -1; + return 0; default: return 0; /* TODO(jart): Implement me. */ } diff --git a/libc/calls/fcntl.c b/libc/calls/fcntl.c index 4ef74e4c..f5fec2a8 100644 --- a/libc/calls/fcntl.c +++ b/libc/calls/fcntl.c @@ -31,7 +31,12 @@ * @return 0 on success, or -1 w/ errno * @asyncsignalsafe */ -int fcntl(int fd, int cmd, int arg) { +int fcntl(int fd, int cmd, ...) { + va_list va; + unsigned arg; + va_start(va, cmd); + arg = va_arg(va, unsigned); + va_end(va); if (!IsWindows()) { return fcntl$sysv(fd, cmd, arg); } else { diff --git a/libc/calls/fixntmagicpath.ncabi.c b/libc/calls/fixntmagicpath.ncabi.c deleted file mode 100644 index 9eafb666..00000000 --- a/libc/calls/fixntmagicpath.ncabi.c +++ /dev/null @@ -1,40 +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 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ -│ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ -│ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/internal.h" -#include "libc/calls/ntmagicpaths.h" -#include "libc/nexgen32e/tinystrcmp.h" -#include "libc/sysv/consts/o.h" - -textwindows const char *(fixntmagicpath)(const char *path, unsigned flags) { - const struct NtMagicPaths *mp = &kNtMagicPaths; - asm("" : "+r"(mp)); - if (path[0] != '/') return path; - if (tinystrcmp(path, mp->devtty) == 0) { - if ((flags & O_ACCMODE) == O_RDONLY) { - return mp->conin; - } else if ((flags & O_ACCMODE) == O_WRONLY) { - return mp->conout; - } - } - if (tinystrcmp(path, mp->devnull) == 0) return mp->nul; - if (tinystrcmp(path, mp->devstdin) == 0) return mp->conin; - if (tinystrcmp(path, mp->devstdout) == 0) return mp->conout; - return path; -} diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 48876175..d742e24f 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -261,15 +261,11 @@ void ntcontext2linux(struct ucontext *, const struct NtContext *) hidden; struct NtOverlapped *offset2overlap(int64_t, struct NtOverlapped *) hidden; bool32 ntsetprivilege(i64, const char16_t *, u32) hidden; bool32 onntconsoleevent$nt(u32) hidden; -void onntalarm(void *, uint32_t, uint32_t) hidden; +void __winalarm(void *, uint32_t, uint32_t) hidden; int ntaccesscheck(const char16_t *, u32) paramsnonnull() hidden; i64 ntreturn(u32); i64 winerr(void) nocallback privileged; -const char *__fixntmagicpath(const char *, unsigned) paramsnonnull() hidden; -int __mkntpath(const char *, unsigned, char16_t[hasatleast PATH_MAX - 16]) - paramsnonnull() hidden; - #define mkntpath(PATH, PATH16) mkntpath2(PATH, -1u, PATH16) #define mkntpath2(PATH, FLAGS, PATH16) \ ({ \ @@ -281,16 +277,6 @@ int __mkntpath(const char *, unsigned, char16_t[hasatleast PATH_MAX - 16]) Count; \ }) -#define fixntmagicpath(PATH, FLAGS) \ - ({ \ - const char *Path2; \ - asm("call\tfixntmagicpath" \ - : "=a"(Path2) \ - : "D"(PATH), "S"(FLAGS), "m"((PATH)[0]) \ - : "cc"); \ - Path2; \ - }) - #undef sigset #undef i32 #undef i64 diff --git a/libc/calls/mkntpath.ncabi.c b/libc/calls/mkntpath.ncabi.c index 9ea70ef9..bedd01b5 100644 --- a/libc/calls/mkntpath.ncabi.c +++ b/libc/calls/mkntpath.ncabi.c @@ -17,15 +17,31 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/bits/pushpop.h" -#include "libc/bits/safemacros.h" -#include "libc/calls/hefty/ntspawn.h" -#include "libc/calls/internal.h" -#include "libc/conv/conv.h" +#include "libc/calls/ntmagicpaths.h" +#include "libc/nexgen32e/tinystrcmp.h" #include "libc/str/str.h" #include "libc/str/tpdecode.h" +#include "libc/sysv/consts/o.h" #include "libc/sysv/errfuns.h" +textwindows static const char *FixNtMagicPath(const char *path, + unsigned flags) { + const struct NtMagicPaths *mp = &kNtMagicPaths; + asm("" : "+r"(mp)); + if (path[0] != '/') return path; + if (tinystrcmp(path, mp->devtty) == 0) { + if ((flags & O_ACCMODE) == O_RDONLY) { + return mp->conin; + } else if ((flags & O_ACCMODE) == O_WRONLY) { + return mp->conout; + } + } + if (tinystrcmp(path, mp->devnull) == 0) return mp->nul; + if (tinystrcmp(path, mp->devstdin) == 0) return mp->conin; + if (tinystrcmp(path, mp->devstdout) == 0) return mp->conout; + return path; +} + /** * Copies path for Windows NT. * @@ -33,13 +49,13 @@ * forward-slashes with backslashes; and (3) remapping several * well-known paths (e.g. /dev/null → NUL) for convenience. * + * @param flags is used by open() * @param path16 is shortened so caller can prefix, e.g. \\.\pipe\, and * due to a plethora of special-cases throughout the Win32 API - * @param flags is used by open(), see fixntmagicpath2() * @return short count excluding NUL on success, or -1 w/ errno * @error ENAMETOOLONG */ -forcealignargpointer textwindows int(mkntpath)( +forcealignargpointer textwindows int mkntpath( const char *path, unsigned flags, char16_t path16[hasatleast PATH_MAX - 16]) { /* @@ -52,7 +68,7 @@ forcealignargpointer textwindows int(mkntpath)( int rc; wint_t wc; size_t i, j; - path = fixntmagicpath(path, flags); + path = FixNtMagicPath(path, flags); i = 0; j = 0; for (;;) { diff --git a/libc/calls/setitimer-nt.c b/libc/calls/setitimer-nt.c index 9ddbd269..38c9bc87 100644 --- a/libc/calls/setitimer-nt.c +++ b/libc/calls/setitimer-nt.c @@ -55,7 +55,7 @@ static struct ItimerNt { static uint32_t ItimerWorker(void *arg) { do { if (!WaitForSingleObject(g_itimernt.ith, -1)) { - onntalarm(NULL, 0, 0); + __winalarm(NULL, 0, 0); } } while (g_itimernt.ith && g_itimernt.tid == GetCurrentThreadId()); return 0; diff --git a/libc/calls/thunks/onntconsoleevent.S b/libc/calls/thunks/onntconsoleevent.S index 6a220f36..8a5ef9d4 100644 --- a/libc/calls/thunks/onntconsoleevent.S +++ b/libc/calls/thunks/onntconsoleevent.S @@ -23,5 +23,5 @@ onntconsoleevent$nt: ezlea onntconsoleevent,ax - jmp nt2sysv + jmp __nt2sysv .endfn onntconsoleevent$nt,globl,hidden diff --git a/libc/calls/thunks/onwincrash.S b/libc/calls/thunks/onwincrash.S index 07666d83..656b3621 100644 --- a/libc/calls/thunks/onwincrash.S +++ b/libc/calls/thunks/onwincrash.S @@ -21,7 +21,7 @@ .text.windows .source __FILE__ -onwincrash$nt: - ezlea onwincrash,ax - jmp nt2sysv - .endfn onwincrash$nt,globl +__wincrash$nt: + ezlea __wincrash,ax + jmp __nt2sysv + .endfn __wincrash$nt,globl diff --git a/libc/calls/thunks/onntalarm.S b/libc/calls/thunks/winalarm.S similarity index 95% rename from libc/calls/thunks/onntalarm.S rename to libc/calls/thunks/winalarm.S index 2018eddd..f30d49a3 100644 --- a/libc/calls/thunks/onntalarm.S +++ b/libc/calls/thunks/winalarm.S @@ -21,7 +21,7 @@ .text.windows .source __FILE__ -onntalarm$nt: - ezlea onntalarm,ax - jmp nt2sysv - .endfn onntalarm$nt,globl,hidden +__winalarm$nt: + ezlea __winalarm,ax + jmp __nt2sysv + .endfn __winalarm$nt,globl,hidden diff --git a/libc/calls/onntalarm.c b/libc/calls/winalarm.c similarity index 94% rename from libc/calls/onntalarm.c rename to libc/calls/winalarm.c index a8b19efc..bd36469f 100644 --- a/libc/calls/onntalarm.c +++ b/libc/calls/winalarm.c @@ -22,8 +22,8 @@ #include "libc/str/str.h" #include "libc/sysv/consts/sig.h" -void onntalarm(void *lpArgToCompletionRoutine, uint32_t dwTimerLowValue, - uint32_t dwTimerHighValue) { +void __winalarm(void *lpArgToCompletionRoutine, uint32_t dwTimerLowValue, + uint32_t dwTimerHighValue) { siginfo_t info; memset(&info, 0, sizeof(info)); info.si_signo = SIGALRM; diff --git a/libc/calls/onwincrash.c b/libc/calls/wincrash.c similarity index 98% rename from libc/calls/onwincrash.c rename to libc/calls/wincrash.c index 264c8a69..fddb6186 100644 --- a/libc/calls/onwincrash.c +++ b/libc/calls/wincrash.c @@ -27,7 +27,7 @@ #include "libc/str/str.h" #include "libc/sysv/consts/sig.h" -textwindows unsigned onwincrash(struct NtExceptionPointers *ep) { +textwindows unsigned __wincrash(struct NtExceptionPointers *ep) { int sig; struct Goodies { ucontext_t ctx; diff --git a/libc/calls/onwincrash_init.S b/libc/calls/wincrash_init.S similarity index 95% rename from libc/calls/onwincrash_init.S rename to libc/calls/wincrash_init.S index f2e30d31..0f274ef6 100644 --- a/libc/calls/onwincrash_init.S +++ b/libc/calls/wincrash_init.S @@ -20,8 +20,8 @@ #include "libc/macros.h" .source __FILE__ - .init.start 300,_init_onwincrash + .init.start 300,_init_wincrash pushpop 1,%rcx - ezlea onwincrash$nt,dx + ezlea __wincrash$nt,dx ntcall __imp_AddVectoredExceptionHandler - .init.end 300,_init_onwincrash,globl,hidden + .init.end 300,_init_wincrash,globl,hidden diff --git a/libc/crt/crt.S b/libc/crt/crt.S index 233030a4..050669d1 100644 --- a/libc/crt/crt.S +++ b/libc/crt/crt.S @@ -54,9 +54,8 @@ _start: test %rdi,%rdi mov %rdi,%rcx # auxv mov %ebx,%edi call _executive -9: .endfn _start,weak,hidden - - ud2 +9: ud2 + .endfn _start,weak,hidden / Macintosh userspace program entrypoint. / diff --git a/libc/dns/getaddrinfo.c b/libc/dns/getaddrinfo.c index 94ae3541..6f523a74 100644 --- a/libc/dns/getaddrinfo.c +++ b/libc/dns/getaddrinfo.c @@ -35,7 +35,7 @@ /** * Resolves address for internet name. * - * @param node is either an ip string or a utf-8 hostname + * @param name is either an ip string or a utf-8 hostname * @param service is the port number as a string * @param hints may be passed to specialize behavior (optional) * @param res receives a pointer that must be freed with freeaddrinfo(), diff --git a/libc/errno.h b/libc/errno.h index d37c319b..935ba526 100644 --- a/libc/errno.h +++ b/libc/errno.h @@ -6,137 +6,137 @@ * @see libc/sysv/consts.sh for numbers */ -#define EPERM EPERM /* operation not permitted */ -#define ENOENT ENOENT /* no such file or directory */ -#define ESRCH ESRCH /* no such process */ -#define EINTR EINTR /* interrupted system call */ -#define EIO EIO /* input/output error */ -#define ENXIO ENXIO /* no such device or address */ -#define E2BIG E2BIG /* argument list too long */ -#define ENOEXEC ENOEXEC /* exec format error */ -#define EBADF EBADF /* bad file descriptor */ -#define ECHILD ECHILD /* no child processes */ -#define EAGAIN EAGAIN /* resource temporarily unavailable */ -#define ENOMEM ENOMEM /* not enough space */ -#define EACCES EACCES /* permission denied */ -#define EFAULT EFAULT /* bad address */ -#define ENOTBLK ENOTBLK /* block device required */ -#define EBUSY EBUSY /* device or resource busy */ -#define EEXIST EEXIST /* file exists */ -#define EXDEV EXDEV /* improper link */ -#define ENODEV ENODEV /* no such device */ -#define ENOTDIR ENOTDIR /* not a directory */ -#define EISDIR EISDIR /* is a directory */ -#define EINVAL EINVAL /* invalid argument */ -#define ENFILE ENFILE /* too many open files in system */ -#define EMFILE EMFILE /* too many open files */ -#define ENOTTY ENOTTY /* inappropriate I/O control op */ -#define ETXTBSY ETXTBSY /* text file busy */ -#define EFBIG EFBIG /* file too large */ -#define ENOSPC ENOSPC /* no space left on device */ -#define ESPIPE ESPIPE /* invalid seek */ -#define EROFS EROFS /* read-only filesystem */ -#define EMLINK EMLINK /* too many links */ -#define EPIPE EPIPE /* broken pipe */ -#define EDOM EDOM /* argument out of function domain */ -#define ERANGE ERANGE /* result too large */ -#define EDEADLK EDEADLK /* resource deadlock avoided */ -#define ENAMETOOLONG ENAMETOOLONG /* filename too long */ -#define ENOLCK ENOLCK /* no locks available */ -#define ENOSYS ENOSYS /* system call not implemented */ -#define ENOTEMPTY ENOTEMPTY /* directory not empty */ -#define ELOOP ELOOP /* too many levels of symbolic links */ -#define ENOMSG ENOMSG /* no message of the desired type */ -#define EIDRM EIDRM /* identifier removed */ -#define ECHRNG ECHRNG /* channel number out of range */ -#define EL2NSYNC EL2NSYNC /* level 2 not synchronized */ -#define EL3HLT EL3HLT /* level 3 halted */ -#define EL3RST EL3RST /* level 3 halted */ -#define ELNRNG ELNRNG /* link number out of range */ -#define EUNATCH EUNATCH /* protocol driver not attached */ -#define ENOCSI ENOCSI /* no csi structure available */ -#define EL2HLT EL2HLT /* level 2 halted */ -#define EBADE EBADE /* invalid exchange */ -#define EBADR EBADR /* invalid request descriptor */ -#define EXFULL EXFULL /* exchange full */ -#define ENOANO ENOANO /* no anode */ -#define EBADRQC EBADRQC /* invalid request code */ -#define EBADSLT EBADSLT /* invalid slot */ -#define ENOSTR ENOSTR /* no string */ -#define ENODATA ENODATA /* no data */ -#define ETIME ETIME /* timer expired */ -#define ENOSR ENOSR /* out of streams resources */ -#define ENONET ENONET /* no network */ -#define ENOPKG ENOPKG /* package not installed */ -#define EREMOTE EREMOTE /* object is remote */ -#define ENOLINK ENOLINK /* link severed */ -#define EADV EADV /* todo */ -#define ESRMNT ESRMNT /* todo */ -#define ECOMM ECOMM /* communication error on send */ -#define EPROTO EPROTO /* protocol error */ -#define EMULTIHOP EMULTIHOP /* multihop attempted */ -#define EDOTDOT EDOTDOT /* todo */ -#define EBADMSG EBADMSG /* bad message */ -#define EOVERFLOW EOVERFLOW /* value too large for type */ -#define ENOTUNIQ ENOTUNIQ /* name not unique on network */ -#define EBADFD EBADFD /* fd in bad *state* (cf. EBADF) */ -#define EREMCHG EREMCHG /* remote address changed */ -#define ELIBACC ELIBACC /* cannot access dso */ -#define ELIBBAD ELIBBAD /* corrupted shared library */ -#define ELIBSCN ELIBSCN /* a.out section corrupted */ -#define ELIBMAX ELIBMAX /* too many shared libraries */ -#define ELIBEXEC ELIBEXEC /* cannot exec a dso directly */ -#define EILSEQ EILSEQ /* invalid wide character */ -#define ERESTART ERESTART /* please restart syscall */ -#define ESTRPIPE ESTRPIPE /* streams pipe error */ -#define EUSERS EUSERS /* too many users */ -#define ENOTSOCK ENOTSOCK /* not a socket */ -#define EDESTADDRREQ EDESTADDRREQ /* dest address needed */ -#define EMSGSIZE EMSGSIZE /* message too long */ -#define EPROTOTYPE EPROTOTYPE /* protocol wrong for socket */ -#define ENOPROTOOPT ENOPROTOOPT /* protocol not available */ -#define EPROTONOSUPPORT EPROTONOSUPPORT /* protocol not supported */ -#define ESOCKTNOSUPPORT ESOCKTNOSUPPORT /* socket type not supported */ -#define EOPNOTSUPP EOPNOTSUPP /* operation not supported on socket */ -#define EPFNOSUPPORT EPFNOSUPPORT /* protocol family not supported */ -#define EAFNOSUPPORT EAFNOSUPPORT /* address family not supported */ -#define EADDRINUSE EADDRINUSE /* address already in use */ -#define EADDRNOTAVAIL EADDRNOTAVAIL /* address not available */ -#define ENETDOWN ENETDOWN /* network is down */ -#define ENETUNREACH ENETUNREACH /* network unreachable */ -#define ENETRESET ENETRESET /* connection aborted by network */ -#define ECONNABORTED ECONNABORTED /* connection aborted */ -#define ECONNRESET ECONNRESET /* connection reset */ -#define ENOBUFS ENOBUFS /* no buffer space available */ -#define EISCONN EISCONN /* socket is connected */ -#define ENOTCONN ENOTCONN /* the socket is not connected */ -#define ESHUTDOWN ESHUTDOWN /* no send after endpoint shutdown */ -#define ETOOMANYREFS ETOOMANYREFS /* too many refs */ -#define ETIMEDOUT ETIMEDOUT /* connection timed out */ -#define ECONNREFUSED ECONNREFUSED /* connection refused */ -#define EHOSTDOWN EHOSTDOWN /* host is down */ -#define EHOSTUNREACH EHOSTUNREACH /* host is unreachable */ -#define EALREADY EALREADY /* connection already in progress */ -#define EINPROGRESS EINPROGRESS /* operation in progress */ -#define ESTALE ESTALE /* stale file handle */ -#define EUCLEAN EUCLEAN /* structure needs cleaning */ -#define ENOTNAM ENOTNAM /* todo */ -#define ENAVAIL ENAVAIL /* todo */ -#define EISNAM EISNAM /* is a named type file */ -#define EREMOTEIO EREMOTEIO /* remote i/o error */ -#define EDQUOT EDQUOT /* disk quota exceeded */ -#define ENOMEDIUM ENOMEDIUM /* no medium found */ -#define EMEDIUMTYPE EMEDIUMTYPE /* wrong medium type */ -#define ECANCELED ECANCELED /* operation canceled */ -#define ENOKEY ENOKEY /* required key not available */ -#define EKEYEXPIRED EKEYEXPIRED /* key has expired */ -#define EKEYREVOKED EKEYREVOKED /* key has been revoked */ -#define EKEYREJECTED EKEYREJECTED /* key was rejected by service */ -#define EOWNERDEAD EOWNERDEAD /* owner died */ -#define ENOTRECOVERABLE ENOTRECOVERABLE /* state not recoverable */ -#define ERFKILL ERFKILL /* can't op b/c RF-kill */ -#define EHWPOISON EHWPOISON /* mempage has h/w error */ -#define EWOULDBLOCK EAGAIN /* poll fd and try again */ +#define EPERM EPERM // operation not permitted +#define ENOENT ENOENT // no such file or directory +#define ESRCH ESRCH // no such process +#define EINTR EINTR // interrupted system call +#define EIO EIO // input/output error +#define ENXIO ENXIO // no such device or address +#define E2BIG E2BIG // argument list too long +#define ENOEXEC ENOEXEC // exec format error +#define EBADF EBADF // bad file descriptor +#define ECHILD ECHILD // no child processes +#define EAGAIN EAGAIN // resource temporarily unavailable +#define ENOMEM ENOMEM // not enough space +#define EACCES EACCES // permission denied +#define EFAULT EFAULT // bad address +#define ENOTBLK ENOTBLK // block device required +#define EBUSY EBUSY // device or resource busy +#define EEXIST EEXIST // file exists +#define EXDEV EXDEV // improper link +#define ENODEV ENODEV // no such device +#define ENOTDIR ENOTDIR // not a directory +#define EISDIR EISDIR // is a directory +#define EINVAL EINVAL // invalid argument +#define ENFILE ENFILE // too many open files in system +#define EMFILE EMFILE // too many open files +#define ENOTTY ENOTTY // inappropriate I/O control op +#define ETXTBSY ETXTBSY // text file busy +#define EFBIG EFBIG // file too large +#define ENOSPC ENOSPC // no space left on device +#define ESPIPE ESPIPE // invalid seek +#define EROFS EROFS // read-only filesystem +#define EMLINK EMLINK // too many links +#define EPIPE EPIPE // broken pipe +#define EDOM EDOM // argument out of function domain +#define ERANGE ERANGE // result too large +#define EDEADLK EDEADLK // resource deadlock avoided +#define ENAMETOOLONG ENAMETOOLONG // filename too long +#define ENOLCK ENOLCK // no locks available +#define ENOSYS ENOSYS // system call not implemented +#define ENOTEMPTY ENOTEMPTY // directory not empty +#define ELOOP ELOOP // too many levels of symbolic links +#define ENOMSG ENOMSG // no message of the desired type +#define EIDRM EIDRM // identifier removed +#define ECHRNG ECHRNG // channel number out of range +#define EL2NSYNC EL2NSYNC // level 2 not synchronized +#define EL3HLT EL3HLT // level 3 halted +#define EL3RST EL3RST // level 3 halted +#define ELNRNG ELNRNG // link number out of range +#define EUNATCH EUNATCH // protocol driver not attached +#define ENOCSI ENOCSI // no csi structure available +#define EL2HLT EL2HLT // level 2 halted +#define EBADE EBADE // invalid exchange +#define EBADR EBADR // invalid request descriptor +#define EXFULL EXFULL // exchange full +#define ENOANO ENOANO // no anode +#define EBADRQC EBADRQC // invalid request code +#define EBADSLT EBADSLT // invalid slot +#define ENOSTR ENOSTR // no string +#define ENODATA ENODATA // no data +#define ETIME ETIME // timer expired +#define ENOSR ENOSR // out of streams resources +#define ENONET ENONET // no network +#define ENOPKG ENOPKG // package not installed +#define EREMOTE EREMOTE // object is remote +#define ENOLINK ENOLINK // link severed +#define EADV EADV // todo +#define ESRMNT ESRMNT // todo +#define ECOMM ECOMM // communication error on send +#define EPROTO EPROTO // protocol error +#define EMULTIHOP EMULTIHOP // multihop attempted +#define EDOTDOT EDOTDOT // todo +#define EBADMSG EBADMSG // bad message +#define EOVERFLOW EOVERFLOW // value too large for type +#define ENOTUNIQ ENOTUNIQ // name not unique on network +#define EBADFD EBADFD // fd in bad *state* (cf. EBADF) +#define EREMCHG EREMCHG // remote address changed +#define ELIBACC ELIBACC // cannot access dso +#define ELIBBAD ELIBBAD // corrupted shared library +#define ELIBSCN ELIBSCN // a.out section corrupted +#define ELIBMAX ELIBMAX // too many shared libraries +#define ELIBEXEC ELIBEXEC // cannot exec a dso directly +#define EILSEQ EILSEQ // invalid wide character +#define ERESTART ERESTART // please restart syscall +#define ESTRPIPE ESTRPIPE // streams pipe error +#define EUSERS EUSERS // too many users +#define ENOTSOCK ENOTSOCK // not a socket +#define EDESTADDRREQ EDESTADDRREQ // dest address needed +#define EMSGSIZE EMSGSIZE // message too long +#define EPROTOTYPE EPROTOTYPE // protocol wrong for socket +#define ENOPROTOOPT ENOPROTOOPT // protocol not available +#define EPROTONOSUPPORT EPROTONOSUPPORT // protocol not supported +#define ESOCKTNOSUPPORT ESOCKTNOSUPPORT // socket type not supported +#define EOPNOTSUPP EOPNOTSUPP // operation not supported on socket +#define EPFNOSUPPORT EPFNOSUPPORT // protocol family not supported +#define EAFNOSUPPORT EAFNOSUPPORT // address family not supported +#define EADDRINUSE EADDRINUSE // address already in use +#define EADDRNOTAVAIL EADDRNOTAVAIL // address not available +#define ENETDOWN ENETDOWN // network is down +#define ENETUNREACH ENETUNREACH // network unreachable +#define ENETRESET ENETRESET // connection aborted by network +#define ECONNABORTED ECONNABORTED // connection aborted +#define ECONNRESET ECONNRESET // connection reset +#define ENOBUFS ENOBUFS // no buffer space available +#define EISCONN EISCONN // socket is connected +#define ENOTCONN ENOTCONN // the socket is not connected +#define ESHUTDOWN ESHUTDOWN // no send after endpoint shutdown +#define ETOOMANYREFS ETOOMANYREFS // too many refs +#define ETIMEDOUT ETIMEDOUT // connection timed out +#define ECONNREFUSED ECONNREFUSED // connection refused +#define EHOSTDOWN EHOSTDOWN // host is down +#define EHOSTUNREACH EHOSTUNREACH // host is unreachable +#define EALREADY EALREADY // connection already in progress +#define EINPROGRESS EINPROGRESS // operation in progress +#define ESTALE ESTALE // stale file handle +#define EUCLEAN EUCLEAN // structure needs cleaning +#define ENOTNAM ENOTNAM // todo +#define ENAVAIL ENAVAIL // todo +#define EISNAM EISNAM // is a named type file +#define EREMOTEIO EREMOTEIO // remote i/o error +#define EDQUOT EDQUOT // disk quota exceeded +#define ENOMEDIUM ENOMEDIUM // no medium found +#define EMEDIUMTYPE EMEDIUMTYPE // wrong medium type +#define ECANCELED ECANCELED // operation canceled +#define ENOKEY ENOKEY // required key not available +#define EKEYEXPIRED EKEYEXPIRED // key has expired +#define EKEYREVOKED EKEYREVOKED // key has been revoked +#define EKEYREJECTED EKEYREJECTED // key was rejected by service +#define EOWNERDEAD EOWNERDEAD // owner died +#define ENOTRECOVERABLE ENOTRECOVERABLE // state not recoverable +#define ERFKILL ERFKILL // can't op b/c RF-kill +#define EHWPOISON EHWPOISON // mempage has h/w error +#define EWOULDBLOCK EAGAIN // poll fd and try again #define ENOTSUP ENOTSUP #if !(__ASSEMBLER__ + __LINKER__ + 0) diff --git a/libc/escape/aescape.c b/libc/escape/aescape.c deleted file mode 100644 index e24e8e25..00000000 --- a/libc/escape/aescape.c +++ /dev/null @@ -1,47 +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 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ -│ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ -│ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" -#include "libc/escape/escape.h" -#include "libc/mem/mem.h" -#include "libc/runtime/runtime.h" - -/** - * Internal function aspecting escaping ops with allocating behavior. - * @see aescapesh(), aescapec() - */ -int aescape(char **escaped, size_t size, const char *unescaped, unsigned length, - int impl(char *escaped, unsigned size, const char *unescaped, - unsigned length)) { - int wrote; - char *p2; - if ((p2 = realloc(*escaped, size)) != NULL) { - *escaped = p2; - if ((wrote = impl(*escaped, size, unescaped, length)) != -1) { - if ((unsigned)wrote <= size - 1) { - return wrote; - } else { - assert(__builtin_return_address(0) != aescape); - return aescape(escaped, wrote + 1, unescaped, length, impl); - } - } - } - free_s(escaped); - return -1; -} diff --git a/libc/escape/cunescape.c b/libc/escape/cunescape.c deleted file mode 100644 index e2df221e..00000000 --- a/libc/escape/cunescape.c +++ /dev/null @@ -1,64 +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 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ -│ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ -│ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/escape/escape.h" -#include "libc/macros.h" -#include "libc/str/str.h" - -// TODO(jart): implement me - -/** - * Decodes backslash escape sequences in-place. - * - * We support the C standard definitions, and the gotchas that entails: - * - * \newline ← noop for multi-line str - * \' \" \? \\ ← we try hard to avoid \? - * \a \b \f \n \r \t \v \e ← \e is A++ GNU extension - * \ octal-digit ← base-8 literal encoding - * \ octal-digit octal-digit ← octal: super dependable - * \ octal-digit octal-digit octal-digit ← longstanding DEC legacy - * \x[0-9A-Fa-f]+ ← base16 literal encoding - * \u[0-9A-Fa-f]{4} ← UNICODEs - * \U[0-9A-Fa-f]{8} (astral planes) ← UNICODEs: Astral Planes - * - * @param n is # bytes in p - * @param p is byte array of string literal content - * @return new byte size of s, or -i to indicate first error at s[i] - * @note we do not check for NUL terminator on input - * @note array is zero-filled if shortened - * @see cescapec(), strlen() - */ -int cunescape(size_t n, char p[n]) { - unsigned char t[32]; - unsigned i, j, m, tc, tn, mask; - for (m = n, i = 0; i < n; i += j) { - tc = sizeof(t); - tn = MIN(m - i, tc); - memset(t, 0, tc); - memcpy(t, p + i, tn); - for (mask = j = 0; j < tc; ++j) { - if (p[j] == '\\') mask |= 1u << j; - } - if (j < ARRAYLEN(t)) { - memcpy(p + i, t, tn); - } - } - return m; -} diff --git a/libc/escape/escape.h b/libc/escape/escape.h deleted file mode 100644 index 75340045..00000000 --- a/libc/escape/escape.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_ESCAPE_ESCAPE_H_ -#define COSMOPOLITAN_LIBC_ESCAPE_ESCAPE_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) -COSMOPOLITAN_C_START_ - -/*───────────────────────────────────────────────────────────────────────────│─╗ -│ cosmopolitan § escaping ─╬─│┼ -╚────────────────────────────────────────────────────────────────────────────│*/ - -unsigned cescapec(int); -int escapec(char *, unsigned, const char *, unsigned) - paramsnonnull((3)) nothrow nocallback; -int escapesh(char *, unsigned, const char *, unsigned) paramsnonnull((3)); -bool escapedos(char16_t *, unsigned, const char16_t *, unsigned); -int aescapec(char **, const char *, unsigned) paramsnonnull(); -int aescapesh(char **, const char *, unsigned) paramsnonnull(); -int aescape(char **, size_t, const char *, unsigned, - int (*)(char *, unsigned, const char *, unsigned)) hidden; - -COSMOPOLITAN_C_END_ -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_ESCAPE_ESCAPE_H_ */ diff --git a/libc/escape/escape.mk b/libc/escape/escape.mk deleted file mode 100644 index 35f494a7..00000000 --- a/libc/escape/escape.mk +++ /dev/null @@ -1,57 +0,0 @@ -#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐ -#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘ - -PKGS += LIBC_ESCAPE - -LIBC_ESCAPE_ARTIFACTS += LIBC_ESCAPE_A -LIBC_ESCAPE = $(LIBC_ESCAPE_A_DEPS) $(LIBC_ESCAPE_A) -LIBC_ESCAPE_A = o/$(MODE)/libc/escape/escape.a -LIBC_ESCAPE_A_FILES := $(wildcard libc/escape/*) -LIBC_ESCAPE_A_HDRS = $(filter %.h,$(LIBC_ESCAPE_A_FILES)) -LIBC_ESCAPE_A_SRCS_S = $(filter %.S,$(LIBC_ESCAPE_A_FILES)) -LIBC_ESCAPE_A_SRCS_C = $(filter %.c,$(LIBC_ESCAPE_A_FILES)) - -LIBC_ESCAPE_A_SRCS = \ - $(LIBC_ESCAPE_A_SRCS_S) \ - $(LIBC_ESCAPE_A_SRCS_C) - -LIBC_ESCAPE_A_OBJS = \ - $(LIBC_ESCAPE_A_SRCS:%=o/$(MODE)/%.zip.o) \ - $(LIBC_ESCAPE_A_SRCS_S:%.S=o/$(MODE)/%.o) \ - $(LIBC_ESCAPE_A_SRCS_C:%.c=o/$(MODE)/%.o) - -LIBC_ESCAPE_A_CHECKS = \ - $(LIBC_ESCAPE_A).pkg \ - $(LIBC_ESCAPE_A_HDRS:%=o/$(MODE)/%.ok) - -LIBC_ESCAPE_A_DIRECTDEPS = \ - LIBC_MEM \ - LIBC_NEXGEN32E \ - LIBC_RUNTIME \ - LIBC_STR \ - LIBC_STUBS \ - LIBC_SYSV - -LIBC_ESCAPE_A_DEPS := \ - $(call uniq,$(foreach x,$(LIBC_ESCAPE_A_DIRECTDEPS),$($(x)))) - -$(LIBC_ESCAPE_A): \ - libc/escape/ \ - $(LIBC_ESCAPE_A).pkg \ - $(LIBC_ESCAPE_A_OBJS) - -$(LIBC_ESCAPE_A).pkg: \ - $(LIBC_ESCAPE_A_OBJS) \ - $(foreach x,$(LIBC_ESCAPE_A_DIRECTDEPS),$($(x)_A).pkg) - -LIBC_ESCAPE_LIBS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x))) -LIBC_ESCAPE_SRCS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_SRCS)) -LIBC_ESCAPE_HDRS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_HDRS)) -LIBC_ESCAPE_BINS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_BINS)) -LIBC_ESCAPE_CHECKS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_CHECKS)) -LIBC_ESCAPE_OBJS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_OBJS)) -LIBC_ESCAPE_TESTS = $(foreach x,$(LIBC_ESCAPE_ARTIFACTS),$($(x)_TESTS)) -$(LIBC_ESCAPE_OBJS): $(BUILD_FILES) libc/escape/escape.mk - -.PHONY: o/$(MODE)/libc/escape -o/$(MODE)/libc/escape: $(LIBC_ESCAPE_CHECKS) diff --git a/libc/escape/escapesh.c b/libc/escape/escapesh.c deleted file mode 100644 index b956f2fa..00000000 --- a/libc/escape/escapesh.c +++ /dev/null @@ -1,73 +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 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ -│ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ -│ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" -#include "libc/bits/bits.h" -#include "libc/bits/safemacros.h" -#include "libc/dce.h" -#include "libc/escape/escape.h" -#include "libc/limits.h" -#include "libc/runtime/runtime.h" -#include "libc/sysv/errfuns.h" - -#define SHQUOTE_PUTCHAR(c) \ - do { \ - if (buf != NULL && j < size - 1) { \ - buf[j] = (c); \ - } \ - j++; \ - } while (0) - -/** - * Quotes memory for inclusion in single-quoted SystemV string literals. - * - * The outer quotation marks are *not* added. - * - * @param buf is the output area, which can't overlap and, no matter - * what, a NUL-terminator will always be placed in the buffer at - * an appropriate place, provided buf!=NULL && size!=0 - * @param size is the byte-length of the output area - * @param s is the data, which may have NUL characters - * @param l is the byte-length of s - * @return number of characters written, excluding NUL terminator; or, - * if the output buffer wasn't passed, or was too short, then the - * number of characters that *would* have been written is returned; - * since that's how the snprintf() API works; and never < 0 - * @see xaescapesh() for an easier api - */ -int escapesh(char *buf, unsigned size, const char *s, unsigned l) { - assert(size <= INT_MAX && l <= INT_MAX); - if (!IsTrustworthy() && l >= INT_MAX) abort(); - unsigned j = 0; - for (unsigned i = 0; i < l; ++i) { - if (s[i] != '\'') { - SHQUOTE_PUTCHAR(s[i]); - } else { - const char *const s2 = "'\"'\"'"; - unsigned l2 = 5; - for (unsigned k = 0; k < l2; ++k) { - SHQUOTE_PUTCHAR(s2[k]); - } - } - } - if (buf && size) { - buf[min(j, size - 1)] = '\0'; - } - return j; -} diff --git a/libc/fmt/palandprintf.c b/libc/fmt/palandprintf.c index dd0012aa..bf73e7fc 100644 --- a/libc/fmt/palandprintf.c +++ b/libc/fmt/palandprintf.c @@ -39,7 +39,6 @@ #include "libc/bits/bits.h" #include "libc/bits/weaken.h" #include "libc/conv/conv.h" -#include "libc/escape/escape.h" #include "libc/fmt/fmt.h" #include "libc/fmt/paland.inc" #include "libc/fmt/palandprintf.h" @@ -58,7 +57,7 @@ static int ppatoi(const char **str) { } /** - * Implements {,v}{,s{,n},{,{,x}as},f,d}printf state machine. + * Implements {,v}{,s{,n},{,{,x}as},f,d}printf domain-specific language. * * Type Specifiers * diff --git a/libc/fmt/stoa.c b/libc/fmt/stoa.c index 1cd3b627..4f93c837 100644 --- a/libc/fmt/stoa.c +++ b/libc/fmt/stoa.c @@ -18,7 +18,6 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/weaken.h" -#include "libc/escape/escape.h" #include "libc/fmt/paland.inc" #include "libc/fmt/palandprintf.h" #include "libc/nexgen32e/tinystrlen.h" diff --git a/libc/fmt/strerror_r.c b/libc/fmt/strerror_r.c index b5013f2c..436876f8 100644 --- a/libc/fmt/strerror_r.c +++ b/libc/fmt/strerror_r.c @@ -35,7 +35,7 @@ const char *geterrname(int code) { n = &EXFULL + 1 - e; for (i = 0; i < n; ++i) { if (code == e[i]) { - return indexdoublenulstring(kErrnoNames, i); + return IndexDoubleNulString(kErrnoNames, i); } } return NULL; diff --git a/libc/log/asan.c b/libc/log/asan.c index 03d665c2..6b0cbe8d 100644 --- a/libc/log/asan.c +++ b/libc/log/asan.c @@ -22,9 +22,11 @@ #include "libc/conv/itoa.h" #include "libc/log/asan.h" #include "libc/log/backtrace.h" +#include "libc/log/log.h" #include "libc/mem/hook/hook.h" #include "libc/runtime/directmap.h" #include "libc/runtime/memtrack.h" +#include "libc/runtime/runtime.h" #include "libc/sysv/consts/fileno.h" #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/prot.h" @@ -144,16 +146,23 @@ static const char *__asan_describe_access_poison(int c) { static noreturn void __asan_die(const char *msg, size_t size) { write(STDERR_FILENO, msg, size); - PrintBacktraceUsingSymbols(STDERR_FILENO, __builtin_frame_address(0), - GetSymbolTable()); - DebugBreak(); - _Exit(66); + die(); +} + +static char *__asan_report_start(char *p) { + bool ansi; + const char *term; + term = getenv("TERM"); + ansi = !term || strcmp(term, "dumb") != 0; + if (ansi) p = stpcpy(p, "\r\e[J\e[1;91m"); + p = stpcpy(p, "asan error"); + if (ansi) p = stpcpy(p, "\e[0m"); + return stpcpy(p, ": "); } static noreturn void __asan_report_deallocate_fault(void *addr, int c) { char *p, ibuf[21], buf[256]; - p = buf; - p = stpcpy(p, "error: "); + p = __asan_report_start(buf); p = stpcpy(p, __asan_dscribe_free_poison(c)); p = stpcpy(p, " "); p = mempcpy(p, ibuf, int64toarray_radix10(c, ibuf)); @@ -166,8 +175,7 @@ static noreturn void __asan_report_deallocate_fault(void *addr, int c) { static noreturn void __asan_report_memory_fault(uint8_t *addr, int size, const char *kind) { char *p, ibuf[21], buf[256]; - p = buf; - p = stpcpy(p, "error: "); + p = __asan_report_start(buf); p = stpcpy(p, __asan_describe_access_poison(*(char *)SHADOW((intptr_t)addr))); p = stpcpy(p, " "); p = mempcpy(p, ibuf, uint64toarray_radix10(size, ibuf)); diff --git a/libc/log/checkfail.c b/libc/log/checkfail.c index d4ff2649..0f8eba1d 100644 --- a/libc/log/checkfail.c +++ b/libc/log/checkfail.c @@ -19,17 +19,19 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/bits/bits.h" #include "libc/bits/safemacros.h" +#include "libc/calls/calls.h" #include "libc/dce.h" #include "libc/errno.h" #include "libc/fmt/fmt.h" #include "libc/log/check.h" +#include "libc/log/color.h" #include "libc/log/internal.h" #include "libc/log/log.h" #include "libc/runtime/memtrack.h" #include "libc/runtime/runtime.h" -#include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/auxv.h" +#include "libc/sysv/consts/fileno.h" STATIC_YOINK("ntoa"); STATIC_YOINK("stoa"); @@ -46,12 +48,12 @@ relegated void __check_fail(const char *suffix, const char *opstr, va_list va; char sufbuf[8]; int lasterr = errno; - startfatal(file, line); + __start_fatal(file, line); if (!memccpy(sufbuf, suffix, '\0', sizeof(sufbuf))) strcpy(sufbuf, "?"); strtoupper(sufbuf); - (fprintf)(stderr, + (dprintf)(STDERR_FILENO, "check failed\r\n" "\tCHECK_%s(%s, %s);\r\n" "\t\t → %#lx (%s)\r\n" @@ -59,27 +61,26 @@ relegated void __check_fail(const char *suffix, const char *opstr, sufbuf, wantstr, gotstr, want, wantstr, opstr, got, gotstr); if (!isempty(fmt)) { - fputc('\t', stderr); + (dprintf)(STDERR_FILENO, "\t"); va_start(va, fmt); - (vfprintf)(stderr, fmt, va); + (vdprintf)(STDERR_FILENO, fmt, va); va_end(va); - fputs("\r\n", stderr); + (dprintf)(STDERR_FILENO, "\r\n"); } - (fprintf)(stderr, "\t%s\r\n\t%s%s%s%s\r\n", strerror(lasterr), SUBTLE, + (dprintf)(STDERR_FILENO, "\t%s\r\n\t%s%s%s%s\r\n", strerror(lasterr), SUBTLE, getauxval(AT_EXECFN), g_argc > 1 ? " \\" : "", RESET); for (i = 1; i < g_argc; ++i) { - (fprintf)(stderr, "\t\t%s%s\r\n", g_argv[i], i < g_argc - 1 ? " \\" : ""); + (dprintf)(STDERR_FILENO, "\t\t%s%s\r\n", g_argv[i], + i < g_argc - 1 ? " \\" : ""); } if (!IsTiny() && lasterr == ENOMEM) { - (fprintf)(stderr, "\r\n"); - fflush(stderr); - PrintMemoryIntervals(fileno(stderr), &_mmi); + (dprintf)(STDERR_FILENO, "\r\n"); + PrintMemoryIntervals(STDERR_FILENO, &_mmi); } - fflush(stderr); die(); unreachable; } diff --git a/libc/log/checkfail_ndebug.c b/libc/log/checkfail_ndebug.c index 6e6fc2fc..f2cd56ff 100644 --- a/libc/log/checkfail_ndebug.c +++ b/libc/log/checkfail_ndebug.c @@ -38,7 +38,7 @@ relegated void ___check_fail_ndebug(uint64_t want, uint64_t got, char bx[21]; int lasterr; lasterr = errno; - startfatal_ndebug(); + __start_fatal_ndebug(); __print_string("check failed: 0x"); __print(bx, uint64toarray_radix16(want, bx)); __print_string(" "); diff --git a/libc/log/color.h b/libc/log/color.h new file mode 100644 index 00000000..05c7cb56 --- /dev/null +++ b/libc/log/color.h @@ -0,0 +1,20 @@ +#ifndef COSMOPOLITAN_LIBC_LOG_COLOR_H_ +#define COSMOPOLITAN_LIBC_LOG_COLOR_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +#define CLS (cancolor() ? "\r\e[J" : "") +#define RED (cancolor() ? "\e[30;101m" : "") +#define GREEN (cancolor() ? "\e[32m" : "") +#define UNBOLD (cancolor() ? "\e[22m" : "") +#define RED2 (cancolor() ? "\e[91;1m" : "") +#define BLUE1 (cancolor() ? "\e[94;49m" : "") +#define BLUE2 (cancolor() ? "\e[34m" : "") +#define RESET (cancolor() ? "\e[0m" : "") +#define SUBTLE (cancolor() ? "\e[35m" : "") + +bool cancolor(void) nothrow nocallback nosideeffect; + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_LOG_COLOR_H_ */ diff --git a/libc/log/internal.h b/libc/log/internal.h index 3b26f180..49adbc2f 100644 --- a/libc/log/internal.h +++ b/libc/log/internal.h @@ -1,33 +1,17 @@ #ifndef COSMOPOLITAN_LIBC_LOG_INTERNAL_H_ #define COSMOPOLITAN_LIBC_LOG_INTERNAL_H_ -#include "libc/calls/calls.h" #include "libc/calls/struct/sigaction.h" -#include "libc/log/log.h" +#include "libc/calls/struct/siginfo.h" +#include "libc/calls/ucontext.h" #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -#define RED (cancolor() ? "\x1b[30;101m" : "") -#define UNBOLD (cancolor() ? "\x1b[22m" : "") -#define RED2 (cancolor() ? "\x1b[91;1m" : "") -#define BLUE1 (cancolor() ? "\x1b[94;49m" : "") -#define BLUE2 (cancolor() ? "\x1b[34m" : "") -#define RESET (cancolor() ? "\x1b[0m" : "") -#define SUBTLE (cancolor() ? "\x1b[35m" : "") - -enum NtExceptionHandlerActions; -struct NtExceptionPointers; - extern int kCrashSigs[8]; extern struct sigaction g_oldcrashacts[8]; -extern const char kCrashSigNames[8][5] aligned(1); -extern const char kGregNames[17][4] aligned(1); -extern const char kGregOrder[17] aligned(1); -void startfatal(const char *, int) hidden; -void startfatal_ndebug(void) hidden; -void oncrash(int, struct siginfo *, struct ucontext *) relegated; -enum NtExceptionHandlerActions wincrash$nt( - const struct NtExceptionPointers *) relegated; +void __start_fatal(const char *, int) hidden; +void __start_fatal_ndebug(void) hidden; +void __oncrash(int, struct siginfo *, struct ucontext *) relegated; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/log/log.h b/libc/log/log.h index efadeafb..cde968f9 100644 --- a/libc/log/log.h +++ b/libc/log/log.h @@ -39,7 +39,6 @@ void meminfo(int); /* shows malloc statistics &c. */ void memsummary(int); /* light version of same thing */ uint16_t getttycols(uint16_t); int getttysize(int, struct winsize *) paramsnonnull(); -bool cancolor(void) nothrow nocallback; bool isterminalinarticulate(void) nosideeffect; char *commandvenv(const char *, const char *) nodiscard; const char *GetAddr2linePath(void); diff --git a/libc/log/log.mk b/libc/log/log.mk index eec74078..5864b411 100644 --- a/libc/log/log.mk +++ b/libc/log/log.mk @@ -32,7 +32,6 @@ LIBC_LOG_A_DIRECTDEPS = \ LIBC_CALLS_HEFTY \ LIBC_CONV \ LIBC_ELF \ - LIBC_ESCAPE \ LIBC_FMT \ LIBC_TINYMATH \ LIBC_NEXGEN32E \ diff --git a/libc/log/oncrash.c b/libc/log/oncrash.c index e7216a59..292299fb 100644 --- a/libc/log/oncrash.c +++ b/libc/log/oncrash.c @@ -24,6 +24,7 @@ #include "libc/dce.h" #include "libc/fmt/fmt.h" #include "libc/log/backtrace.h" +#include "libc/log/color.h" #include "libc/log/gdb.h" #include "libc/log/internal.h" #include "libc/log/log.h" @@ -49,18 +50,18 @@ STATIC_YOINK("stoa"); struct siginfo; -const char kGregOrder[17] aligned(1) = { +static const char kGregOrder[17] aligned(1) = { 13, 11, 8, 14, 12, 9, 10, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, }; -const char kGregNames[17][4] aligned(1) = { +static const char kGregNames[17][4] aligned(1) = { "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", "RDI", "RSI", "RBP", "RBX", "RDX", "RAX", "RCX", "RSP", "RIP", }; -const char kGodHatesFlags[12] aligned(1) = "CVPRAKZSTIDO"; -const char kCrashSigNames[8][5] aligned(1) = {"QUIT", "FPE", "ILL", "SEGV", - "TRAP", "ABRT", "BUS"}; +static const char kGodHatesFlags[12] aligned(1) = "CVPRAKZSTIDO"; +static const char kCrashSigNames[8][5] aligned(1) = { + "QUIT", "FPE", "ILL", "SEGV", "TRAP", "ABRT", "BUS"}; int kCrashSigs[8]; struct sigaction g_oldcrashacts[8]; @@ -191,7 +192,7 @@ relegated static void RestoreDefaultCrashSignalHandlers(void) { * * This function never returns, except for traps w/ human supervision. */ -relegated void oncrash(int sig, struct siginfo *si, ucontext_t *ctx) { +relegated void __oncrash(int sig, struct siginfo *si, ucontext_t *ctx) { intptr_t rip; int gdbpid, err; static bool once; diff --git a/libc/log/oncrashthunks.S b/libc/log/oncrashthunks.S index ca9cfec4..7aee1686 100644 --- a/libc/log/oncrashthunks.S +++ b/libc/log/oncrashthunks.S @@ -24,69 +24,69 @@ / caused the crash, particularly in the GDB GUI. They're coded / into an array to pinch pennies on code size registering them. -kOncrashThunks: +__oncrash_thunks: .org 11*0 -oncrash_sigquit: +__oncrash_sigquit: push %rbp mov %rsp,%rbp - call oncrash + call __oncrash pop %rbp ret - .endfn oncrash_sigquit,globl + .endfn __oncrash_sigquit,globl .org 11*1 -oncrash_sigfpe: +__oncrash_sigfpe: push %rbp mov %rsp,%rbp - call oncrash + call __oncrash pop %rbp ret - .endfn oncrash_sigfpe,globl + .endfn __oncrash_sigfpe,globl .org 11*2 -oncrash_sigill: +__oncrash_sigill: push %rbp mov %rsp,%rbp - call oncrash + call __oncrash pop %rbp ret - .endfn oncrash_sigill,globl + .endfn __oncrash_sigill,globl .org 11*3 -oncrash_sigsegv: +__oncrash_sigsegv: push %rbp mov %rsp,%rbp - call oncrash + call __oncrash pop %rbp ret - .endfn oncrash_sigsegv,globl + .endfn __oncrash_sigsegv,globl .org 11*4 -oncrash_sigtrap: +__oncrash_sigtrap: push %rbp mov %rsp,%rbp - call oncrash + call __oncrash pop %rbp ret - .endfn oncrash_sigtrap,globl + .endfn __oncrash_sigtrap,globl .org 11*5 -oncrash_sigabrt: +__oncrash_sigabrt: push %rbp mov %rsp,%rbp - call oncrash + call __oncrash pop %rbp ret - .endfn oncrash_sigabrt,globl + .endfn __oncrash_sigabrt,globl .org 11*6 -oncrash_sigbus: +__oncrash_sigbus: push %rbp mov %rsp,%rbp - call oncrash + call __oncrash pop %rbp ret - .endfn oncrash_sigbus,globl + .endfn __oncrash_sigbus,globl - .endobj kOncrashThunks,globl + .endobj __oncrash_thunks,globl diff --git a/libc/log/perror.c b/libc/log/perror.c index 1589f5bd..ed5a6a5d 100644 --- a/libc/log/perror.c +++ b/libc/log/perror.c @@ -19,6 +19,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/errno.h" #include "libc/fmt/fmt.h" +#include "libc/log/color.h" #include "libc/log/internal.h" #include "libc/log/log.h" #include "libc/runtime/runtime.h" diff --git a/libc/log/showcrashreports.c b/libc/log/showcrashreports.c index 11d7f12a..08b4e051 100644 --- a/libc/log/showcrashreports.c +++ b/libc/log/showcrashreports.c @@ -34,7 +34,7 @@ STATIC_YOINK("die"); STATIC_YOINK("__ubsan_abort"); -extern const unsigned char kOncrashThunks[7][11]; +extern const unsigned char __oncrash_thunks[7][11]; /** * Installs crash signal handlers. @@ -73,7 +73,7 @@ void showcrashreports(void) { } for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) { if (kCrashSigs[i]) { - sa.sa_sigaction = (sigaction_f)kOncrashThunks[i]; + sa.sa_sigaction = (sigaction_f)__oncrash_thunks[i]; sigaction(kCrashSigs[i], &sa, &g_oldcrashacts[i]); } } diff --git a/libc/log/startfatal.c b/libc/log/startfatal.c index e873e2e9..d4a1254b 100644 --- a/libc/log/startfatal.c +++ b/libc/log/startfatal.c @@ -17,18 +17,19 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/calls.h" +#include "libc/log/color.h" #include "libc/log/internal.h" #include "libc/runtime/runtime.h" -#include "libc/stdio/stdio.h" +#include "libc/sysv/consts/fileno.h" /** * Prints initial part of fatal message. * * @note this is support code for __check_fail(), __assert_fail(), etc. - * @see startfatal_ndebug() + * @see __start_fatal_ndebug() */ -relegated void startfatal(const char *file, int line) { - fflush(stdout); - fprintf(stderr, "%s%s%s:%s:%d:%s%s: ", RED, "error", BLUE1, file, line, - program_invocation_short_name, RESET); +relegated void __start_fatal(const char *file, int line) { + dprintf(STDERR_FILENO, "%s%s%s%s:%s:%d:%s%s: ", CLS, RED, "error", BLUE1, + file, line, program_invocation_short_name, RESET); } diff --git a/libc/log/startfatal_ndebug.c b/libc/log/startfatal_ndebug.c index c4ac1535..68917a1b 100644 --- a/libc/log/startfatal_ndebug.c +++ b/libc/log/startfatal_ndebug.c @@ -17,6 +17,7 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/log/color.h" #include "libc/runtime/missioncritical.h" #include "libc/stdio/stdio.h" @@ -24,11 +25,10 @@ * Prints initial part of fatal message. * * @note this is support code for __check_fail(), __assert_fail(), etc. - * @see startfatal() + * @see __start_fatal() */ -relegated void startfatal_ndebug(void) { - fflush(stdout); - fflush(stderr); +relegated void __start_fatal_ndebug(void) { + if (cancolor()) __print_string("\r\e[J"); __print_string("error:"); __print_string(program_invocation_name); __print_string(": "); diff --git a/libc/log/ubsan.c b/libc/log/ubsan.c index 042d2945..f9317d0c 100644 --- a/libc/log/ubsan.c +++ b/libc/log/ubsan.c @@ -55,7 +55,7 @@ void __ubsan_abort(const struct UbsanSourceLocation *loc, } g_runstate |= RUNSTATE_BROKEN; if (IsDebuggerPresent(false)) DebugBreak(); - startfatal(loc->file, loc->line); + __start_fatal(loc->file, loc->line); fprintf(stderr, "%s\r\n", description); die(); unreachable; @@ -74,7 +74,7 @@ void __ubsan_handle_type_mismatch(struct UbsanTypeMismatchInfo *type_mismatch, uintptr_t pointer) { struct UbsanSourceLocation *loc = &type_mismatch->location; const char *description; - const char *kind = indexdoublenulstring(kUbsanTypeCheckKinds, + const char *kind = IndexDoubleNulString(kUbsanTypeCheckKinds, type_mismatch->type_check_kind); if (pointer == 0) { description = "null pointer access"; diff --git a/libc/log/verr.c b/libc/log/verr.c index da2b8aba..896dfeef 100644 --- a/libc/log/verr.c +++ b/libc/log/verr.c @@ -18,6 +18,7 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/log/bsd.h" +#include "libc/log/color.h" #include "libc/log/internal.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" diff --git a/libc/log/verrx.c b/libc/log/verrx.c index e53a3b84..36db02f7 100644 --- a/libc/log/verrx.c +++ b/libc/log/verrx.c @@ -18,6 +18,7 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/log/bsd.h" +#include "libc/log/color.h" #include "libc/log/internal.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" diff --git a/libc/log/vflogf.c b/libc/log/vflogf.c index dc7dbfd3..46d1bcbd 100644 --- a/libc/log/vflogf.c +++ b/libc/log/vflogf.c @@ -32,6 +32,7 @@ #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" +#include "libc/sysv/consts/fileno.h" #include "libc/time/struct/tm.h" #include "libc/time/time.h" @@ -113,8 +114,8 @@ void(vflogf)(unsigned level, const char *file, int line, FILE *f, va_end(va); fputs("\r\n", f); if (level == kLogFatal) { - startfatal(file, line); - (fprintf)(stderr, "fatal error see logfile\r\n"); + __start_fatal(file, line); + (dprintf)(STDERR_FILENO, "fatal error see logfile\r\n"); die(); unreachable; } diff --git a/libc/log/vwarn.c b/libc/log/vwarn.c index 2fd0e5b5..f6ccc0f5 100644 --- a/libc/log/vwarn.c +++ b/libc/log/vwarn.c @@ -18,6 +18,7 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/log/bsd.h" +#include "libc/log/color.h" #include "libc/log/internal.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" diff --git a/libc/log/vwarnx.c b/libc/log/vwarnx.c index a0d81c5d..117f0115 100644 --- a/libc/log/vwarnx.c +++ b/libc/log/vwarnx.c @@ -18,6 +18,7 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/log/bsd.h" +#include "libc/log/color.h" #include "libc/log/internal.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" diff --git a/libc/x/xaescapeshq.c b/libc/mem/malloc_trim.c similarity index 86% rename from libc/x/xaescapeshq.c rename to libc/mem/malloc_trim.c index e0f73c2c..2c789f03 100644 --- a/libc/x/xaescapeshq.c +++ b/libc/mem/malloc_trim.c @@ -17,15 +17,15 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/escape/escape.h" -#include "libc/runtime/gc.h" -#include "libc/x/x.h" +#include "libc/mem/mem.h" +#include "third_party/dlmalloc/dlmalloc.h" /** - * Single-quotes string for bourne shell. + * Releases freed memory back to system. * - * @return escaped string which must make its way to free() + * @param pad can specify how many bytes of memory to leave available + * @return 1 if it actually released any memory, else 0 */ -char *xaescapeshq(const char *unescaped) { - return xasprintf("'%s'", gc(xaescape(unescaped, escapesh))); +int malloc_trim(size_t pad) { + return dlmalloc_trim(pad); } diff --git a/libc/nexgen32e/nt2sysv.S b/libc/nexgen32e/nt2sysv.S index 7321df83..e5ea81bc 100644 --- a/libc/nexgen32e/nt2sysv.S +++ b/libc/nexgen32e/nt2sysv.S @@ -29,7 +29,8 @@ / @param %rcx,%rdx,%r8,%r9 / @return %rax,%xmm0 / @note this is so much slower than sysv2nt() -nt2sysv:push %rbp +__nt2sysv: + push %rbp mov %rsp,%rbp .profilable sub $0x100,%rsp @@ -53,5 +54,5 @@ nt2sysv:push %rbp pop %rbx leave ret - .endfn nt2sysv,globl,hidden + .endfn __nt2sysv,globl,hidden .source __FILE__ diff --git a/libc/nexgen32e/strsak.S b/libc/nexgen32e/strsak.S index 6f52553b..8124c8f0 100644 --- a/libc/nexgen32e/strsak.S +++ b/libc/nexgen32e/strsak.S @@ -105,15 +105,6 @@ strnlen_s: .leafepilogue .endfn strnlen_s,globl -/ Returns length of NUL-terminated string. -/ -/ @param rdi is non-null NUL-terminated string pointer -/ @return rax is the number of bytes, excluding the NUL -/ @asyncsignalsafe -strlen: or $-1,%rsi -/ 𝑠𝑙𝑖𝑑𝑒 - .endfn strlen,globl - / Returns length of NUL-terminated memory, with limit. / / @param rdi is non-null memory @@ -129,7 +120,7 @@ strnlen:.leafprologue .endfn strnlen,globl / Swiss army knife of string character scanning. -/ Sixteen fast functions in one. +/ Fourteen fast functions in one. / / @param rdi is non-null string memory / @param rsi is max number of bytes to consider diff --git a/libc/rand/rand.mk b/libc/rand/rand.mk index d8f37d8e..cb6ffe9d 100644 --- a/libc/rand/rand.mk +++ b/libc/rand/rand.mk @@ -29,6 +29,7 @@ LIBC_RAND_A_DIRECTDEPS = \ LIBC_TINYMATH \ LIBC_NEXGEN32E \ LIBC_NT_KERNELBASE \ + LIBC_STR \ LIBC_SYSV_CALLS \ LIBC_SYSV diff --git a/libc/stdio/g_stderr_init.S b/libc/stdio/g_stderr_init.S index 4a4a984f..2158bf8e 100644 --- a/libc/stdio/g_stderr_init.S +++ b/libc/stdio/g_stderr_init.S @@ -25,18 +25,18 @@ .source __FILE__ .init.start 400,_init_g_stderr - lea g_stderr(%rip),%rax + ezlea g_stderr,ax push $_IOLBF pop (%rax) #→ f.fd push STDERR_FILENO pop 12(%rax) mov O_WRONLY,%edx mov %edx,4(%rax) #→ f.iomode - lea g_stderr_buf(%rip),%rcx + ezlea g_stderr_buf,cx mov %rcx,24(%rax) #→ f.buf movl $BUFSIZ,32(%rax) #→ f.size - lea fwritebuf(%rip),%rcx - lea fswritebuf(%rip),%rdx + ezlea fwritebuf,cx + ezlea fswritebuf,dx testb IsMetal() cmove %rcx,%rdx mov %rdx,48(%rax) #→ f.writer diff --git a/libc/stdio/g_stdin_init.S b/libc/stdio/g_stdin_init.S index 44de317b..753e1b57 100644 --- a/libc/stdio/g_stdin_init.S +++ b/libc/stdio/g_stdin_init.S @@ -25,14 +25,14 @@ .source __FILE__ .init.start 400,_init_g_stdin - lea g_stdin(%rip),%rax + ezlea g_stdin,ax mov O_RDONLY,%edx mov %edx,4(%rax) #→ f.iomode - lea g_stdin_buf(%rip),%rcx + ezlea g_stdin_buf,cx mov %rcx,24(%rax) #→ f.buf movl $BUFSIZ,32(%rax) #→ f.size - lea freadbuf(%rip),%rcx - lea fsreadbuf(%rip),%rdx + ezlea freadbuf,cx + ezlea fsreadbuf,dx testb IsMetal() cmove %rcx,%rdx mov %rdx,40(%rax) #→ f.reader diff --git a/libc/stdio/g_stdout_init.S b/libc/stdio/g_stdout_init.S index a9fb03d4..ab91f9ca 100644 --- a/libc/stdio/g_stdout_init.S +++ b/libc/stdio/g_stdout_init.S @@ -25,16 +25,16 @@ .source __FILE__ .init.start 400,_init_g_stdout - lea g_stdout(%rip),%rax + ezlea g_stdout,ax push STDOUT_FILENO pop 12(%rax) #→ f.fd mov O_WRONLY,%edx mov %edx,4(%rax) #→ f.iomode - lea g_stdout_buf(%rip),%rcx + ezlea g_stdout_buf,cx mov %rcx,24(%rax) #→ f.buf movl $BUFSIZ,32(%rax) #→ f.size - lea fwritebuf(%rip),%rcx - lea fswritebuf(%rip),%rdx + ezlea fwritebuf,cx + ezlea fswritebuf,dx testb IsMetal() cmovz %rcx,%rdx mov %rdx,48(%rax) #→ f.writer diff --git a/libc/stdio/stdio.mk b/libc/stdio/stdio.mk index 5517639d..8c7d8193 100644 --- a/libc/stdio/stdio.mk +++ b/libc/stdio/stdio.mk @@ -29,7 +29,6 @@ LIBC_STDIO_A_DIRECTDEPS = \ LIBC_BITS \ LIBC_CALLS \ LIBC_CONV \ - LIBC_ESCAPE \ LIBC_FMT \ LIBC_MEM \ LIBC_NEXGEN32E \ diff --git a/libc/stdio/system.c b/libc/stdio/system.c index ac2668cd..c119de13 100644 --- a/libc/stdio/system.c +++ b/libc/stdio/system.c @@ -22,7 +22,6 @@ #include "libc/calls/hefty/ntspawn.h" #include "libc/calls/internal.h" #include "libc/dce.h" -#include "libc/escape/escape.h" #include "libc/mem/mem.h" #include "libc/nt/accounting.h" #include "libc/nt/enum/startf.h" diff --git a/libc/str/endswith.c b/libc/str/endswith.c index 22605cae..47daad12 100644 --- a/libc/str/endswith.c +++ b/libc/str/endswith.c @@ -25,11 +25,10 @@ * @param s is a NUL-terminated string * @param suffix is also NUL-terminated */ -bool(endswith)(const char *s, const char *suffix) { - size_t l1, l2; - if (s == suffix) return true; - l1 = strlen(s); - l2 = strnlen(suffix, l1); - if (l2 > l1) return false; - return memcmp(s + (l1 - l2) * sizeof(char), suffix, l2 * sizeof(char)) == 0; +bool endswith(const char *s, const char *suffix) { + size_t n, m; + n = strlen(s); + m = strlen(suffix); + if (m > n) return false; + return memcmp(s + n - m, suffix, m) == 0; } diff --git a/libc/escape/escapedos.c b/libc/str/escapedos.c similarity index 99% rename from libc/escape/escapedos.c rename to libc/str/escapedos.c index e4a784d6..8de0ceb1 100644 --- a/libc/escape/escapedos.c +++ b/libc/str/escapedos.c @@ -17,7 +17,6 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/escape/escape.h" #include "libc/str/str.h" static textwindows bool shouldescapedos(const char16_t c) { diff --git a/libc/str/getkvlin.c b/libc/str/getkvlin.c index b09cc4a9..2b5d2660 100644 --- a/libc/str/getkvlin.c +++ b/libc/str/getkvlin.c @@ -20,11 +20,11 @@ #include "libc/str/str.h" int getkvlin(const char *name, const char *const unsorted[]) { + unsigned i, n; if (unsorted) { - unsigned namelen = strlen(name); - for (int i = 0; unsorted[i]; ++i) { - if (strncmp(unsorted[i], name, namelen) == 0 && - unsorted[i][namelen] == '=') { + n = strlen(name); + for (i = 0; unsorted[i]; ++i) { + if (strncmp(unsorted[i], name, n) == 0 && unsorted[i][n] == '=') { return i; } } diff --git a/libc/str/indexdoublenulstring.c b/libc/str/indexdoublenulstring.c index 43d0821e..2e2d1441 100644 --- a/libc/str/indexdoublenulstring.c +++ b/libc/str/indexdoublenulstring.c @@ -19,11 +19,14 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" -const char *indexdoublenulstring(const char *p, unsigned i) { +const char *IndexDoubleNulString(const char *s, unsigned i) { + size_t n; while (i--) { - const char *p2 = rawmemchr(p, '\0'); - if (p2 == p) return NULL; - p = p2 + 1; + if ((n = strlen(s))) { + s += n + 1; + } else { + return NULL; + } } - return p; + return s; } diff --git a/libc/str/internal.h b/libc/str/internal.h index be45024c..df678062 100644 --- a/libc/str/internal.h +++ b/libc/str/internal.h @@ -26,27 +26,12 @@ hidden extern const uint32_t kSha256Tab[64]; -extern const struct TpEncode { - uint8_t mark; - uint8_t len; -} kTpDecoderRing[32]; - -forceinline struct TpEncode UseTpDecoderRing(wint_t c) { - unsigned msb; - if (c) { - asm("bsr\t%1,%0" : "=r"(msb) : "rm"(c) : "cc"); - } else { - msb = 0; - } - return kTpDecoderRing[msb]; -} - nodebuginfo forceinline bool32 ismoar(wint_t c) { - return (c & 0b11000000) == 0b11000000; + return (c & 0300) == 0300; } nodebuginfo forceinline bool32 iscont(wint_t c) { - return (c & 0b11000000) == 0b10000000; + return (c & 0300) == 0200; } char *strstr$sse42(const char *, const char *) strlenesque hidden; diff --git a/libc/str/isascii.c b/libc/str/isascii.c index 10b0994e..5313b23d 100644 --- a/libc/str/isascii.c +++ b/libc/str/isascii.c @@ -17,6 +17,7 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/str/str.h" int isascii(int c) { return 0x00 <= c && c <= 0x7F; diff --git a/libc/str/isnotplaintext.c b/libc/str/isnotplaintext.c deleted file mode 100644 index 19f5af2d..00000000 --- a/libc/str/isnotplaintext.c +++ /dev/null @@ -1,64 +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 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ -│ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ -│ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ -╚─────────────────────────────────────────────────────────────────────────────*/ - -/** - * Checks if memory address contains non-plain text. - * - * @param data points to memory that's interpreted as char - * @param size is usually strlen(data) and provided by caller - * @return NULL if plain text, or pointer to first non-text datum - * @type char may be 6/7/8/16/32/64-bit signed/unsigned single/multi - * @author Justine Alexandra Roberts Tunney - * @see ASA X3.4, ISO/IEC 646, ITU T.50, ANSI X3.64-1979 - * @perf 27gBps on i7-6700 w/ -O3 -mavx2 - * @cost 143 bytes of code w/ -Os - */ -void *isnotplaintext(const void *data, size_t size) { - /* - * ASCII, EBCDIC, UNICODE, ISO IR-67, etc. all agree upon the - * encoding of the NUL, SOH, STX, and ETX characters due to a - * longstanding human tradition of using them for the purpose - * of delimiting text from non-text, b/c fixed width integers - * makes their presence in binary formats nearly unavoidable. - */ -#define isnotplain(C) (0 <= (C) && (C) < 4) - char no; - unsigned i; - const char *p, *pe; - if (CHAR_BIT > 6) { - p = (const char *)data; - pe = (const char *)(p + size); - for (; ((intptr_t)p & 31) && p < pe; ++p) { - if (isnotplain(*p)) return p; - } - for (; p + 64 < pe; p += 64) { - no = 0; - for (i = 0; i < 64; ++i) { - no |= isnotplain(p[i]); - } - if (no & 1) break; - } - for (; p < pe; ++p) { - if (isnotplain(*p)) return p; - } - } - return 0; -#undef isnotplain -} diff --git a/libc/str/ktpdecoderring.S b/libc/str/ktpdecoderring.S deleted file mode 100644 index b708f3ef..00000000 --- a/libc/str/ktpdecoderring.S +++ /dev/null @@ -1,56 +0,0 @@ -/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ -│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ -╞══════════════════════════════════════════════════════════════════════════════╡ -│ Copyright 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ -│ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ -│ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/macros.h" -.source __FILE__ - -/ Thompson-Pike Decoder Ring. -/ -/ The IA-32 BSR instruction can be used to turn a 32-bit -/ number into an index for this table. -/ -/ @see libc/str/internal.h - .rodata - .align 2 -kTpDecoderRing: - .rept 7 # MSB≤6 (0x7F) - .byte 0b00000000,1 # mark,len -/ 0b11000000 # mask - .endr - .rept 4 # MSB≤10 (0x7FF) - .byte 0b11000000,2 # mark,len -/ 0b11100000 # mask - .endr - .rept 5 # MSB≤15 (0xFFFF) - .byte 0b11100000,3 # mark,len -/ 0b11110000 # mask - .endr - .rept 5 # MSB≤20 (0x1FFFFF) - .byte 0b11110000,4 # mark,len -/ 0b11111000 # mask - .endr - .rept 5 # MSB≤25 (0x3FFFFFF) - .byte 0b11111000,5 # mark,len -/ 0b11111100 # mask - .endr - .rept 6 # MSB≤31 (0xffffffff) - .byte 0b11111100,6 # mark,len - .endr - .endobj kTpDecoderRing,globl,hidden - .previous diff --git a/libc/str/startswith.c b/libc/str/startswith.c index 91dbfa1d..542fe805 100644 --- a/libc/str/startswith.c +++ b/libc/str/startswith.c @@ -21,11 +21,11 @@ /** * Returns true if s has prefix. + * * @param s is a NUL-terminated string * @param prefix is also NUL-terminated */ -bool(startswith)(const char *s, const char *prefix) { - if (s == prefix) return true; +bool startswith(const char *s, const char *prefix) { for (;;) { if (!*prefix) return true; if (!*s) return false; diff --git a/libc/str/stpcpy.c b/libc/str/stpcpy.c index ab9dff15..a4e8c23e 100644 --- a/libc/str/stpcpy.c +++ b/libc/str/stpcpy.c @@ -17,20 +17,45 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/intrin/pcmpeqb.h" +#include "libc/intrin/pmovmskb.h" #include "libc/str/str.h" /** - * Copies string and advances destination pointer. + * Copies bytes from 𝑠 to 𝑑 until a NUL is encountered. + * + * @param 𝑑 is destination memory + * @param 𝑠 is a NUL-terminated string + * @note 𝑑 and 𝑠 can't overlap + * @return pointer to nul byte + * @see strcpy(), memccpy() * @asyncsignalsafe */ -char *stpcpy(char *dst, const char *src) { - char c; - for (;;) { - c = *src; - *dst = c; - if (!c) break; - ++src; - ++dst; +char *stpcpy(char *d, const char *s) { + size_t i; + uint8_t v1[16], v2[16], vz[16]; + i = 0; + while (((uintptr_t)(s + i) & 15)) { + if (!(d[i] = s[i])) { + return d + i; + } + ++i; + } + for (;;) { + memset(vz, 0, 16); + memcpy(v1, s + i, 16); + pcmpeqb(v2, v1, vz); + if (!pmovmskb(v2)) { + memcpy(d + i, v1, 16); + i += 16; + } else { + break; + } + } + for (;;) { + if (!(d[i] = s[i])) { + return d + i; + } + ++i; } - return dst; } diff --git a/libc/str/str.h b/libc/str/str.h index 4090fc73..f30a1565 100644 --- a/libc/str/str.h +++ b/libc/str/str.h @@ -30,8 +30,7 @@ int tolower(int); int ispunct(int); int toupper(int); int hextoint(int); - -void *isnotplaintext(const void *, size_t) nothrow nocallback nosideeffect; +int cescapec(int); /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § characters » thompson-pike encoding ─╬─│┼ @@ -173,7 +172,7 @@ bool wcsstartswith(const wchar_t *, const wchar_t *) strlenesque; bool endswith(const char *, const char *) strlenesque; bool endswith16(const char16_t *, const char16_t *) strlenesque; bool wcsendswith(const wchar_t *, const wchar_t *) strlenesque; -const char *indexdoublenulstring(const char *, unsigned) strlenesque; +const char *IndexDoubleNulString(const char *, unsigned) strlenesque; int getkvlin(const char *, const char *const[]); wchar_t *wmemset(wchar_t *, wchar_t, size_t) memcpyesque; char16_t *memset16(char16_t *, char16_t, size_t) memcpyesque; @@ -194,6 +193,8 @@ char *chomp(char *); char16_t *chomp16(char16_t *); wchar_t *wchomp(wchar_t *); +bool escapedos(char16_t *, unsigned, const char16_t *, unsigned); + /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § strings » multibyte ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ @@ -341,27 +342,6 @@ extern int (*const hook$wcsncmp)(const wchar_t *, const wchar_t *, size_t); : strncasecmp16, default \ : strncasecmp)(s1, s2, n) -#define startswith(s, c) \ - _Generic(*(s), wchar_t \ - : wcsstartswith, char16_t \ - : startswith16, default \ - : startswith)(s, c) - -#define endswith(s, c) \ - _Generic(*(s), wchar_t \ - : wcsendswith, char16_t \ - : endswith16, default \ - : endswith)(s, c) - -#define strclen(s) \ - _Generic(*(s), wchar_t : wcslen, char16_t : strclen16, default : strclen)(s) - -#define strnclen(s, n) \ - _Generic(*(s), wchar_t \ - : wcslen, char16_t \ - : strnclen16, default \ - : strnclen)(s, n) - #define chomp(s) \ _Generic(*(s), wchar_t : wchomp, char16_t : chomp16, default : chomp)(s) diff --git a/libc/str/str.mk b/libc/str/str.mk index 498c44e0..96145d23 100644 --- a/libc/str/str.mk +++ b/libc/str/str.mk @@ -28,6 +28,7 @@ LIBC_STR_A_CHECKS = \ $(LIBC_STR_A_HDRS:%=o/$(MODE)/%.ok) LIBC_STR_A_DIRECTDEPS = \ + LIBC_INTRIN \ LIBC_STUBS \ LIBC_NEXGEN32E diff --git a/libc/str/strclen.c b/libc/str/strclen.c index 4647bdaf..58242290 100644 --- a/libc/str/strclen.c +++ b/libc/str/strclen.c @@ -17,23 +17,23 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/str/internal.h" #include "libc/str/str.h" /** * Returns number of characters in UTF-8 string. */ -size_t(strclen)(const char *s) { return strnclen(s, -1ull); } +size_t strclen(const char *s) { + return strnclen(s, -1); +} -noinline size_t(strnclen)(const char *s, size_t n) { - const unsigned char *p = (const unsigned char *)s; - size_t l = 0; +noinline size_t strnclen(const char *s, size_t n) { + size_t r = 0; if (n) { - while (*p && n && iscont(*p)) ++p, --n; - while (*p) { - if (!iscont(*p++)) l++; + while (n && *s && (*s & 0300) == 0200) ++s, --n; + while (*s) { + if ((*s++ & 0300) != 0200) r++; if (!--n) break; } } - return l; + return r; } diff --git a/libc/str/strcpy.c b/libc/str/strcpy.c index fc9a23f4..3be415de 100644 --- a/libc/str/strcpy.c +++ b/libc/str/strcpy.c @@ -17,7 +17,10 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/intrin/pcmpeqb.h" +#include "libc/intrin/pmovmskb.h" #include "libc/limits.h" +#include "libc/nexgen32e/bsf.h" #include "libc/str/str.h" /** @@ -31,6 +34,30 @@ * @asyncsignalsafe */ char *strcpy(char *d, const char *s) { - memccpy(d, s, '\0', SIZE_MAX); - return d; + size_t i; + uint8_t v1[16], v2[16], vz[16]; + i = 0; + while (((uintptr_t)(s + i) & 15)) { + if (!(d[i] = s[i])) { + return d; + } + ++i; + } + for (;;) { + memset(vz, 0, 16); + memcpy(v1, s + i, 16); + pcmpeqb(v2, v1, vz); + if (!pmovmskb(v2)) { + memcpy(d + i, v1, 16); + i += 16; + } else { + break; + } + } + for (;;) { + if (!(d[i] = s[i])) { + return d; + } + ++i; + } } diff --git a/libc/x/xaescape.c b/libc/str/strlen.c similarity index 74% rename from libc/x/xaescape.c rename to libc/str/strlen.c index 3421e63f..0acd9642 100644 --- a/libc/x/xaescape.c +++ b/libc/str/strlen.c @@ -17,22 +17,34 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/escape/escape.h" -#include "libc/log/log.h" -#include "libc/runtime/runtime.h" +#include "libc/assert.h" +#include "libc/intrin/pcmpeqb.h" +#include "libc/intrin/pmovmskb.h" +#include "libc/nexgen32e/bsf.h" #include "libc/str/str.h" -#include "libc/x/x.h" /** - * Aspects 2-arity memory op with allocating behavior. - * Used to turn FOO() into aFOO() without too much duplicated code. + * Returns length of NUL-terminated string. + * + * @param s is non-null NUL-terminated string pointer + * @return number of bytes (excluding NUL) + * @asyncsignalsafe */ -char *xaescape(const char *unescaped, - int impl(char *escaped, unsigned size, const char *unescaped, - unsigned length)) { - char *escaped = NULL; - if (aescape(&escaped, 32, unescaped, strlen(unescaped), impl) == -1) { - xdie(); +size_t strlen(const char *s) { + const char *p; + unsigned k, m; + uint8_t v1[16], vz[16]; + k = (uintptr_t)s & 15; + p = (const char *)((uintptr_t)s & -16); + memset(vz, 0, 16); + memcpy(v1, p, 16); + pcmpeqb(v1, v1, vz); + m = pmovmskb(v1) >> k << k; + while (!m) { + p += 16; + memcpy(v1, p, 16); + pcmpeqb(v1, v1, vz); + m = pmovmskb(v1); } - return escaped; + return p + bsf(m) - s; } diff --git a/libc/str/thompike.h b/libc/str/thompike.h index b8763b10..c975aaf8 100644 --- a/libc/str/thompike.h +++ b/libc/str/thompike.h @@ -2,10 +2,10 @@ #define COSMOPOLITAN_LIBC_STR_THOMPIKE_H_ #include "libc/nexgen32e/bsr.h" -#define ThomPikeCont(x) (((x)&0b11000000) == 0b10000000) +#define ThomPikeCont(x) (((x)&0300) == 0200) #define ThomPikeByte(x) ((x) & (((1 << ThomPikeMsb(x)) - 1) | 3)) #define ThomPikeLen(x) (7 - ThomPikeMsb(x)) #define ThomPikeMsb(x) (((x)&0xff) < 252 ? bsr(~(x)&0xff) : 1) -#define ThomPikeMerge(x, y) ((x) << 6 | (y)&0b00111111) +#define ThomPikeMerge(x, y) ((x) << 6 | (y)&077) #endif /* COSMOPOLITAN_LIBC_STR_THOMPIKE_H_ */ diff --git a/libc/stubs/sysv2nt.S b/libc/stubs/sysv2nt.S index 5bd4d8ec..b3cc9d79 100644 --- a/libc/stubs/sysv2nt.S +++ b/libc/stubs/sysv2nt.S @@ -29,7 +29,7 @@ / @return is in %rax, %xmm0, or %st / @note GCC 4.8+ and Clang can avoid this indirection / @note thunk that jumps here must setup frame -/ @note this is so much faster than nt2sysv() +/ @note this is so much faster than __nt2sysv() __sysv2nt14: pushq 72(%rbp) pushq 64(%rbp) diff --git a/libc/sysv/calls/vfork.s b/libc/sysv/calls/vfork.s deleted file mode 100644 index 54431877..00000000 --- a/libc/sysv/calls/vfork.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.inc" -.scall vfork 0x004200422042003a globl diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index adc2ee92..9aeb80bc 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -293,14 +293,14 @@ syscon spawn POSIX_SPAWN_SETSCHEDPARAM 0x10 0 4 4 0 syscon spawn POSIX_SPAWN_SETSCHEDULER 0x20 0 8 8 0 syscon spawn POSIX_SPAWN_USEVFORK 0x40 0 0 0 0 -# mprotect(), etc. +# mmap(), mprotect(), etc. # digital restrictions management for the people # # group name GNU/Systemd XNU's Not UNIX FreeBSD OpenBSD XENIX Commentary -syscon mprot PROT_NONE 0 0 0 0 0 # unix consensus (nt needs special business logic here) -syscon mprot PROT_READ 1 1 1 1 1 # unix consensus -syscon mprot PROT_WRITE 2 2 2 2 2 # unix consensus -syscon mprot PROT_EXEC 4 4 4 4 4 # unix consensus +syscon mprot PROT_NONE 0 0 0 0 0 # mmap, mprotect, unix consensus (nt needs special business logic here) +syscon mprot PROT_READ 1 1 1 1 1 # mmap, mprotect, unix consensus +syscon mprot PROT_WRITE 2 2 2 2 2 # mmap, mprotect, unix consensus +syscon mprot PROT_EXEC 4 4 4 4 4 # mmap, mprotect, unix consensus syscon mprot PROT_GROWSDOWN 0x01000000 0 0 0 0 # intended for mprotect; see MAP_GROWSDOWN for mmap() (todo: what was 0x01000000 on nt) syscon mprot PROT_GROWSUP 0x02000000 0 0 0 0 # intended for mprotect; see MAP_GROWSDOWN for mmap() @@ -2798,6 +2798,7 @@ syscon nr __NR_access 0x0015 0x2000021 0x0021 0x0021 -1 syscon nr __NR_sched_yield 0x0018 0x100003c 0x014b 0x012a -1 syscon nr __NR_sendfile 0x0028 0x2000151 0x0189 0xffff -1 syscon nr __NR_fork 0x0039 0x2000002 0x0002 0x0002 -1 +syscon nr __NR_vfork 0x003a 0x2000042 0x0042 0x0042 -1 syscon nr __NR_gettimeofday 0x0060 0x2000074 0x0074 0x0043 -1 syscon nr __NR_arch_prctl 0x009e 0x000ffff 0x00a5 0x00a5 -1 syscon nr __NR_gettid 0x00ba 0x200011e 0xffff 0xffff -1 diff --git a/libc/sysv/consts/MAP_FIXED.s b/libc/sysv/consts/MAP_FIXED.s index 59e0fca5..b17c886f 100644 --- a/libc/sysv/consts/MAP_FIXED.s +++ b/libc/sysv/consts/MAP_FIXED.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon mmap MAP_FIXED 16 16 16 16 16 +.syscon mmap MAP_FIXED 0x10 0x10 0x10 0x10 0x10 diff --git a/libc/sysv/consts/MAP_NONBLOCK.s b/libc/sysv/consts/MAP_NONBLOCK.s index 57a313de..4db11be9 100644 --- a/libc/sysv/consts/MAP_NONBLOCK.s +++ b/libc/sysv/consts/MAP_NONBLOCK.s @@ -1,2 +1,2 @@ .include "libc/sysv/consts/syscon.inc" -.syscon mmap MAP_NONBLOCK 0x010000 0 0 0 0 +.syscon mmap MAP_NONBLOCK 0x10000 0 0 0 0 diff --git a/libc/sysv/consts/__NR_vfork.s b/libc/sysv/consts/__NR_vfork.s new file mode 100644 index 00000000..5eb5a551 --- /dev/null +++ b/libc/sysv/consts/__NR_vfork.s @@ -0,0 +1,2 @@ +.include "libc/sysv/consts/syscon.inc" +.syscon nr __NR_vfork 0x003a 0x2000042 0x0042 0x0042 -1 diff --git a/libc/sysv/syscalls.sh b/libc/sysv/syscalls.sh index 16bf9312..ecf0d77a 100755 --- a/libc/sysv/syscalls.sh +++ b/libc/sysv/syscalls.sh @@ -91,7 +91,7 @@ scall 'socketpair$sysv' 0x0087008720870035 globl hidden scall 'setsockopt$sysv' 0x0069006920690036 globl hidden scall 'getsockopt$sysv' 0x0076007620760037 globl hidden scall 'fork$sysv' 0x0002000220020039 globl hidden -scall vfork 0x004200422042003a globl +#scall vfork 0x004200422042003a globl # needs to be called via vfork.S scall posix_spawn 0xffffffff20f4ffff globl hidden # TODO: put in spawnve() scall 'execve$sysv' 0x003b003b203b003b globl hidden scall 'wait4$sysv' 0x000b00072007003d globl hidden diff --git a/libc/sysv/systemfive.S b/libc/sysv/systemfive.S index 5108b382..43b399ce 100644 --- a/libc/sysv/systemfive.S +++ b/libc/sysv/systemfive.S @@ -107,18 +107,18 @@ systemfive.linux: systemfive.error: neg %eax / 𝑠𝑙𝑖𝑑𝑒 - .endfn systemfive.error + .endfn systemfive.error,globl,hidden systemfive.errno: mov %eax,errno(%rip) push $-1 pop %rax stc ret - .endfn systemfive.errno + .endfn systemfive.errno,globl,hidden systemfive.enosys: mov ENOSYS(%rip),%eax jmp systemfive.errno - .endfn systemfive.enosys + .endfn systemfive.enosys,globl,hidden systemfive.openbsd: shr $48,%rax jmp systemfive.bsd diff --git a/libc/sysv/sysv.mk b/libc/sysv/sysv.mk index 76a72e97..1e4bfa16 100644 --- a/libc/sysv/sysv.mk +++ b/libc/sysv/sysv.mk @@ -34,6 +34,7 @@ LIBC_SYSV_A_FILES := \ libc/sysv/restorert.S \ libc/sysv/syscall.S \ libc/sysv/systemfive.S \ + libc/sysv/vfork.S \ $(wildcard libc/sysv/stubs/*) \ $(wildcard libc/sysv/consts/*) \ $(wildcard libc/sysv/errfuns/*) @@ -86,6 +87,7 @@ LIBC_SYSV_CALLS_A_DEPS := \ $(call uniq,$(foreach x,$(LIBC_SYSV_CALLS_A_DIRECTDEPS),$($(x)))) $(LIBC_SYSV_CALLS_A): \ + libc/sysv/calls/ \ $(LIBC_SYSV_CALLS_A).pkg \ $(LIBC_SYSV_CALLS_A_OBJS) diff --git a/libc/escape/aescapesh.c b/libc/sysv/vfork.S similarity index 71% rename from libc/escape/aescapesh.c rename to libc/sysv/vfork.S index edb702e4..d44d2631 100644 --- a/libc/escape/aescapesh.c +++ b/libc/sysv/vfork.S @@ -1,5 +1,5 @@ -/*-*- 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│ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2020 Justine Alexandra Roberts Tunney │ │ │ @@ -17,12 +17,32 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/escape/escape.h" +#include "libc/dce.h" +#include "libc/macros.h" -/** - * Delegates to escapesh(), allocating as much memory as needed. - * @return bytes written excluding NUL, or -1 on alloc error or overflow - */ -int aescapesh(char **escaped, const char *unescaped, unsigned length) { - return aescape(escaped, 32, unescaped, length, escapesh); -} +/ Forks process without copying page tables. +/ +/ This is the same as fork() except it's optimized for the case +/ where the caller invokes exec() immediately afterwards. +/ +/ @return pid of child process or 0 if forked process +/ @returnstwice +vfork: mov __NR_vfork(%rip),%eax + cmp $-1,%eax + je systemfive.enosys + pop %rsi + testb IsBsd() + jnz vfork.bsd + syscall + push %rsi + cmp $-4095,%rax + jae systemfive.error + ret + .endfn vfork,globl + +vfork.bsd: + syscall + push %rsi + jc systemfive.errno + ret + .endfn vfork.bsd diff --git a/libc/testlib/showerror.c b/libc/testlib/showerror.c index 67c661cd..f8c50d10 100644 --- a/libc/testlib/showerror.c +++ b/libc/testlib/showerror.c @@ -20,6 +20,7 @@ #include "libc/calls/internal.h" #include "libc/errno.h" #include "libc/fmt/fmt.h" +#include "libc/log/color.h" #include "libc/log/internal.h" #include "libc/log/log.h" #include "libc/math.h" diff --git a/libc/testlib/showerror_.c b/libc/testlib/showerror_.c index 193a3c8b..b0392a72 100644 --- a/libc/testlib/showerror_.c +++ b/libc/testlib/showerror_.c @@ -21,6 +21,7 @@ #include "libc/calls/internal.h" #include "libc/errno.h" #include "libc/fmt/fmt.h" +#include "libc/log/color.h" #include "libc/log/internal.h" #include "libc/log/log.h" #include "libc/math.h" diff --git a/libc/time/dsleep.c b/libc/time/dsleep.c index 6a8acc41..fd6abd7a 100644 --- a/libc/time/dsleep.c +++ b/libc/time/dsleep.c @@ -17,8 +17,6 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/struct/timespec.h" -#include "libc/math.h" #include "libc/nexgen32e/nexgen32e.h" #include "libc/time/time.h" diff --git a/libc/escape/escapec.c b/libc/unicode/strnwidth.c similarity index 58% rename from libc/escape/escapec.c rename to libc/unicode/strnwidth.c index 3b3d26bb..46b8b60f 100644 --- a/libc/escape/escapec.c +++ b/libc/unicode/strnwidth.c @@ -17,52 +17,65 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/escape/escape.h" -#include "libc/limits.h" -#include "libc/sysv/errfuns.h" +#include "libc/macros.h" +#include "libc/str/thompike.h" +#include "libc/unicode/unicode.h" /** - * Escapes memory for inclusion in C string literals (or Python, etc.) + * Returns monospace display width of UTF-8 string. * - * The outer quotation marks are *not* added. + * - Control codes are discounted + * - ANSI escape sequences are discounted + * - East asian glyphs, emoji, etc. count as two * - * @param buf is the output area, which can't overlap and, no matter - * what, a NUL-terminator will always be placed in the buffer at - * an appropriate place, provided buf!=NULL && size!=0 - * @param size is the byte-length of the output area - * @param s is the data, which may have NUL characters - * @param l is the byte-length of s or -1 if s is NUL-terminated - * @return number of characters written, excluding NUL terminator; or, - * if the output buffer wasn't passed, or was too short, then the - * number of characters that *would* have been written is returned; - * since that's how the snprintf() API works; or -1 on overflow - * @see xaescapec() for an easier api + * @param s is NUL-terminated string + * @param n is max bytes to consider + * @return monospace display width */ -int escapec(char *buf, unsigned size, const char *s, unsigned l) { - if (l >= INT_MAX) return eoverflow(); - unsigned i, j = 0; - for (i = 0; i < l; ++i) { - unsigned t = cescapec(s[i]); - if (t) { - while (t) { - if (j < size) { - buf[j] = (unsigned char)t; - t >>= 8; - } - j++; +int strnwidth(const char *s, size_t n) { + wint_t c, w; + unsigned l, r; + enum { kAscii, kUtf8, kEsc, kCsi } t; + for (w = r = t = l = 0; n--;) { + if ((c = *s++ & 0xff)) { + switch (t) { + case kAscii: + if (0x20 <= c && c <= 0x7E || c == '\t') { + ++l; + } else if (c == 033) { + t = kEsc; + } else if (c >= 0300) { + t = kUtf8; + w = ThomPikeByte(c); + r = ThomPikeLen(c) - 1; + } + break; + case kUtf8: + if (ThomPikeCont(c)) { + w = ThomPikeMerge(w, c); + if (--r) break; + } + l += MAX(0, wcwidth(w)); + t = kAscii; + break; + case kEsc: + if (c == '[') { + t = kCsi; + } else if (!(040 <= c && c < 060)) { + t = kAscii; + } + break; + case kCsi: + if (!(060 <= c && c < 0100)) { + t = kAscii; + } + break; + default: + unreachable; } } else { - if (l == -1) { - break; - } + break; } } - if (buf && size) { - if (j < size) { - buf[j] = '\0'; - } else { - buf[size - 1] = '\0'; - } - } - return j; + return l; } diff --git a/libc/unicode/strwidth.c b/libc/unicode/strwidth.c index 8451d741..d71e2311 100644 --- a/libc/unicode/strwidth.c +++ b/libc/unicode/strwidth.c @@ -17,56 +17,18 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/bits/safemacros.h" -#include "libc/conv/conv.h" -#include "libc/limits.h" -#include "libc/str/internal.h" -#include "libc/str/str.h" -#include "libc/str/tpdecode.h" #include "libc/unicode/unicode.h" -#define kOneTrueTabWidth 8 - /** - * Returns monospace display width in UTF-8 string. + * Returns monospace display width of UTF-8 string. + * + * - Control codes are discounted + * - ANSI escape sequences are discounted + * - East asian glyphs, emoji, etc. count as two + * + * @param s is NUL-terminated string + * @return monospace display width */ -int(strwidth)(const char *s) { - return strnwidth(s, SIZE_MAX); -} - -int(strnwidth)(const char *s, size_t n) { - /* TODO(jart): Fix this function. */ - size_t l; - wint_t wc; - const unsigned char *p, *pe; - l = 0; - if (n) { - p = (const unsigned char *)s; - pe = (const unsigned char *)(n == SIZE_MAX ? INTPTR_MAX : (intptr_t)s + n); - for (;;) { - while (p < pe && iscont(*p)) p++; - if (p == pe || !*p) break; - if (*p == L'\t') { - if (l & (kOneTrueTabWidth - 1)) { - l += kOneTrueTabWidth - (l & (kOneTrueTabWidth - 1)); - } else { - l += kOneTrueTabWidth; - } - ++p; - } else if (*p == L'\e') { - while (++p < pe && *p) { - if (*p == '[' || *p == ';' || isdigit(*p)) { - continue; - } else { - ++p; - break; - } - } - } else { - p += abs(tpdecode((const char *)p, &wc)); - l += max(0, wcwidth(wc)); - } - } - } - return l; +int strwidth(const char *s) { + return strnwidth(s, -1); } diff --git a/libc/unicode/unicode.h b/libc/unicode/unicode.h index faf97953..63640b85 100644 --- a/libc/unicode/unicode.h +++ b/libc/unicode/unicode.h @@ -3,19 +3,6 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -/*───────────────────────────────────────────────────────────────────────────│─╗ -│ cosmopolitan § characters » unicode ─╬─│┼ -╚────────────────────────────────────────────────────────────────────────────│*/ - -extern const uint8_t kEastAsianWidth[]; -extern const uint32_t kEastAsianWidthBits; -extern const uint8_t kCombiningChars[]; -extern const uint32_t kCombiningCharsBits; - -/*───────────────────────────────────────────────────────────────────────────│─╗ -│ cosmopolitan § strings » multibyte » unicode ─╬─│┼ -╚────────────────────────────────────────────────────────────────────────────│*/ - int wcwidth(wchar_t) pureconst; int wcswidth(const wchar_t *) strlenesque; int wcsnwidth(const wchar_t *, size_t) strlenesque; @@ -24,26 +11,6 @@ int strnwidth(const char *, size_t) strlenesque; int strwidth16(const char16_t *) strlenesque; int strnwidth16(const char16_t *, size_t) strlenesque; -/*───────────────────────────────────────────────────────────────────────────│─╗ -│ cosmopolitan § unicode » generic typing ─╬─│┼ -╚────────────────────────────────────────────────────────────────────────────│*/ - -#if __STDC_VERSION__ + 0 >= 201112 - -#define strwidth(s) \ - _Generic(*(s), wchar_t \ - : wcswidth, char16_t \ - : strwidth16, default \ - : strwidth)(s) - -#define strnwidth(s, n) \ - _Generic(*(s), wchar_t \ - : wcswidth, char16_t \ - : strnwidth16, default \ - : strnwidth)(s, n) - -#endif /* C11 */ - COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* COSMOPOLITAN_LIBC_UNICODE_UNICODE_H_ */ diff --git a/libc/unicode/wcwidth.c b/libc/unicode/wcwidth.c index 0cd39d90..a10d0626 100644 --- a/libc/unicode/wcwidth.c +++ b/libc/unicode/wcwidth.c @@ -19,6 +19,11 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/unicode/unicode.h" +extern const uint8_t kEastAsianWidth[]; +extern const uint32_t kEastAsianWidthBits; +extern const uint8_t kCombiningChars[]; +extern const uint32_t kCombiningCharsBits; + /** * Returns cell width of monospace character. */ diff --git a/libc/x/x.h b/libc/x/x.h index d5454319..66aa5e3a 100644 --- a/libc/x/x.h +++ b/libc/x/x.h @@ -68,11 +68,6 @@ char *xstrcat(const char *, ...) paramsnonnull((1)) nullterminated() _XMAL; char *xstrmul(const char *, size_t) paramsnonnull((1)) _XMAL; char *xjoinpaths(const char *, const char *) paramsnonnull() _XMAL; char *xinet_ntop(int, const void *) _XPNN _XMAL; -char *xaescapec(const char *) _XPNN _XMAL; -char *xaescapesh(const char *) _XPNN _XMAL; -char *xaescapeshq(const char *) _XPNN _XMAL; -char *xaescape(const char *, int (*)(char *, unsigned, const char *, - unsigned)) _XPNN hidden _XMAL; /*───────────────────────────────────────────────────────────────────────────│─╗ │ cosmopolitan § eXtended apis » time ─╬─│┼ diff --git a/libc/x/x.mk b/libc/x/x.mk index aa6b6a4c..db5f5a24 100644 --- a/libc/x/x.mk +++ b/libc/x/x.mk @@ -35,7 +35,6 @@ LIBC_X_A_CHECKS = \ LIBC_X_A_DIRECTDEPS = \ LIBC_CALLS \ - LIBC_ESCAPE \ LIBC_FMT \ LIBC_MEM \ LIBC_NEXGEN32E \ diff --git a/libc/x/xaescapec.c b/libc/x/xaescapec.c deleted file mode 100644 index 54e93162..00000000 --- a/libc/x/xaescapec.c +++ /dev/null @@ -1,31 +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 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ -│ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ -│ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/escape/escape.h" -#include "libc/x/x.h" - -/** - * Delegates NUL-terminated string to escapec() or dies. - * - * The surrounding quotes are *not* included. Death hapens only on - * allocation error or int32 overflow, which are extremely unlikely. - * - * @return escaped string which must make its way to free() - */ -char *xaescapec(const char *unescaped) { return xaescape(unescaped, escapec); } diff --git a/libc/x/xaescapesh.c b/libc/x/xaescapesh.c deleted file mode 100644 index fcaf4a16..00000000 --- a/libc/x/xaescapesh.c +++ /dev/null @@ -1,34 +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 2020 Justine Alexandra Roberts Tunney │ -│ │ -│ This program is free software; you can redistribute it and/or modify │ -│ it under the terms of the GNU General Public License as published by │ -│ the Free Software Foundation; version 2 of the License. │ -│ │ -│ This program is distributed in the hope that it will be useful, but │ -│ WITHOUT ANY WARRANTY; without even the implied warranty of │ -│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ -│ General Public License for more details. │ -│ │ -│ You should have received a copy of the GNU General Public License │ -│ along with this program; if not, write to the Free Software │ -│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ -│ 02110-1301 USA │ -╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/escape/escape.h" -#include "libc/x/x.h" - -/** - * Delegates NUL-terminated string to escapesh() or dies. - * - * The surrounding single quotes are *not* included. Death hapens only - * on allocation error or int32 overflow. - * - * @return escaped string which must make its way to free() - * @see xaescapeshq() which adds quotes - */ -char *xaescapesh(const char *unescaped) { - return xaescape(unescaped, escapesh); -} diff --git a/net/http/http.mk b/net/http/http.mk index 0572727c..5b5c7898 100644 --- a/net/http/http.mk +++ b/net/http/http.mk @@ -38,6 +38,7 @@ NET_HTTP_A_DIRECTDEPS = \ LIBC_RUNTIME \ LIBC_SOCK \ LIBC_STDIO \ + LIBC_STR \ LIBC_STUBS \ LIBC_SYSV \ LIBC_TIME \ diff --git a/test/libc/fmt/palandprintf_test.c b/test/libc/fmt/palandprintf_test.c index 45eb6600..781cc369 100644 --- a/test/libc/fmt/palandprintf_test.c +++ b/test/libc/fmt/palandprintf_test.c @@ -29,7 +29,6 @@ #include "libc/bits/safemacros.h" #include "libc/conv/itoa.h" #include "libc/errno.h" -#include "libc/escape/escape.h" #include "libc/fmt/fmt.h" #include "libc/limits.h" #include "libc/math.h" diff --git a/test/libc/mem/malloc_test.c b/test/libc/mem/malloc_test.c index b0e65e8b..05a5a06f 100644 --- a/test/libc/mem/malloc_test.c +++ b/test/libc/mem/malloc_test.c @@ -73,4 +73,5 @@ TEST(malloc, test) { for (i = 0; i < ARRAYLEN(A); ++i) free(A[i]); for (i = 0; i < ARRAYLEN(maps); ++i) munmap(maps[i], mapsizes[i]); for (i = 0; i < ARRAYLEN(fds); ++i) close(fds[i]); + malloc_trim(0); } diff --git a/test/libc/nexgen32e/cescapec_test.c b/test/libc/nexgen32e/cescapec_test.c index 7469a1bd..08538322 100644 --- a/test/libc/nexgen32e/cescapec_test.c +++ b/test/libc/nexgen32e/cescapec_test.c @@ -17,7 +17,7 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/escape/escape.h" +#include "libc/str/str.h" #include "libc/testlib/testlib.h" TEST(cescapec, test) { diff --git a/test/libc/str/str_test.c b/test/libc/str/str_test.c index a97601cf..fad8f7c5 100644 --- a/test/libc/str/str_test.c +++ b/test/libc/str/str_test.c @@ -37,8 +37,8 @@ TEST(strclen, testAegeanNumberSupplementaryPlane) { EXPECT_EQ(18, strlen16(u"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); EXPECT_EQ(9, wcslen(L"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); EXPECT_EQ(9, strclen("𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); - EXPECT_EQ(9, strclen(u"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); - EXPECT_EQ(9, strclen(L"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); + EXPECT_EQ(9, strclen16(u"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); + EXPECT_EQ(9, wcslen(L"𐄷𐄸𐄹𐄺𐄻𐄼𐄽𐄾𐄿")); } TEST(strlen16, testCoolKidNulTerminator) { diff --git a/test/libc/str/isnotplaintext_test.c b/test/libc/str/strcpy_test.c similarity index 73% rename from test/libc/str/isnotplaintext_test.c rename to test/libc/str/strcpy_test.c index 2260806d..3772e267 100644 --- a/test/libc/str/isnotplaintext_test.c +++ b/test/libc/str/strcpy_test.c @@ -19,25 +19,23 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/str/str.h" #include "libc/testlib/ezbench.h" -#include "libc/testlib/hyperion.h" #include "libc/testlib/testlib.h" -#if 0 -void *isnotplaintext(const void *, size_t) - __attribute__((__pure__, __leaf__, __nothrow__)); -#endif - -TEST(isnotplaintext, test) { - EXPECT_EQ(NULL, isnotplaintext(kHyperion, kHyperionSize)); - EXPECT_STREQ("", isnotplaintext(kHyperion, kHyperionSize + 1)); +TEST(strcpy, test) { + char buf[64]; + EXPECT_STREQ("hello", strcpy(buf, "hello")); + EXPECT_STREQ("hello there what's up", strcpy(buf, "hello there what's up")); } -char *doit(char *data, size_t size) { - data = isnotplaintext(data, size); - asm volatile("" : "+r"(data)); - return data; -} - -BENCH(isnotplaintext, bench) { - EZBENCH(donothing, doit(kHyperion, kHyperionSize)); +BENCH(strcpy, bench) { + extern char *strcpy_(char *, const char *) asm("strcpy"); + static char buf[1024], buf2[1024]; + memset(buf2, -1, sizeof(buf2) - 1); + EZBENCH2("strcpy 1", donothing, strcpy_(buf, "")); + EZBENCH2("strcpy 2", donothing, strcpy_(buf, "1")); + EZBENCH2("strcpy 7", donothing, strcpy_(buf, "123456")); + EZBENCH2("strcpy 8", donothing, strcpy_(buf, "1234567")); + EZBENCH2("strcpy 9", donothing, strcpy_(buf, "12345678")); + EZBENCH2("strcpy 16", donothing, strcpy_(buf, "123456781234567")); + EZBENCH2("strcpy 1023", donothing, strcpy_(buf, buf2)); } diff --git a/test/libc/str/strlen_test.c b/test/libc/str/strlen_test.c index a80fac37..2a75d5ac 100644 --- a/test/libc/str/strlen_test.c +++ b/test/libc/str/strlen_test.c @@ -21,6 +21,7 @@ #include "libc/macros.h" #include "libc/nexgen32e/tinystrlen.h" #include "libc/str/str.h" +#include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" char u8[] = "utf-8 ☻"; @@ -129,3 +130,16 @@ TEST(tinystrnlen16, test) { EXPECT_EQ(2, tinystrnlen16(u"123", 2)); EXPECT_EQ(3, tinystrnlen16(u"123", 4)); } + +BENCH(strlen, bench) { + extern size_t strlen_(const char *) asm("strlen"); + static char b[1024]; + memset(b, -1, sizeof(b) - 1); + EZBENCH2("strlen 1", donothing, strlen_("")); + EZBENCH2("strlen 2", donothing, strlen_("1")); + EZBENCH2("strlen 7", donothing, strlen_("123456")); + EZBENCH2("strlen 8", donothing, strlen_("1234567")); + EZBENCH2("strlen 9", donothing, strlen_("12345678")); + EZBENCH2("strlen 16", donothing, strlen_("123456781234567")); + EZBENCH2("strlen 1023", donothing, strlen_(b)); +} diff --git a/libc/escape/aescapec.c b/test/libc/unicode/strwidth_test.c similarity index 86% rename from libc/escape/aescapec.c rename to test/libc/unicode/strwidth_test.c index 8fcdf306..634a0477 100644 --- a/libc/escape/aescapec.c +++ b/test/libc/unicode/strwidth_test.c @@ -17,12 +17,11 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/escape/escape.h" +#include "libc/testlib/testlib.h" +#include "libc/unicode/unicode.h" -/** - * Delegates to escapec(), allocating as much memory as needed. - * @return bytes written excluding NUL, or -1 on alloc error or overflow - */ -int aescapec(char **escaped, const char *unescaped, unsigned length) { - return aescape(escaped, 32, unescaped, length, escapec); +TEST(strwidth, test) { + EXPECT_EQ(5, strwidth("hello")); + EXPECT_EQ(5, strwidth("\1he\e[0;0mllo\e#8")); + EXPECT_EQ(10, strwidth("HELLO")); } diff --git a/test/libc/unicode/wcwidth_test.c b/test/libc/unicode/wcwidth_test.c index 54aa0365..686b487c 100644 --- a/test/libc/unicode/wcwidth_test.c +++ b/test/libc/unicode/wcwidth_test.c @@ -62,10 +62,6 @@ TEST(wcwidth, testCjkWidesAndCombiningLowLines_widthIsNotLength) { /*────────────────────────────────────────────────────┴─*/ } -TEST(strwidth, tab) { - EXPECT_EQ(32, strwidth("mov 0x0(%rip),%rcx \t")); -} - TEST(wcwidth, block) { EXPECT_EQ(1, wcwidth(u'▄')); } diff --git a/test/tool/build/lib/machine_test.c b/test/tool/build/lib/machine_test.c index 8b264199..568ea803 100644 --- a/test/tool/build/lib/machine_test.c +++ b/test/tool/build/lib/machine_test.c @@ -102,25 +102,27 @@ struct Machine *m; void SetUp(void) { m = NewMachine(); - m->ip = 0; - ReserveVirtual(m, 0, 4096); - ASSERT_EQ(0x5000, m->real.i); + m->mode = XED_MACHINE_MODE_LONG_64; + m->cr3 = AllocateLinearPage(m); + ReserveVirtual(m, 0, 4096, 0x0207); ASSERT_EQ(0x1007, Read64(m->real.p + 0x0000)); // PML4T ASSERT_EQ(0x2007, Read64(m->real.p + 0x1000)); // PDPT ASSERT_EQ(0x3007, Read64(m->real.p + 0x2000)); // PDE - ASSERT_EQ(0x4007, Read64(m->real.p + 0x3000)); // PT + ASSERT_EQ(0x0207, Read64(m->real.p + 0x3000)); // PT + ASSERT_EQ(0x4000, m->real.i); + ASSERT_EQ(1, m->memstat.reserved); + ASSERT_EQ(4, m->memstat.committed); + ASSERT_EQ(4, m->memstat.allocated); + ASSERT_EQ(3, m->memstat.pagetables); Write64(m->sp, 4096); } void TearDown(void) { FreeVirtual(m, 0, 4096); - ASSERT_EQ(0x5000, m->real.i); ASSERT_EQ(0x1007, Read64(m->real.p + 0x0000)); // PML4T ASSERT_EQ(0x2007, Read64(m->real.p + 0x1000)); // PDPT ASSERT_EQ(0x3007, Read64(m->real.p + 0x2000)); // PDE ASSERT_EQ(0x0000, Read64(m->real.p + 0x3000)); // PT - ASSERT_EQ(0x4000, m->realfree->i); - ASSERT_EQ(0x1000, m->realfree->n); FreeMachine(m); } diff --git a/test/tool/build/lib/pty_test.c b/test/tool/build/lib/pty_test.c index 12dc860f..080f26e6 100644 --- a/test/tool/build/lib/pty_test.c +++ b/test/tool/build/lib/pty_test.c @@ -26,12 +26,12 @@ #include "libc/unicode/unicode.h" #include "tool/build/lib/pty.h" -char *render(struct MachinePty *pty) { +char *render(struct Pty *pty) { static struct Buffer b; int y; b.i = 0; for (y = 0; y < pty->yn; ++y) { - MachinePtyAppendLine(pty, &b, y); + PtyAppendLine(pty, &b, y); } b.p[b.i] = 0; return b.p; @@ -76,10 +76,10 @@ static const char widelatin_golden[] = "\ "; TEST(pty, testFunWidth) { - struct MachinePty *pty = MachinePtyNew(); - MachinePtyWrite(pty, widelatin, ARRAYLEN(widelatin) - 1); + struct Pty *pty = NewPty(); + PtyWrite(pty, widelatin, ARRAYLEN(widelatin) - 1); EXPECT_STREQ(widelatin_golden, render(pty)); - MachinePtyFree(pty); + FreePty(pty); } const char hyperion[] aligned(16) = "\ @@ -130,10 +130,10 @@ m scribe my hand is in the grave. "; TEST(pty, testPureAscii_benefitsFromVectorization) { - struct MachinePty *pty = MachinePtyNew(); - MachinePtyWrite(pty, hyperion, ARRAYLEN(hyperion) - 1); + struct Pty *pty = NewPty(); + PtyWrite(pty, hyperion, ARRAYLEN(hyperion) - 1); EXPECT_STREQN(pty->wcs, hyperion_golden, ARRAYLEN(hyperion_golden) - 1); - MachinePtyFree(pty); + FreePty(pty); } static const char kKiloAnsi[] = "\ @@ -196,7 +196,7 @@ TEST(pty, testLongestPossibleCharacter) { EXPECT_EQ(60, strlen("\e[21;22;27;24;25;29;38;2;255;255;255;48;2;255;255;" "255m\377\277\277\277\277\277")); struct Buffer b = {0}; - struct MachinePty *pty = MachinePtyNew(); + struct Pty *pty = NewPty(); const char *s = "\e[1;2;3;4;5;6;7;9m" "h" "\e[0;" @@ -204,8 +204,8 @@ TEST(pty, testLongestPossibleCharacter) { "48;2;255;255;255m" "\377\277\277\277\277\277" "\e[0m"; - MachinePtyWrite(pty, s, strlen(s)); - MachinePtyAppendLine(pty, &b, 0); + PtyWrite(pty, s, strlen(s)); + PtyAppendLine(pty, &b, 0); AppendChar(&b, '\0'); EXPECT_STREQ("\e[1;2;4;7;5;9m" "𝒉" @@ -214,22 +214,23 @@ TEST(pty, testLongestPossibleCharacter) { "\e[0m▂ " " ", b.p); - MachinePtyFree(pty); + FreePty(pty); free(b.p); } TEST(pty, test) { - struct MachinePty *pty = MachinePtyNew(); - MachinePtyWrite(pty, kKiloAnsi, strlen(kKiloAnsi)); + struct Pty *pty = NewPty(); + PtyWrite(pty, kKiloAnsi, strlen(kKiloAnsi)); EXPECT_STREQN(kKiloGolden, pty->wcs, wcslen(kKiloGolden)); - MachinePtyFree(pty); + FreePty(pty); } BENCH(pty, bench) { - struct MachinePty *pty = MachinePtyNew(); + struct Pty *pty = NewPty(); EZBENCH2("pty write ascii", donothing, - MachinePtyWrite(pty, hyperion, sizeof(hyperion) - 1)); + PtyWrite(pty, hyperion, sizeof(hyperion) - 1)); EZBENCH2("pty write kilo", donothing, - MachinePtyWrite(pty, kKiloAnsi, sizeof(kKiloAnsi) - 1)); + PtyWrite(pty, kKiloAnsi, sizeof(kKiloAnsi) - 1)); EZBENCH2("pty render", donothing, render(pty)); + FreePty(pty); } diff --git a/third_party/dlmalloc/dlmalloc.h b/third_party/dlmalloc/dlmalloc.h index b8963288..6007e034 100644 --- a/third_party/dlmalloc/dlmalloc.h +++ b/third_party/dlmalloc/dlmalloc.h @@ -1248,6 +1248,7 @@ void *dlrealloc_in_place(void *, size_t) hidden; void *dlvalloc(size_t) hidden; void *dlpvalloc(size_t) hidden; void *dlmemalign(size_t, size_t) hidden; +int dlmalloc_trim(size_t) hidden; size_t dlmalloc_usable_size(const void *) hidden; int dlposix_memalign(void **, size_t, size_t) hidden; void **dlindependent_calloc(size_t, size_t, void *[]) hidden; diff --git a/third_party/dlmalloc/malloc_trim.c b/third_party/dlmalloc/malloc_trim.c index 63a1d1ef..ef361c08 100644 --- a/third_party/dlmalloc/malloc_trim.c +++ b/third_party/dlmalloc/malloc_trim.c @@ -20,7 +20,7 @@ * * @return 1 if it actually released any memory, else 0 */ -int malloc_trim(size_t pad) { +int dlmalloc_trim(size_t pad) { int result = 0; ensure_initialization(); if (!PREACTION(g_dlmalloc)) { diff --git a/third_party/regex/regerror.c b/third_party/regex/regerror.c index cf02d785..385ed947 100644 --- a/third_party/regex/regerror.c +++ b/third_party/regex/regerror.c @@ -49,6 +49,6 @@ static const char kRegexErrors[] = */ size_t regerror(int e, const regex_t *preg, char *buf, size_t size) { return 1 + snprintf(buf, size, "%s", - firstnonnull(indexdoublenulstring(kRegexErrors, e), + firstnonnull(IndexDoubleNulString(kRegexErrors, e), "Unknown error")); } diff --git a/third_party/xed/xederror.c b/third_party/xed/xederror.c index 19f642d1..ab6ff018 100644 --- a/third_party/xed/xederror.c +++ b/third_party/xed/xederror.c @@ -22,7 +22,7 @@ /** * Xed error code names. * - * puts(indexdoublenulstring(kXedErrorNames, xedd->op.error)); + * puts(IndexDoubleNulString(kXedErrorNames, xedd->op.error)); * * @see XedError */ diff --git a/tool/build/blinkenlights.c b/tool/build/blinkenlights.c index 02932944..325ded7e 100644 --- a/tool/build/blinkenlights.c +++ b/tool/build/blinkenlights.c @@ -34,7 +34,10 @@ #include "libc/errno.h" #include "libc/fmt/bing.h" #include "libc/fmt/fmt.h" +#include "libc/intrin/pcmpeqb.h" +#include "libc/intrin/pmovmskb.h" #include "libc/log/check.h" +#include "libc/log/color.h" #include "libc/log/log.h" #include "libc/macros.h" #include "libc/math.h" @@ -143,21 +146,19 @@ FEATURES\n\ #define kXmmHex 1 #define kXmmChar 2 -#define CTRL(C) ((C) ^ 0100) +#define kMouseLeftDown 0 +#define kMouseMiddleDown 1 +#define kMouseRightDown 2 +#define kMouseLeftUp 4 +#define kMouseMiddleUp 5 +#define kMouseRightUp 6 +#define kMouseLeftDrag 32 +#define kMouseMiddleDrag 33 +#define kMouseRightDrag 34 +#define kMouseWheelUp 64 +#define kMouseWheelDown 65 -enum Mouse { - kMouseLeftDown = 0, - kMouseMiddleDown = 1, - kMouseRightDown = 2, - kMouseLeftUp = 4, - kMouseMiddleUp = 5, - kMouseRightUp = 6, - kMouseLeftDrag = 32, - kMouseMiddleDrag = 33, - kMouseRightDrag = 34, - kMouseWheelUp = 64, - kMouseWheelDown = 65, -}; +#define CTRL(C) ((C) ^ 0100) struct MachineState { uint64_t ip; @@ -171,6 +172,7 @@ struct MachineState { uint8_t xmm[16][16]; struct MachineFpu fpu; struct MachineSse sse; + struct MachineMemstat memstat; }; struct Panels { @@ -196,8 +198,9 @@ struct Panels { struct Panel writedata; struct Panel stackhr; struct Panel stack; + struct Panel status; }; - struct Panel p[20]; + struct Panel p[21]; }; }; @@ -230,6 +233,7 @@ static int readzoom; static int writezoom; static int stackzoom; +static long ips; static long rombase; static long codesize; static int64_t opstart; @@ -240,20 +244,23 @@ static int64_t writestart; static int64_t stackstart; static int64_t framesstart; static int64_t breakpointsstart; +static uint64_t last_opcount; static char *codepath; static void *onbusted; static char *statusmessage; static struct Machine *m; -static struct MachinePty *pty; +static struct Pty *pty; static struct Panels pan; static struct MachineState laststate; static struct Breakpoints breakpoints; +static struct MachineMemstat lastmemstat; static struct Elf elf[1]; static struct Dis dis[1]; static uint8_t xmmtype[16]; static uint8_t xmmsize[16]; +long double last_seconds; static long double statusexpires; static struct termios oldterm; static char logpath[PATH_MAX]; @@ -386,6 +393,18 @@ static int64_t GetSp(void) { } } +static int64_t ReadWord(uint8_t *p) { + switch (GetPointerWidth()) { + default: + case 8: + return Read64(p); + case 4: + return Read32(p); + case 2: + return Read16(p); + } +} + static void UpdateXmmTypes(int regtype, int rmtype) { xmmtype[RexrReg(m->xedd->op.rde)] = regtype; if (IsModrmRegister(m->xedd->op.rde)) { @@ -519,6 +538,18 @@ static void UpdateXmmType(void) { UpdateXmmSizes(1, 2); UpdateXmmTypes(kXmmIntegral, kXmmIntegral); break; + case 0x128: // MOVAPS Vps Wps + if (IsModrmRegister(m->xedd->op.rde)) { + xmmtype[RexrReg(m->xedd->op.rde)] = xmmtype[RexbRm(m->xedd->op.rde)]; + xmmsize[RexrReg(m->xedd->op.rde)] = xmmsize[RexbRm(m->xedd->op.rde)]; + } + break; + case 0x129: // MOVAPS Wps Vps + if (IsModrmRegister(m->xedd->op.rde)) { + xmmtype[RexbRm(m->xedd->op.rde)] = xmmtype[RexrReg(m->xedd->op.rde)]; + xmmsize[RexbRm(m->xedd->op.rde)] = xmmsize[RexrReg(m->xedd->op.rde)]; + } + break; case 0x16F: // MOVDQA Vdq Wdq if (Osz(m->xedd->op.rde) && IsModrmRegister(m->xedd->op.rde)) { xmmtype[RexrReg(m->xedd->op.rde)] = xmmtype[RexbRm(m->xedd->op.rde)]; @@ -671,7 +702,6 @@ static void OnSigAlarm(void) { static void OnSigCont(void) { TuiRejuvinate(); - SetupDraw(); Redraw(); } @@ -771,12 +801,12 @@ void TuiSetup(void) { LoadSyms(); ResolveBreakpoints(); ioctl(ttyout, TCGETS, &oldterm); - xsigaction(SIGALRM, OnSigAlarm, 0, 0, 0); xsigaction(SIGINT, OnSigInt, 0, 0, oldsig + 3); atexit(TtyRestore2); once = true; report = true; } + setitimer(ITIMER_REAL, &((struct itimerval){0}), NULL); xsigaction(SIGCONT, OnSigCont, SA_RESTART | SA_NODEFER, 0, oldsig + 2); CopyMachineState(&laststate); TuiRejuvinate(); @@ -798,6 +828,9 @@ static void ExecSetup(void) { } once = true; } + setitimer(ITIMER_REAL, + &((struct itimerval){{0, 1. / 60 * 1e6}, {0, 1. / 60 * 1e6}}), + NULL); } static void AppendPanel(struct Panel *p, long line, const char *s) { @@ -807,12 +840,14 @@ static void AppendPanel(struct Panel *p, long line, const char *s) { } static bool IsXmmNonZero(long start, long end) { - long i, j; + long i; + uint8_t v1[16], vz[16]; for (i = start; i < end; ++i) { - for (j = 0; j < 16; ++j) { - if (m->xmm[i][j]) { - return true; - } + memset(vz, 0, 16); + memcpy(v1, m->xmm[i], 16); + pcmpeqb(v1, v1, vz); + if (pmovmskb(v1) != 0xffff) { + return true; } } return false; @@ -840,16 +875,8 @@ static int PickNumberOfXmmRegistersToShow(void) { } } -static void SetupDraw(void) { - int i, j, n, a, b, cpuy, ssey, dx[2], c2y[3], c3y[5]; - - for (i = 0; i < ARRAYLEN(pan.p); ++i) { - n = pan.p[i].bottom - pan.p[i].top; - for (j = 0; j < n; ++j) { - free(pan.p[i].lines[j].p); - } - free(pan.p[i].lines); - } +void SetupDraw(void) { + int i, j, n, a, b, yn, cpuy, ssey, dx[2], c2y[3], c3y[5]; cpuy = 9; if (IsSegNonZero()) cpuy += 2; @@ -861,20 +888,21 @@ static void SetupDraw(void) { dx[1] = txn >= a + b ? txn - a : txn; dx[0] = txn >= a + b + b ? txn - a - b : dx[1]; - a = 1 / 8. * tyn; - b = 3 / 8. * tyn; + yn = tyn - 1; + a = 1 / 8. * yn; + b = 3 / 8. * yn; c2y[0] = a * .7; c2y[1] = a * 2; c2y[2] = a * 2 + b; - if (tyn - c2y[2] > 26) { - c2y[1] -= tyn - c2y[2] - 26; - c2y[2] = tyn - 26; + if (yn - c2y[2] > 26) { + c2y[1] -= yn - c2y[2] - 26; + c2y[2] = yn - 26; } - if (tyn - c2y[2] < 26) { - c2y[2] = tyn - 26; + if (yn - c2y[2] < 26) { + c2y[2] = yn - 26; } - a = (tyn - (cpuy + ssey) - 3) / 4; + a = (yn - (cpuy + ssey) - 3) / 4; c3y[0] = cpuy; c3y[1] = cpuy + ssey; c3y[2] = cpuy + ssey + 1 + 1 + a * 1; @@ -885,8 +913,8 @@ static void SetupDraw(void) { pan.disassembly.top = 0; pan.disassembly.left = 0; - pan.disassembly.bottom = tyn; - pan.disassembly.right = dx[0]; + pan.disassembly.bottom = yn; + pan.disassembly.right = dx[0] - 1; /* COLUMN #2: BREAKPOINTS, MEMORY MAPS, BACKTRACE, DISPLAY */ @@ -927,7 +955,7 @@ static void SetupDraw(void) { pan.display.top = c2y[2] + 1; pan.display.left = dx[0]; - pan.display.bottom = tyn; + pan.display.bottom = yn; pan.display.right = dx[1] - 1; /* COLUMN #3: REGISTERS, VECTORS, CODE, MEMORY READS, MEMORY WRITES, STACK */ @@ -984,18 +1012,38 @@ static void SetupDraw(void) { pan.stack.top = c3y[4] + 1; pan.stack.left = dx[1]; - pan.stack.bottom = tyn; + pan.stack.bottom = yn; pan.stack.right = txn; + pan.status.top = yn; + pan.status.left = 0; + pan.status.bottom = yn + 1; + pan.status.right = txn; + for (i = 0; i < ARRAYLEN(pan.p); ++i) { - if (pan.p[i].top > pan.p[i].bottom) pan.p[i].top = pan.p[i].bottom = 0; - if (pan.p[i].left > pan.p[i].right) pan.p[i].left = pan.p[i].right = 0; - pan.p[i].lines = - xcalloc(pan.p[i].bottom - pan.p[i].top, sizeof(struct Buffer)); + if (pan.p[i].left > pan.p[i].right) { + pan.p[i].left = pan.p[i].right = 0; + } + if (pan.p[i].top > pan.p[i].bottom) { + pan.p[i].top = pan.p[i].bottom = 0; + } + n = pan.p[i].bottom - pan.p[i].top; + if (n == pan.p[i].n) { + for (j = 0; j < n; ++j) { + pan.p[i].lines[j].i = 0; + } + } else { + for (j = 0; j < pan.p[i].n; ++j) { + free(pan.p[i].lines[j].p); + } + free(pan.p[i].lines); + pan.p[i].lines = xcalloc(n, sizeof(struct Buffer)); + pan.p[i].n = n; + } } - MachinePtyResize(pty, pan.display.bottom - pan.display.top, - pan.display.right - pan.display.left); + PtyResize(pty, pan.display.bottom - pan.display.top, + pan.display.right - pan.display.left); } static long Disassemble(void) { @@ -1043,30 +1091,30 @@ static void DrawHr(struct Panel *p, const char *s) { void DrawTerminal(struct Panel *p) { long i, y, yn; - if (pty->conf & kMachinePtyBell) { + if (pty->conf & kPtyBell) { if (!alarmed) { alarmed = true; setitimer(ITIMER_REAL, &((struct itimerval){{0, 0}, {0, 800000}}), NULL); } AppendStr(&pan.displayhr.lines[0], "\e[1m"); } - AppendStr( - &pan.displayhr.lines[0], - gc(xasprintf("──────────TELETYPEWRITER──%s──%s──%s──%s", - (pty->conf & kMachinePtyLed1) ? "\e[1;31m◎\e[0m" : "○", - (pty->conf & kMachinePtyLed2) ? "\e[1;32m◎\e[0m" : "○", - (pty->conf & kMachinePtyLed3) ? "\e[1;33m◎\e[0m" : "○", - (pty->conf & kMachinePtyLed4) ? "\e[1;34m◎\e[0m" : "○"))); + AppendStr(&pan.displayhr.lines[0], + gc(xasprintf("──────────TELETYPEWRITER──%s──%s──%s──%s", + (pty->conf & kPtyLed1) ? "\e[1;31m◎\e[0m" : "○", + (pty->conf & kPtyLed2) ? "\e[1;32m◎\e[0m" : "○", + (pty->conf & kPtyLed3) ? "\e[1;33m◎\e[0m" : "○", + (pty->conf & kPtyLed4) ? "\e[1;34m◎\e[0m" : "○"))); for (i = 36; i < pan.displayhr.right - pan.displayhr.left; ++i) { AppendWide(&pan.displayhr.lines[0], u'─'); } for (yn = MIN(pty->yn, p->bottom - p->top), y = 0; y < yn; ++y) { - MachinePtyAppendLine(pty, p->lines + y, y); + PtyAppendLine(pty, p->lines + y, y); AppendStr(p->lines + y, "\e[0m"); } } void DrawDisplay(struct Panel *p) { + if (p->top == p->bottom) return; switch (vidya) { case 7: DrawHr(&pan.displayhr, "MONOCHROME DISPLAY ADAPTER"); @@ -1140,6 +1188,7 @@ static void DrawSt(struct Panel *p, long i, long r) { static void DrawCpu(struct Panel *p) { char buf[48]; + if (p->top == p->bottom) return; DrawRegister(p, 0, 7), DrawRegister(p, 0, 0), DrawSt(p, 0, 0); DrawRegister(p, 1, 6), DrawRegister(p, 1, 3), DrawSt(p, 1, 1); DrawRegister(p, 2, 2), DrawRegister(p, 2, 5), DrawSt(p, 2, 2); @@ -1239,6 +1288,7 @@ static void DrawXmm(struct Panel *p, long i, long r) { static void DrawSse(struct Panel *p) { long i; + if (p->top == p->bottom) return; for (i = 0; i < MIN(16, MAX(0, p->bottom - p->top)); ++i) { DrawXmm(p, i, i); } @@ -1314,6 +1364,7 @@ static void DrawMemory(struct Panel *p, int zoom, long startline, long histart, char buf[16]; bool high, changed; long i, j, k, c, width; + if (p->top == p->bottom) return; high = false; width = DUMPWIDTH * (1 << zoom); for (i = 0; i < p->bottom - p->top; ++i) { @@ -1342,6 +1393,7 @@ static void DrawMemory(struct Panel *p, int zoom, long startline, long histart, static void DrawMaps(struct Panel *p) { int i; char *text, *p1, *p2; + if (p->top == p->bottom) return; p1 = text = FormatPml4t(m); for (i = 0; p1; ++i, p1 = p2) { if ((p2 = strchr(p1, '\n'))) *p2++ = '\0'; @@ -1357,6 +1409,7 @@ static void DrawBreakpoints(struct Panel *p) { const char *name; char *s, buf[256]; long i, line, sym; + if (p->top == p->bottom) return; for (line = 0, i = breakpoints.i; i--;) { if (breakpoints.p[i].disable) continue; if (line >= breakpointsstart) { @@ -1396,6 +1449,7 @@ static void DrawFrames(struct Panel *p) { const char *name; char *s, line[256]; int64_t sp, bp, rp; + if (p->top == p->bottom) return; rp = m->ip; bp = Read64(m->bp); sp = Read64(m->sp); @@ -1427,8 +1481,8 @@ static void DrawFrames(struct Panel *p) { break; } sp = bp; - bp = Read64(r + 0); - rp = Read64(r + 8); + bp = ReadWord(r + 0); + rp = ReadWord(r + 8); } } @@ -1466,8 +1520,60 @@ static bool IsExecuting(void) { return (action & (CONTINUE | STEP | NEXT | FINISH)) && !(action & FAILURE); } +static int AppendStat(struct Buffer *b, const char *name, int64_t value, + bool changed) { + int width; + AppendChar(b, ' '); + if (changed) AppendStr(b, "\e[31m"); + width = AppendFmt(b, "%,8ld %s", value, name); + if (changed) AppendStr(b, "\e[39m"); + return 1 + width; +} + +void DrawStatus(struct Panel *p) { + int yn, xn, rw; + struct Buffer s; + struct MachineMemstat *a, *b; + yn = p->top - p->bottom; + xn = p->right - p->left; + if (!yn || !xn) return; + rw = 0; + a = &m->memstat; + b = &lastmemstat; + memset(&s, 0, sizeof(s)); + if (ips > 0) rw += AppendStat(&s, "ips", ips, false); + rw += AppendStat(&s, "kb", m->real.n / 1024, false); + rw += AppendStat(&s, "reserve", a->reserved, a->reserved != b->reserved); + rw += AppendStat(&s, "commit", a->committed, a->committed != b->committed); + rw += AppendStat(&s, "freed", a->freed, a->freed != b->freed); + rw += AppendStat(&s, "tables", a->pagetables, a->pagetables != b->pagetables); + rw += AppendStat(&s, "fds", m->fds.i, false); + AppendFmt(&p->lines[0], "\e[7m%-*s%s\e[0m", xn - rw, + statusmessage && nowl() < statusexpires ? statusmessage + : "das blinkenlights", + s.p); + free(s.p); + memcpy(b, a, sizeof(*a)); +} + +static void PreventBufferbloat(void) { + long double now, rate; + static long double last; + now = nowl(); + rate = 1. / 60; + if (now - last < rate) { + dsleep(rate - (now - last)); + } + last = now; +} + static void Redraw(void) { int i, j; + ScrollOp(&pan.disassembly, GetDisIndex()); + if (last_opcount) { + ips = unsignedsubtract(opcount, last_opcount) / (nowl() - last_seconds); + } + SetupDraw(); for (i = 0; i < ARRAYLEN(pan.p); ++i) { for (j = 0; j < pan.p[i].bottom - pan.p[i].top; ++j) { pan.p[i].lines[j].i = 0; @@ -1478,7 +1584,7 @@ static void Redraw(void) { DrawCpu(&pan.registers); DrawSse(&pan.sse); DrawHr(&pan.breakpointshr, "BREAKPOINTS"); - DrawHr(&pan.mapshr, "MAPS"); + DrawHr(&pan.mapshr, "PML4T"); DrawHr(&pan.frameshr, m->bofram[0] ? "PROTECTED FRAMES" : "FRAMES"); DrawHr(&pan.ssehr, "SSE"); DrawHr(&pan.codehr, "CODE"); @@ -1496,19 +1602,20 @@ static void Redraw(void) { m->writeaddr + m->writesize); DrawMemory(&pan.stack, stackzoom, stackstart, GetSp(), GetSp() + GetPointerWidth()); + DrawStatus(&pan.status); + PreventBufferbloat(); if (PrintPanels(ttyout, ARRAYLEN(pan.p), pan.p, tyn, txn) == -1) { LOGF("PrintPanels Interrupted"); CHECK_EQ(EINTR, errno); } - if (statusmessage && nowl() < statusexpires) { - TtyWriteString(statusmessage); - } + last_opcount = opcount; + last_seconds = nowl(); + CopyMachineState(&laststate); } static void ReactiveDraw(void) { if (tuimode) { m->ip -= m->xedd->length; - SetupDraw(); Redraw(); m->ip += m->xedd->length; tick = speed; @@ -1518,7 +1625,7 @@ static void ReactiveDraw(void) { static void HandleAlarm(void) { alarmed = false; action &= ~ALARM; - pty->conf &= ~kMachinePtyBell; + pty->conf &= ~kPtyBell; free(statusmessage); statusmessage = NULL; } @@ -1547,7 +1654,7 @@ static void HandleAppReadInterrupt(void) { } static int OnPtyFdClose(int fd) { - return 0; + return close(fd); } static bool HasPendingInput(int fd) { @@ -1564,7 +1671,7 @@ static ssize_t ReadPtyFdDirect(int fd, void *data, size_t size) { ssize_t rc; DEBUGF("ReadPtyFdDirect"); buf = malloc(PAGESIZE); - pty->conf |= kMachinePtyBlinkcursor; + pty->conf |= kPtyBlinkcursor; if (tuimode) DisableMouseTracking(); for (;;) { ReactiveDraw(); @@ -1573,11 +1680,11 @@ static ssize_t ReadPtyFdDirect(int fd, void *data, size_t size) { HandleAppReadInterrupt(); } if (tuimode) EnableMouseTracking(); - pty->conf &= ~kMachinePtyBlinkcursor; + pty->conf &= ~kPtyBlinkcursor; if (rc > 0) { - MachinePtyWriteInput(pty, buf, rc); + PtyWriteInput(pty, buf, rc); ReactiveDraw(); - rc = MachinePtyRead(pty, data, size); + rc = PtyRead(pty, data, size); } free(buf); return rc; @@ -1596,7 +1703,7 @@ static ssize_t OnPtyFdReadv(int fd, const struct iovec *iov, int iovlen) { } } if (size) { - if (!(rc = MachinePtyRead(pty, data, size))) { + if (!(rc = PtyRead(pty, data, size))) { rc = ReadPtyFdDirect(fd, data, size); } return rc; @@ -1605,14 +1712,16 @@ static ssize_t OnPtyFdReadv(int fd, const struct iovec *iov, int iovlen) { } } -static void DrawTerminalOnly(void) { +static void DrawDisplayOnly(struct Panel *p) { struct Buffer b; int i, y, yn, xn, tly, tlx, conf; - conf = pty->conf & kMachinePtyNocursor; - pty->conf |= kMachinePtyNocursor; + yn = MIN(tyn, p->bottom - p->top); + xn = MIN(txn, p->right - p->left); + for (i = 0; i < yn; ++i) { + p->lines[i].i = 0; + } + DrawDisplay(p); memset(&b, 0, sizeof(b)); - yn = MIN(tyn, pty->yn); - xn = MIN(txn, pty->xn); tly = tyn / 2 - yn / 2; tlx = txn / 2 - xn / 2; AppendStr(&b, "\e[0m\e[H"); @@ -1622,24 +1731,21 @@ static void DrawTerminalOnly(void) { for (i = 0; i < tlx; ++i) { AppendChar(&b, ' '); } - MachinePtyAppendLine(pty, &b, y - tly); + AppendData(&b, p->lines[y - tly].p, p->lines[y - tly].i); } AppendStr(&b, "\e[0m\e[K"); } - AppendFmt(&b, "\e[%d;%dH", tly + pty->y + 1, tlx + pty->x + 1); write(ttyout, b.p, b.i); free(b.p); - pty->conf |= conf; } static ssize_t OnPtyFdWritev(int fd, const struct iovec *iov, int iovlen) { int i; size_t size; for (size = i = 0; i < iovlen; ++i) { - MachinePtyWrite(pty, iov[i].iov_base, iov[i].iov_len); + PtyWrite(pty, iov[i].iov_base, iov[i].iov_len); size += iov[i].iov_len; } - if (!tuimode) DrawTerminalOnly(); return size; } @@ -1651,27 +1757,27 @@ static int OnPtyFdTiocgwinsz(int fd, struct winsize *ws) { static int OnPtyFdTcgets(int fd, struct termios *c) { memset(c, 0, sizeof(*c)); - if (!(pty->conf & kMachinePtyNocanon)) c->c_iflag |= ICANON; - if (!(pty->conf & kMachinePtyNoecho)) c->c_iflag |= ECHO; - if (!(pty->conf & kMachinePtyNoopost)) c->c_oflag |= OPOST; + if (!(pty->conf & kPtyNocanon)) c->c_iflag |= ICANON; + if (!(pty->conf & kPtyNoecho)) c->c_iflag |= ECHO; + if (!(pty->conf & kPtyNoopost)) c->c_oflag |= OPOST; return 0; } static int OnPtyFdTcsets(int fd, uint64_t request, struct termios *c) { if (c->c_iflag & ICANON) { - pty->conf &= ~kMachinePtyNocanon; + pty->conf &= ~kPtyNocanon; } else { - pty->conf |= kMachinePtyNocanon; + pty->conf |= kPtyNocanon; } if (c->c_iflag & ECHO) { - pty->conf &= ~kMachinePtyNoecho; + pty->conf &= ~kPtyNoecho; } else { - pty->conf |= kMachinePtyNoecho; + pty->conf |= kPtyNoecho; } if (c->c_oflag & OPOST) { - pty->conf &= ~kMachinePtyNoopost; + pty->conf &= ~kPtyNoopost; } else { - pty->conf |= kMachinePtyNoopost; + pty->conf |= kPtyNoopost; } return 0; } @@ -1732,14 +1838,13 @@ static void OnSimdException(void) { } static void OnUndefinedInstruction(void) { - die(); strcpy(systemfailure, "UNDEFINED INSTRUCTION"); LaunchDebuggerReactively(); } static void OnDecodeError(void) { strcpy(stpcpy(systemfailure, "DECODE: "), - indexdoublenulstring(kXedErrorNames, m->xedd->op.error)); + IndexDoubleNulString(kXedErrorNames, m->xedd->op.error)); LaunchDebuggerReactively(); } @@ -1854,15 +1959,15 @@ static void OnVidyaServiceGetMode(void) { } static void OnVidyaServiceSetCursorPosition(void) { - MachinePtySetY(pty, m->dx[1]); - MachinePtySetX(pty, m->dx[0]); + PtySetY(pty, m->dx[1]); + PtySetX(pty, m->dx[0]); } static void OnVidyaServiceGetCursorPosition(void) { m->dx[1] = pty->y; m->dx[0] = pty->x; m->cx[1] = 5; // cursor ▂ scan lines 5..7 of 0..7 - m->cx[0] = 7 | !!(pty->conf & kMachinePtyNocursor) << 5; + m->cx[0] = 7 | !!(pty->conf & kPtyNocursor) << 5; } static int GetVidyaByte(unsigned char b) { @@ -1880,7 +1985,7 @@ static void OnVidyaServiceWriteCharacter(void) { p += tpencode(p, 8, GetVidyaByte(m->ax[0]), false); p = stpcpy(p, "\e8"); for (i = Read16(m->cx); i--;) { - MachinePtyWrite(pty, buf, p - buf); + PtyWrite(pty, buf, p - buf); } } @@ -1902,7 +2007,7 @@ static void OnVidyaServiceTeletypeOutput(void) { char buf[12]; n = FormatCga(m->bx[0], buf); n += tpencode(buf + n, 6, VidyaServiceXlatTeletype(m->ax[0]), false); - MachinePtyWrite(pty, buf, n); + PtyWrite(pty, buf, n); } static void OnVidyaService(void) { @@ -1933,7 +2038,7 @@ static void OnVidyaService(void) { static void OnKeyboardServiceReadKeyPress(void) { uint8_t b; ssize_t rc; - pty->conf |= kMachinePtyBlinkcursor; + pty->conf |= kPtyBlinkcursor; if (tuimode) DisableMouseTracking(); for (;;) { ReactiveDraw(); @@ -1942,7 +2047,7 @@ static void OnKeyboardServiceReadKeyPress(void) { HandleAppReadInterrupt(); } if (tuimode) EnableMouseTracking(); - pty->conf &= ~kMachinePtyBlinkcursor; + pty->conf &= ~kPtyBlinkcursor; ReactiveDraw(); if (b == 0x7F) b = '\b'; m->ax[0] = b; @@ -2065,16 +2170,12 @@ static void SetStatus(const char *fmt, ...) { va_list va; int y, x, n; va_start(va, fmt); - s = gc(xvasprintf(fmt, va)); + s = xvasprintf(fmt, va); va_end(va); - n = strwidth(s); - y = tyn - (n / txn + 1); - x = txn / 2 - n / 2; free(statusmessage); - statusmessage = xasprintf("\e[0m\e[%d;%dH%s", y + 1, x + 1, s); - TtyWriteString(statusmessage); - setitimer(ITIMER_REAL, &((struct itimerval){{0, 0}, {1, 0}}), NULL); + statusmessage = s; statusexpires = nowl() + 1; + setitimer(ITIMER_REAL, &((struct itimerval){{0, 0}, {1, 0}}), NULL); } static void OnTurbo(void) { @@ -2201,8 +2302,7 @@ static void Sleep(int ms) { } static void OnMouse(char *p) { - enum Mouse e; - int i, x, y, dy; + int e, i, x, y, dy; struct Panel *ep; e = strtol(p, &p, 10); if (*p == ';') ++p; @@ -2251,7 +2351,10 @@ static void OnMouse(char *p) { static void ReadKeyboard(void) { char buf[64], *p = buf; if (readansi(ttyin, buf, sizeof(buf)) == -1) { - if (errno == EINTR) return; + if (errno == EINTR) { + LOGF("readkeyboard interrupted"); + return; + } FATALF("readkeyboard failed: %s", strerror(errno)); } switch (*p++) { @@ -2384,39 +2487,42 @@ static void Exec(void) { if (!(interrupt = setjmp(m->onhalt))) { if (!(action & CONTINUE) && (bp = IsAtBreakpoint(&breakpoints, GetIp())) != -1) { - LOGF("BREAK %p", breakpoints.p[bp].addr); + LOGF("BREAK1 %p", breakpoints.p[bp].addr); tuimode = true; LoadInstruction(m); ExecuteInstruction(m); + ++opcount; CheckFramePointer(); - ops++; } else { action &= ~CONTINUE; for (;;) { LoadInstruction(m); + if ((bp = IsAtBreakpoint(&breakpoints, GetIp())) != -1) { + LOGF("BREAK2 %p", breakpoints.p[bp].addr); + action &= ~(FINISH | NEXT | CONTINUE); + tuimode = true; + break; + } ExecuteInstruction(m); + ++opcount; KeepGoing: CheckFramePointer(); - ops++; - if (action || breakpoints.i) { - if (action & EXIT) { - LOGF("EXEC EXIT"); - break; - } - if (action & INT) { - LOGF("EXEC INT"); - if (react) { - LOGF("REACT"); - action &= ~(INT | STEP | FINISH | NEXT); - tuimode = true; - } - break; - } - if ((bp = IsAtBreakpoint(&breakpoints, GetIp())) != -1) { - LOGF("BREAK %p", breakpoints.p[bp].addr); + if (action & ALARM) { + DrawDisplayOnly(&pan.display); + action &= ~ALARM; + } + if (action & EXIT) { + LOGF("EXEC EXIT"); + break; + } + if (action & INT) { + LOGF("EXEC INT"); + if (react) { + LOGF("REACT"); + action &= ~(INT | STEP | FINISH | NEXT); tuimode = true; - break; } + break; } } } @@ -2441,6 +2547,12 @@ static void Tui(void) { if (!(action & FAILURE)) { LoadInstruction(m); UpdateXmmType(); + if ((action & (FINISH | NEXT | CONTINUE)) && + (bp = IsAtBreakpoint(&breakpoints, GetIp())) != -1) { + action &= ~(FINISH | NEXT | CONTINUE); + LOGF("BREAK %p", breakpoints.p[bp].addr); + break; + } } else { m->xedd = (struct XedDecodedInst *)m->icache[0]; m->xedd->length = 1; @@ -2466,14 +2578,17 @@ static void Tui(void) { } if (!(action & CONTINUE) || interactive) { tick = 0; - GetDisIndex(); - SetupDraw(); Redraw(); } if (action & FAILURE) { LOGF("TUI FAILURE"); PrintMessageBox(ttyout, systemfailure, tyn, txn); ReadKeyboard(); + if (action & INT) { + LOGF("TUI INT"); + LeaveScreen(); + exit(1); + } } else if (!IsExecuting() || (!(action & CONTINUE) && !(action & INT) && HasPendingKeyboard())) { ReadKeyboard(); @@ -2505,10 +2620,6 @@ static void Tui(void) { break; } if (IsExecuting()) { - op = GetDisIndex(); - ScrollOp(&pan.disassembly, op); - VERBOSEF("%s", DisGetLine(dis, m, op)); - CopyMachineState(&laststate); if (!(action & CONTINUE)) { action &= ~STEP; if (action & NEXT) { @@ -2529,6 +2640,7 @@ static void Tui(void) { } if (!IsDebugBreak()) { ExecuteInstruction(m); + ++opcount; if (!(action & CONTINUE) || interactive) { ScrollCode(&pan.code); ScrollStack(&pan.stack); @@ -2546,7 +2658,6 @@ static void Tui(void) { } KeepGoing: CheckFramePointer(); - ops++; if (!(action & CONTINUE)) { ScrollOp(&pan.disassembly, GetDisIndex()); if ((action & FINISH) && IsRet()) action &= ~FINISH; @@ -2554,12 +2665,6 @@ static void Tui(void) { action &= ~NEXT; } } - if ((action & (FINISH | NEXT | CONTINUE)) && - (bp = IsAtBreakpoint(&breakpoints, GetIp())) != -1) { - action &= ~(FINISH | NEXT | CONTINUE); - LOGF("BREAK %p", breakpoints.p[bp].addr); - break; - } } } } else { @@ -2611,25 +2716,30 @@ static void GetOpts(int argc, char *argv[]) { setvbuf(g_logfile, xmalloc(PAGESIZE), _IOLBF, PAGESIZE); } +static int OpenDevTty(void) { + return open("/dev/tty", O_RDWR | O_NOCTTY); +} + +static void AddHostFd(int fd) { + int i = m->fds.i++; + CHECK_NE(-1, (m->fds.p[i].fd = fd)); + m->fds.p[i].cb = &kMachineFdCbHost; +} + int Emulator(int argc, char *argv[]) { void *code; int rc, fd; codepath = argv[optind++]; - pty = MachinePtyNew(); m->fds.p = xcalloc((m->fds.n = 8), sizeof(struct MachineFd)); Restart: action = 0; LoadProgram(m, codepath, argv + optind, environ, elf); - m->fds.i = 3; - m->fds.p[0].fd = STDIN_FILENO; - m->fds.p[0].cb = &kMachineFdCbHost; - m->fds.p[1].fd = STDOUT_FILENO; - m->fds.p[1].cb = &kMachineFdCbHost; - m->fds.p[2].fd = STDERR_FILENO; - m->fds.p[2].cb = &kMachineFdCbHost; + AddHostFd(STDIN_FILENO); + AddHostFd(STDOUT_FILENO); + AddHostFd(STDERR_FILENO); if (tuimode) { - ttyin = isatty(0) ? 0 : open("/dev/tty", O_RDWR | O_NOCTTY); - ttyout = isatty(1) ? 1 : open("/dev/tty", O_RDWR | O_NOCTTY); + ttyin = isatty(STDIN_FILENO) ? STDIN_FILENO : OpenDevTty(); + ttyout = isatty(STDOUT_FILENO) ? STDOUT_FILENO : OpenDevTty(); } else { ttyin = -1; ttyout = -1; @@ -2640,18 +2750,9 @@ Restart: tyn = 24; txn = 80; GetTtySize(ttyout); - if (isatty(0)) { - m->fds.p[0].fd = 0; - m->fds.p[0].cb = &kMachineFdCbPty; - } - if (isatty(1)) { - m->fds.p[1].fd = 1; - m->fds.p[1].cb = &kMachineFdCbPty; - } - if (isatty(2)) { - m->fds.p[2].fd = 2; - m->fds.p[2].cb = &kMachineFdCbPty; - } + if (isatty(STDIN_FILENO)) m->fds.p[STDIN_FILENO].cb = &kMachineFdCbPty; + if (isatty(STDOUT_FILENO)) m->fds.p[STDOUT_FILENO].cb = &kMachineFdCbPty; + if (isatty(STDERR_FILENO)) m->fds.p[STDERR_FILENO].cb = &kMachineFdCbPty; } while (!(action & EXIT)) { if (!tuimode) { @@ -2669,7 +2770,7 @@ Restart: if (printstats) { fprintf(stderr, "taken: %,ld\n", taken); fprintf(stderr, "ntaken: %,ld\n", ntaken); - fprintf(stderr, "ops: %,ld\n", ops); + fprintf(stderr, "ops: %,ld\n", opcount); } munmap(elf->ehdr, elf->size); DisFree(dis); @@ -2682,12 +2783,13 @@ static void OnlyRunOnFirstCpu(void) { } int main(int argc, char *argv[]) { + if (!NoDebug()) showcrashreports(); + pty = NewPty(); m = NewMachine(); + m->mode = XED_MACHINE_MODE_LONG_64; speed = 16; SetXmmSize(2); SetXmmDisp(kXmmHex); - if (!NoDebug()) showcrashreports(); - /* OnlyRunOnFirstCpu(); */ if ((colorize = cancolor())) { g_high.keyword = 155; g_high.reg = 215; @@ -2697,6 +2799,7 @@ int main(int argc, char *argv[]) { g_high.quote = 215; } GetOpts(argc, argv); + xsigaction(SIGALRM, OnSigAlarm, 0, 0, 0); if (optind == argc) PrintUsage(EX_USAGE, stderr); return Emulator(argc, argv); } diff --git a/tool/build/calculator.c b/tool/build/calculator.c index 8128501c..495f3502 100644 --- a/tool/build/calculator.c +++ b/tool/build/calculator.c @@ -19,6 +19,7 @@ #include "libc/dce.h" #include "libc/fmt/fmt.h" #include "libc/limits.h" +#include "libc/log/color.h" #include "libc/log/log.h" #include "libc/macros.h" #include "libc/math.h" diff --git a/tool/build/emubin/emubin.mk b/tool/build/emubin/emubin.mk index 38f5ddc8..bb71fd98 100644 --- a/tool/build/emubin/emubin.mk +++ b/tool/build/emubin/emubin.mk @@ -58,6 +58,14 @@ o/$(MODE)/tool/build/emubin/%.elf: \ $(ELF) @$(ELFLINK) +o/$(MODE)/tool/build/emubin/lisp.elf: \ + $(TOOL_BUILD_EMUBIN_DEPS) \ + $(TOOL_BUILD_EMUBIN_A) \ + o/$(MODE)/tool/build/emubin/lisp.o \ + o/$(MODE)/tool/build/emubin/lispelf.o \ + $(ELF) + @$(ELFLINK) + o/dbg/tool/build/emubin/lisp.real.com.dbg: \ $(TOOL_BUILD_EMUBIN_DEPS) \ $(TOOL_BUILD_EMUBIN_A) \ @@ -73,6 +81,13 @@ o/$(MODE)/tool/build/emubin/lisp.bin.dbg: \ tool/build/emubin/lisp.lds @$(ELFLINK) -z max-page-size=0x10 +o/$(MODE)/tool/build/emubin/love.bin.dbg: \ + $(TOOL_BUILD_EMUBIN_DEPS) \ + o/$(MODE)/tool/build/emubin/love.o \ + o/$(MODE)/tool/build/emubin/lispstart.o \ + tool/build/emubin/lisp.lds + @$(ELFLINK) -z max-page-size=0x10 + o/tiny/tool/build/emubin/spiral.bin.dbg: \ $(TOOL_BUILD_EMUBIN_DEPS) \ o/tiny/tool/build/emubin/spiral.real.o diff --git a/tool/build/emubin/lisp.c b/tool/build/emubin/lisp.c index b390b88b..e83c1bb9 100644 --- a/tool/build/emubin/lisp.c +++ b/tool/build/emubin/lisp.c @@ -18,15 +18,13 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "tool/build/emubin/lisp.h" -#define TRACE 0 // print eval input output -#define RETRO 1 // auto capitalize input -#define ERRORS 1 // print messages or undefined behavior -#define DELETE 1 // allow backspace to rub out symbol -#define QUOTES 1 // allow 'X shorthand (QUOTE X) -#define MUTABLE 0 // allow setting globals -#define PROMPT 1 // show repl prompt -#define WORD short -#define WORDS 8192 +#define TRACE 0 // print eval input output +#define RETRO 0 // auto capitalize input +#define DELETE 0 // allow backspace to rub out symbol +#define QUOTES 0 // allow 'X shorthand (QUOTE X) +#define PROMPT 0 // show repl prompt +#define WORD short +#define WORDS 8192 /*───────────────────────────────────────────────────────────────────────────│─╗ │ The LISP Challenge § LISP Machine ─╬─│┼ @@ -36,25 +34,16 @@ #define CONS 1 #define NIL 0 -#define ATOM_T 8 -#define ATOM_QUOTE 12 -#define ATOM_ATOM 24 -#define ATOM_EQ 34 -#define ATOM_COND 40 -#define ATOM_CAR 50 -#define ATOM_CDR 58 -#define ATOM_CONS 66 -#define ATOM_LAMBDA 76 -#define ATOM_SET 90 - -#define Quote(x) List(ATOM_QUOTE, x) -#define List(x, y) Cons(x, Cons(y, NIL)) -#define Caar(x) Car(Car(x)) // ((A B C D) (E F G) H I) → A -#define Cdar(x) Cdr(Car(x)) // ((A B C D) (E F G) H I) → (B C D) -#define Cadar(x) Cadr(Car(x)) // ((A B C D) (E F G) H I) → B -#define Caddar(x) Caddr(Car(x)) // ((A B C D) (E F G) H I) → C -#define Cadr(x) Car(Cdr(x)) // ((A B C D) (E F G) H I) → (E F G) -#define Caddr(x) Cadr(Cdr(x)) // ((A B C D) (E F G) H I) → H +#define UNDEFINED 8 +#define ATOM_T 30 +#define ATOM_QUOTE 34 +#define ATOM_ATOM 46 +#define ATOM_EQ 56 +#define ATOM_COND 62 +#define ATOM_CAR 72 +#define ATOM_CDR 80 +#define ATOM_CONS 88 +#define ATOM_LAMBDA 98 #define BOOL(x) ((x) ? ATOM_T : NIL) #define VALUE(x) ((x) >> 1) @@ -67,7 +56,6 @@ struct Lisp { WORD globals; WORD index; char token[128]; - long jb[8]; char str[WORDS]; }; @@ -75,6 +63,7 @@ _Static_assert(sizeof(struct Lisp) <= 0x7c00 - 0x600, "LISP Machine too large for real mode"); _Alignas(char) const char kSymbols[] = "NIL\0" + "*UNDEFINED\0" "T\0" "QUOTE\0" "ATOM\0" @@ -83,8 +72,7 @@ _Alignas(char) const char kSymbols[] = "NIL\0" "CAR\0" "CDR\0" "CONS\0" - "LAMBDA\0" - "SET\0"; + "LAMBDA\0"; #ifdef __REAL_MODE__ static struct Lisp *const q; @@ -112,6 +100,10 @@ static void SetupSyntax(void) { #endif } +static void SetupBuiltins(void) { + CopyMemory(q->str, kSymbols, sizeof(kSymbols)); +} + static inline WORD Car(long x) { return PEEK_ARRAY(q, mem, VALUE(x), 0); } @@ -136,23 +128,16 @@ static WORD Cons(WORD car, WORD cdr) { return cell; } -static void SetupBuiltins(void) { - CopyMemory(q->str, kSymbols, sizeof(kSymbols)); - q->mem[0] = PTR(2); - q->globals = PTR(0); - q->index = 4; -} - static char *StpCpy(char *d, char *s) { char c; do { - c = LODS(s); /* a.k.a. c = *s++; */ - STOS(d, c); /* a.k.a. *d++ = c; */ + c = LODS(s); // a.k.a. c = *s++ + STOS(d, c); // a.k.a. *d++ = c } while (c); return d; } -WORD Intern(char *s) { +static WORD Intern(char *s) { int j, cx; char c, *z, *t; z = q->str; @@ -175,7 +160,7 @@ WORD Intern(char *s) { return OBJECT(ATOM, SUB((long)z, q->str)); } -forceinline unsigned char XlatSyntax(unsigned char b) { +static unsigned char XlatSyntax(unsigned char b) { return PEEK_ARRAY(q, syntax, b, 0); } @@ -207,17 +192,19 @@ static int GetChar(void) { static void GetToken(void) { char *t; - unsigned char b; + unsigned char b, x; b = q->look; t = q->token; - while (XlatSyntax(b) == ' ') { + for (;;) { + x = XlatSyntax(b); + if (x != ' ') break; b = GetChar(); } - if (XlatSyntax(b)) { + if (x) { STOS(t, b); b = GetChar(); } else { - while (b && !XlatSyntax(b)) { + while (b && !x) { if (!DELETE || b != '\b') { STOS(t, b); } else if (t > q->token) { @@ -225,6 +212,7 @@ static void GetToken(void) { if (t > q->token) --t; } b = GetChar(); + x = XlatSyntax(b); } } STOS(t, 0); @@ -236,6 +224,18 @@ static WORD ConsumeObject(void) { return GetObject(); } +static WORD Cadr(long x) { + return Car(Cdr(x)); // ((A B C D) (E F G) H I) → (E F G) +} + +static WORD List(long x, long y) { + return Cons(x, Cons(y, NIL)); +} + +static WORD Quote(long x) { + return List(ATOM_QUOTE, x); +} + static WORD GetQuote(void) { return Quote(ConsumeObject()); } @@ -298,7 +298,7 @@ static void PrintList(long x) { PrintChar('('); PrintObject(Car(x)); while ((x = Cdr(x))) { - if (TYPE(x) == CONS) { + if (!ISATOM(x)) { PrintChar(' '); PrintObject(Car(x)); } else { @@ -311,7 +311,7 @@ static void PrintList(long x) { } static void PrintObject(long x) { - if (TYPE(x) == ATOM) { + if (ISATOM(x)) { PrintAtom(x); } else { PrintList(x); @@ -323,42 +323,38 @@ static void Print(long i) { PrintString("\r\n"); } -__attribute__((__noreturn__)) static void Reset(void) { - longjmp(q->jb, 1); -} - -__attribute__((__noreturn__)) static void OnArity(void) { - PrintString("ARITY!\n"); - Reset(); -} - -__attribute__((__noreturn__)) static void OnUndefined(long x) { - PrintString("UNDEF! "); - Print(x); - Reset(); -} - -#if !ERRORS -#define OnArity() __builtin_unreachable() -#define OnUndefined(x) __builtin_unreachable() -#endif - /*───────────────────────────────────────────────────────────────────────────│─╗ │ The LISP Challenge § Bootstrap John McCarthy's Metacircular Evaluator ─╬─│┼ ╚────────────────────────────────────────────────────────────────────────────│*/ static WORD Atom(long x) { - return BOOL(TYPE(x) == ATOM); + return BOOL(ISATOM(x)); } -static WORD Null(long x) { - return BOOL(!x); -} - -static WORD Eq(long x, long y) { +WORD Eq(long x, long y) { return BOOL(x == y); } +static WORD Caar(long x) { + return Car(Car(x)); // ((A B C D) (E F G) H I) → A +} + +static WORD Cdar(long x) { + return Cdr(Car(x)); // ((A B C D) (E F G) H I) → (B C D) +} + +static WORD Cadar(long x) { + return Cadr(Car(x)); // ((A B C D) (E F G) H I) → B +} + +static WORD Caddr(long x) { + return Cadr(Cdr(x)); // ((A B C D) (E F G) H I) → H +} + +static WORD Caddar(long x) { + return Caddr(Car(x)); // ((A B C D) (E F G) H I) → C +} + static WORD Arg1(long e, long a) { return Eval(Cadr(e), a); } @@ -368,37 +364,36 @@ static WORD Arg2(long e, long a) { } static WORD Append(long x, long y) { - return Null(x) ? y : Cons(Car(x), Append(Cdr(x), y)); + return x ? Cons(Car(x), Append(Cdr(x), y)) : y; } static WORD Evcon(long c, long a) { return Eval(Caar(c), a) ? Eval(Cadar(c), a) : Evcon(Cdr(c), a); } -static WORD Evlis(long m, long a) { - return m ? Cons(Eval(Car(m), a), Evlis(Cdr(m), a)) : NIL; +static WORD Bind(long v, long a, long e) { + return v ? Cons(Cons(Car(v), Eval(Car(a), e)), Bind(Cdr(v), Cdr(a), e)) : e; } static WORD Assoc(long x, long y) { - if (!y) OnUndefined(x); - return Eq(Caar(y), x) ? Cdar(y) : Assoc(x, Cdr(y)); + return y ? Eq(Caar(y), x) ? Cdar(y) : Assoc(x, Cdr(y)) : NIL; } static WORD Pair(long x, long y) { - if (Null(x) && Null(y)) { + if (Atom(x) || Atom(y)) { return NIL; - } else if (!Atom(x) && !Atom(y)) { - return Cons(Cons(Car(x), Car(y)), Pair(Cdr(x), Cdr(y))); } else { - OnArity(); + return Cons(Cons(Car(x), Car(y)), Pair(Cdr(x), Cdr(y))); } } -static WORD Evaluate(long e, long a) { +__attribute__((__noinline__)) static WORD Evaluate(long e, long a) { if (Atom(e)) { return Assoc(e, a); } else if (Atom(Car(e))) { switch (Car(e)) { + case NIL: + return UNDEFINED; case ATOM_QUOTE: return Cadr(e); case ATOM_ATOM: @@ -413,17 +408,13 @@ static WORD Evaluate(long e, long a) { return Cdr(Arg1(e, a)); case ATOM_CONS: return Cons(Arg1(e, a), Arg2(e, a)); -#if MUTABLE - case ATOM_SET: - return Cdar(Set(a, Cons(Arg1(e, a), Arg2(e, a)), Cons(Car(a), Cdr(a)))); -#endif default: - return Eval(Cons(Assoc(Car(e), a), Evlis(Cdr(e), a)), a); + return Eval(Cons(Assoc(Car(e), a), Cdr(e)), a); } } else if (Eq(Caar(e), ATOM_LAMBDA)) { - return Eval(Caddar(e), Append(Pair(Cadar(e), Evlis(Cdr(e), a)), a)); + return Eval(Caddar(e), Bind(Cadar(e), Cdr(e), a)); } else { - OnUndefined(Caar(e)); + return UNDEFINED; } } @@ -448,9 +439,6 @@ static WORD Eval(long e, long a) { ╚────────────────────────────────────────────────────────────────────────────│*/ void Repl(void) { -#if ERRORS - setjmp(q->jb); -#endif for (;;) { #if PROMPT PrintString("* "); @@ -460,7 +448,7 @@ void Repl(void) { } int main(int argc, char *argv[]) { - /* RawMode(); */ + RawMode(); SetupSyntax(); SetupBuiltins(); #if PROMPT diff --git a/tool/build/emubin/lisp.h b/tool/build/emubin/lisp.h index de2c13ae..e97e983e 100644 --- a/tool/build/emubin/lisp.h +++ b/tool/build/emubin/lisp.h @@ -4,11 +4,11 @@ #define CompilerBarrier() asm volatile("" ::: "memory"); -#define TYPE(x) /* a.k.a. x&1 */ \ - ({ \ - char IsAtom; \ - asm("test%z1\t$1,%1" : "=@ccnz"(IsAtom) : "Qm"((char)x)); \ - IsAtom; \ +#define ISATOM(x) /* a.k.a. !(x&1) */ \ + ({ \ + _Bool IsAtom; \ + asm("test%z1\t$1,%1" : "=@ccz"(IsAtom) : "Qm"((char)x)); \ + IsAtom; \ }) #define OBJECT(t, v) /* a.k.a. v<<1|t */ \ @@ -112,9 +112,6 @@ } \ } while (0) -int setjmp(void *) __attribute__((__returns_twice__)); -int longjmp(void *, int) __attribute__((__noreturn__)); - static inline void *SetMemory(void *di, int al, unsigned long cx) { asm("rep stosb" : "=D"(di), "=c"(cx), "=m"(*(char(*)[cx])di) @@ -170,6 +167,7 @@ static int ReadChar(void) { int c; #ifdef __REAL_MODE__ asm volatile("int\t$0x16" : "=a"(c) : "0"(0) : "memory"); + c &= 0xff; #else static int buf; asm volatile("syscall" diff --git a/tool/build/emubin/lisp.lds b/tool/build/emubin/lisp.lds index 25dc53bd..0a9f976e 100644 --- a/tool/build/emubin/lisp.lds +++ b/tool/build/emubin/lisp.lds @@ -29,7 +29,7 @@ SECTIONS { . = 0x1fe; SHORT(0xaa55); *(.text .text.*) - BYTE(0x90); + /*BYTE(0x90);*/ _etext = .; . = ALIGN(512); } diff --git a/tool/build/emubin/lisp.lisp b/tool/build/emubin/lisp.lisp index b8bf7312..d1836107 100644 --- a/tool/build/emubin/lisp.lisp +++ b/tool/build/emubin/lisp.lisp @@ -1,30 +1,105 @@ -;; (SET 'APPLY '(LAMBDA (E ARGS) -;; ((LAMBDA (APPQ) -;; (CONS )) -;; '(LAMBDA (M) -;; (COND ((EQ M 'NIL) 'NIL) -;; ('T (CONS (QUOTE (CAR M)) -;; (APPQ (CONS 'QUOTE (CDR M)))))))))) -;; (SET 'LIST '(LAMBDA (X Y) (CONS X (CONS Y 'NIL)))) -;; (SET 'AND '(LAMBDA (P Q) (COND ((EQ P 'T) Q) ('T 'F)))) -;; (SET 'OR '(LAMBDA (P Q) (COND ((EQ P 'T) 'T) ('T Q)))) -;; (SET 'NOT '(LAMBDA (P) (COND ((EQ P 'F) 'T) ('T 'T)))) -;; (SET 'IMPLIES '(LAMBDA (P Q) (COND ((EQ P 'T) Q) ('T 'T)))) +;; (setq lisp-indent-function 'common-lisp-indent-function) +;; (paredit-mode) -((LAMBDA (CALL MKQUOT NULL AND APPEND KEYS VALS E A) - (CALL (CONS (CONS (QUOTE LAMBDA) (CONS (KEYS (QUOTE A)) (CONS E NIL))) (VALS (QUOTE A))))) - (QUOTE (LAMBDA (X) (X))) - (QUOTE (LAMBDA (X) (CONS (QUOTE QUOTE) (CONS X NIL)))) - (QUOTE (LAMBDA (P Q) (COND ((EQ P (QUOTE T)) Q) ((QUOTE T) (QUOTE F))))) - (QUOTE (LAMBDA (X) (AND (QUOTE (ATOM X)) (QUOTE (EQ X NIL))))) - (QUOTE (LAMBDA (X Y) (COND ((EQ X NIL) Y) ((QUOTE T) (CONS (CAR X) (APPEND (QUOTE (CDR X)) (QUOTE Y))))))) - (QUOTE (LAMBDA (A) (COND ((EQ A NIL) NIL) ((QUOTE T) (CONS (CAR (CAR A)) (KEYS (QUOTE (CDR A)))))))) - (QUOTE (LAMBDA (A) (COND ((EQ A NIL) NIL) ((QUOTE T) (CONS (MKQUOT (QUOTE (CDR (CAR A)))) (VALS (QUOTE (CDR A)))))))) - (QUOTE (AND (QUOTE A) (QUOTE C))) - (CONS (CONS (QUOTE A) (QUOTE B)) (CONS (CONS (QUOTE C) (QUOTE D)) NIL))) +;; ________ +;; /_ __/ /_ ___ +;; / / / __ \/ _ \ +;; / / / / / / __/ +;; /_/ /_/ /_/\___/ +;; __ _________ ____ ________ ____ +;; / / / _/ ___// __ \ / ____/ /_ ____ _/ / /__ ____ ____ ____ +;; / / / / \__ \/ /_/ / / / / __ \/ __ `/ / / _ \/ __ \/ __ `/ _ \ +;; / /____/ / ___/ / ____/ / /___/ / / / /_/ / / / __/ / / / /_/ / __/ +;; /_____/___//____/_/ \____/_/ /_/\__,_/_/_/\___/_/ /_/\__, /\___/ +;; /____/ +;; +;; THE LISP CHALLENGE +;; +;; PICK YOUR FAVORITE PROGRAMMING LANGUAGE +;; IMPLEMENT THE TINIEST POSSIBLE LISP MACHINE THAT +;; BOOTSTRAPS JOHN MCCARTHY'S METACIRCULAR EVALUATOR +;; WINNING IS DEFINED BY LINES OF CODE FOR SCRIPTING LANGUAGES +;; WINNING IS DEFINED BY BINARY FOOTPRINT FOR COMPILED LANGUAGES +;; +;; @SEE LISP FROM NOTHING; NILS M. HOLM; LULU PRESS, INC. 2020 +;; @SEE RECURSIVE FUNCTIONS OF SYMBOLIC EXPRESSIONS AND THEIR +;; COMPUTATION BY MACHINE, PART I; JOHN MCCARTHY, MASSACHUSETTS +;; INSTITUTE OF TECHNOLOGY, CAMBRIDGE, MASS. APRIL 1960 -((LAMBDA (FF X) (FF 'X)) - '(LAMBDA (X) - (COND ((ATOM X) X) - ((QUOTE T) (FF '(CAR X))))) - '((A) B C)) +;; NIL ATOM +;; ABSENCE OF VALUE +NIL + +;; CONS CELL +;; BUILDING BLOCK OF DATA STRUCTURES +(CONS NIL NIL) + +;; REFLECTION +;; EVERYTHING IS AN ATOM OR NOT AN ATOM +(ATOM NIL) +(ATOM (CONS NIL NIL)) + +;; QUOTING +;; CODE IS DATA AND DATA IS CODE +(QUOTE (CONS NIL NIL)) +(CONS (QUOTE CONS) (CONS NIL (CONS NIL NIL))) + +;; LOGIC +;; LAW OF IDENTITY VIA STRING INTERNING +(EQ (QUOTE A) (QUOTE A)) + +;; FIND FIRST ATOM IN TREE +;; RECURSIVE CONDITIONAL FUNCTION BINDING +((LAMBDA (FF X) (FF X)) + (QUOTE (LAMBDA (X) + (COND ((ATOM X) X) + ((QUOTE T) (FF (CAR X)))))) + (QUOTE ((A) B C))) + +;; LISP IMPLEMENTED IN LISP +;; USED TO EVALUATE FIND FIRST ATOM IN TREE +;; REQUIRES CONS CAR CDR QUOTE ATOM EQ LAMBDA COND +;; FIXES BUGS FROM JOHN MCCARTHY PAPER AND MORE MINIMAL +((LAMBDA (ASSOC EVCON BIND APPEND EVAL) + (EVAL (QUOTE ((LAMBDA (FF X) (FF X)) + (QUOTE (LAMBDA (X) + (COND ((ATOM X) X) + ((QUOTE T) (FF (CAR X)))))) + (QUOTE ((A) B C)))) + NIL)) + (QUOTE (LAMBDA (X E) + (COND ((EQ E NIL) NIL) + ((EQ X (CAR (CAR E))) (CDR (CAR E))) + ((QUOTE T) (ASSOC X (CDR E)))))) + (QUOTE (LAMBDA (C E) + (COND ((EVAL (CAR (CAR C)) E) (EVAL (CAR (CDR (CAR C))) E)) + ((QUOTE T) (EVCON (CDR C) E))))) + (QUOTE (LAMBDA (V A E) + (COND ((EQ V NIL) E) + ((QUOTE T) (CONS (CONS (CAR V) (EVAL (CAR A) E)) + (BIND (CDR V) (CDR A) E)))))) + (QUOTE (LAMBDA (A B) + (COND ((EQ A NIL) B) + ((QUOTE T) (CONS (CAR A) (APPEND (CDR A) B)))))) + (QUOTE (LAMBDA (E A) + (COND + ((ATOM E) (ASSOC E A)) + ((ATOM (CAR E)) + (COND + ((EQ (CAR E) NIL) (QUOTE *UNDEFINED)) + ((EQ (CAR E) (QUOTE QUOTE)) (CAR (CDR E))) + ((EQ (CAR E) (QUOTE ATOM)) (ATOM (EVAL (CAR (CDR E)) A))) + ((EQ (CAR E) (QUOTE EQ)) (EQ (EVAL (CAR (CDR E)) A) + (EVAL (CAR (CDR (CDR E))) A))) + ((EQ (CAR E) (QUOTE CAR)) (CAR (EVAL (CAR (CDR E)) A))) + ((EQ (CAR E) (QUOTE CDR)) (CDR (EVAL (CAR (CDR E)) A))) + ((EQ (CAR E) (QUOTE CONS)) (CONS (EVAL (CAR (CDR E)) A) + (EVAL (CAR (CDR (CDR E))) A))) + ((EQ (CAR E) (QUOTE COND)) (EVCON (CDR E) A)) + ((EQ (CAR E) (QUOTE LABEL)) (EVAL (CAR (CDR (CDR E))) + (APPEND (CAR (CDR E)) A))) + ((EQ (CAR E) (QUOTE LAMBDA)) E) + ((QUOTE T) (EVAL (CONS (EVAL (CAR E) A) (CDR E)) A)))) + ((EQ (CAR (CAR E)) (QUOTE LAMBDA)) + (EVAL (CAR (CDR (CDR (CAR E)))) + (BIND (CAR (CDR (CAR E))) (CDR E) A))))))) diff --git a/tool/build/emubin/lispelf.S b/tool/build/emubin/lispelf.S new file mode 100644 index 00000000..348211f7 --- /dev/null +++ b/tool/build/emubin/lispelf.S @@ -0,0 +1,23 @@ +/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ +│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2020 Justine Alexandra Roberts Tunney │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/macros.h" + +_start: jmp main + .endfn _start,globl diff --git a/tool/build/emubin/lispstart.S b/tool/build/emubin/lispstart.S index f34d670f..dd32a494 100644 --- a/tool/build/emubin/lispstart.S +++ b/tool/build/emubin/lispstart.S @@ -49,29 +49,3 @@ _begin: push %cs jmp main .type _begin,@function .size _begin,.-_begin - - .section .start.setjmp,"ax",@progbits -setjmp: mov %sp,%ax - stosw - xchg %ax,%si - movsw %ss:(%si),(%di) - mov %bp,%ax - stosw - ret $6 - .type setjmp,@function - .size setjmp,.-setjmp - .globl setjmp - .previous - - .section .start.longjmp,"ax",@progbits -longjmp: - mov (%di),%sp - mov 2(%di),%dx - mov 4(%di),%bp - pop %ax - mov %si,%ax - jmp *%dx - .type longjmp,@function - .size longjmp,.-longjmp - .globl longjmp - .previous diff --git a/tool/build/lib/alu.c b/tool/build/lib/alu.c index 2db41e7d..a36c1028 100644 --- a/tool/build/lib/alu.c +++ b/tool/build/lib/alu.c @@ -37,15 +37,6 @@ const aluop_f kBsu[8][4] = { {Shl8, Shl16, Shl32, Shl64}, {Sar8, Sar16, Sar32, Sar64}, }; -int64_t AluFlags(uint64_t x, uint32_t af, uint32_t *f, uint32_t of, uint32_t cf, - uint32_t sf) { - *f &= ~(1u << FLAGS_CF | 1u << FLAGS_ZF | 1u << FLAGS_SF | 1u << FLAGS_OF | - 1u << FLAGS_AF | 0xFF000000u); - *f |= sf << FLAGS_SF | cf << FLAGS_CF | !x << FLAGS_ZF | of << FLAGS_OF | - af << FLAGS_AF | (x & 0xFF) << 24; - return x; -} - int64_t AluFlags8(uint8_t z, uint32_t af, uint32_t *f, uint32_t of, uint32_t cf) { return AluFlags(z, af, f, of, cf, z >> 7); diff --git a/tool/build/lib/alu.h b/tool/build/lib/alu.h index aecefc37..4b73d7ca 100644 --- a/tool/build/lib/alu.h +++ b/tool/build/lib/alu.h @@ -108,7 +108,6 @@ int64_t Rcl64(uint64_t, uint64_t, uint32_t *); uint64_t BsuDoubleShift(int, uint64_t, uint64_t, uint8_t, bool, uint32_t *); -int64_t AluFlags(uint64_t, uint32_t, uint32_t *, uint32_t, uint32_t, uint32_t); int64_t AluFlags8(uint8_t, uint32_t, uint32_t *, uint32_t, uint32_t); int64_t AluFlags16(uint16_t, uint32_t, uint32_t *, uint32_t, uint32_t); int64_t AluFlags32(uint32_t, uint32_t, uint32_t *, uint32_t, uint32_t); diff --git a/tool/build/lib/buffer.c b/tool/build/lib/buffer.c index 634a01cc..7e8d4d86 100644 --- a/tool/build/lib/buffer.c +++ b/tool/build/lib/buffer.c @@ -49,16 +49,17 @@ void AppendWide(struct Buffer *b, wint_t wc) { } while (wb); } -void AppendFmt(struct Buffer *b, const char *fmt, ...) { - int size; +int AppendFmt(struct Buffer *b, const char *fmt, ...) { + int bytes; char *tmp; va_list va; tmp = NULL; va_start(va, fmt); - size = vasprintf(&tmp, fmt, va); + bytes = vasprintf(&tmp, fmt, va); va_end(va); - if (size != -1) AppendData(b, tmp, size); + if (bytes != -1) AppendData(b, tmp, bytes); free(tmp); + return bytes; } /** diff --git a/tool/build/lib/buffer.h b/tool/build/lib/buffer.h index 70224066..795ee836 100644 --- a/tool/build/lib/buffer.h +++ b/tool/build/lib/buffer.h @@ -12,7 +12,7 @@ void AppendChar(struct Buffer *, char); void AppendData(struct Buffer *, char *, size_t); void AppendStr(struct Buffer *, const char *); void AppendWide(struct Buffer *, wint_t); -void AppendFmt(struct Buffer *, const char *, ...); +int AppendFmt(struct Buffer *, const char *, ...); ssize_t WriteBuffer(struct Buffer *, int); COSMOPOLITAN_C_END_ diff --git a/tool/build/lib/buildlib.mk b/tool/build/lib/buildlib.mk index c14966a8..9c30029b 100644 --- a/tool/build/lib/buildlib.mk +++ b/tool/build/lib/buildlib.mk @@ -68,6 +68,10 @@ $(TOOL_BUILD_LIB_A_OBJS): \ -fsanitize=address endif +o/$(MODE)/tool/build/lib/memory-gcc.asm: \ + OVERRIDE_CFLAGS += \ + -fsanitize=address + o/$(MODE)/tool/build/lib/ssefloat.o: \ TARGET_ARCH += \ -msse3 diff --git a/tool/build/lib/cpuid.c b/tool/build/lib/cpuid.c index 074fda28..489e04bf 100644 --- a/tool/build/lib/cpuid.c +++ b/tool/build/lib/cpuid.c @@ -31,8 +31,8 @@ void OpCpuid(struct Machine *m, uint32_t rde) { case 0x80000000: ax = 7; bx = 'G' | 'e' << 8 | 'n' << 16 | 'u' << 24; - cx = 'i' | 'n' << 8 | 'e' << 16 | 'C' << 24; - dx = 'o' | 's' << 8 | 'm' << 16 | 'o' << 24; + dx = 'i' | 'n' << 8 | 'e' << 16 | 'C' << 24; + cx = 'o' | 's' << 8 | 'm' << 16 | 'o' << 24; break; case 1: cx |= 1 << 0; // sse3 diff --git a/tool/build/lib/dis.c b/tool/build/lib/dis.c index bff902cc..41cd842f 100644 --- a/tool/build/lib/dis.c +++ b/tool/build/lib/dis.c @@ -89,7 +89,7 @@ static char *DisError(struct Dis *d, char *p) { p = HighStart(p, g_high.comment); *p++ = '#'; *p++ = ' '; - p = stpcpy(p, indexdoublenulstring(kXedErrorNames, d->xedd->op.error)); + p = stpcpy(p, IndexDoubleNulString(kXedErrorNames, d->xedd->op.error)); p = HighEnd(p); *p = '\0'; return p; diff --git a/tool/build/lib/dis.h b/tool/build/lib/dis.h index 6325bf73..6eb7aad5 100644 --- a/tool/build/lib/dis.h +++ b/tool/build/lib/dis.h @@ -30,10 +30,10 @@ struct Dis { size_t i, n; struct DisSym { int64_t addr; - int rank; int unique; int size; int name; + char rank; bool iscode; bool isabs; } * p; diff --git a/tool/build/lib/disarg.c b/tool/build/lib/disarg.c index 77479789..75f4e98e 100644 --- a/tool/build/lib/disarg.c +++ b/tool/build/lib/disarg.c @@ -156,17 +156,12 @@ static char *DisSymImpl(struct Dis *d, char *p, int64_t x, long sym) { return p; } -static char *DisSym(struct Dis *d, char *p, int64_t x1, int64_t x2, - bool isrelative) { +static char *DisSym(struct Dis *d, char *p, int64_t value, int64_t addr) { long sym; - if ((sym = DisFindSym(d, x2)) != -1 && d->syms.p[sym].name && - (d->syms.p[sym].isabs ^ isrelative)) { - return DisSymImpl(d, p, x2, sym); - } else if ((sym = DisFindSym(d, x1)) != -1 && d->syms.p[sym].name && - (d->syms.p[sym].isabs ^ isrelative)) { - return DisSymImpl(d, p, x1, sym); + if ((sym = DisFindSym(d, addr)) != -1 && d->syms.p[sym].name) { + return DisSymImpl(d, p, addr, sym); } else { - return DisInt(p, x1); + return DisInt(p, value); } } @@ -174,7 +169,7 @@ static char *DisSymLiteral(struct Dis *d, uint32_t rde, char *p, uint64_t addr, uint64_t ip) { *p++ = '$'; p = HighStart(p, g_high.literal); - p = DisSym(d, p, addr, addr, false); + p = DisSym(d, p, addr, addr); p = HighEnd(p); return p; } @@ -227,7 +222,7 @@ static char *DisDisp(struct Dis *d, uint32_t rde, char *p) { } else { rela = true; } - p = DisSym(d, p, disp, disp, rela); + p = DisSym(d, p, disp, disp); } return p; } @@ -477,11 +472,11 @@ static char *DisJb(struct Dis *d, uint32_t rde, char *p) { static char *DisJvds(struct Dis *d, uint32_t rde, char *p) { return DisSym(d, p, RipRelative(d, d->xedd->op.disp), - RipRelative(d, d->xedd->op.disp) - Read64(d->m->cs), true); + RipRelative(d, d->xedd->op.disp) - Read64(d->m->cs)); } static char *DisAbs(struct Dis *d, uint32_t rde, char *p) { - return DisSym(d, p, d->xedd->op.disp, d->xedd->op.disp, false); + return DisSym(d, p, d->xedd->op.disp, d->xedd->op.disp); } static char *DisSw(struct Dis *d, uint32_t rde, char *p) { diff --git a/tool/build/lib/diself.c b/tool/build/lib/diself.c index 6cc87cbd..e35ab929 100644 --- a/tool/build/lib/diself.c +++ b/tool/build/lib/diself.c @@ -18,12 +18,12 @@ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/alg/alg.h" -#include "libc/alg/arraylist2.h" #include "libc/elf/elf.h" #include "libc/elf/struct/sym.h" #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/macros.h" +#include "libc/mem/mem.h" #include "libc/str/str.h" #include "tool/build/lib/dis.h" @@ -46,38 +46,51 @@ static int DisSymCompare(const struct DisSym *a, const struct DisSym *b) { } static void DisLoadElfLoads(struct Dis *d, struct Elf *elf) { - long i; + long i, j, n; int64_t addr; uint64_t size; Elf64_Phdr *phdr; - struct DisLoad l; - d->loads.i = 0; - for (i = 0; i < elf->ehdr->e_phnum; ++i) { + j = 0; + n = elf->ehdr->e_phnum; + if (d->loads.n < n) { + d->loads.n = n; + d->loads.p = realloc(d->loads.p, d->loads.n * sizeof(*d->loads.p)); + CHECK_NOTNULL(d->loads.p); + } + for (i = 0; i < n; ++i) { phdr = getelfsegmentheaderaddress(elf->ehdr, elf->size, i); if (phdr->p_type != PT_LOAD) continue; - l.addr = phdr->p_vaddr; - l.size = phdr->p_memsz; - l.istext = (phdr->p_flags & PF_X) == PF_X; - APPEND(&d->loads.p, &d->loads.i, &d->loads.n, &l); + d->loads.p[j].addr = phdr->p_vaddr; + d->loads.p[j].size = phdr->p_memsz; + d->loads.p[j].istext = (phdr->p_flags & PF_X) == PF_X; + ++j; } + d->loads.i = j; } static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) { - size_t i, n; + size_t i, j, n; int64_t stablen; - struct DisSym t; const Elf64_Sym *st, *sym; bool isabs, iscode, isweak, islocal, ishidden, isprotected, isfunc, isobject; - d->syms.i = 0; + j = 0; if ((d->syms.stab = getelfstringtable(elf->ehdr, elf->size)) && (st = getelfsymboltable(elf->ehdr, elf->size, &n))) { stablen = (intptr_t)elf->ehdr + elf->size - (intptr_t)d->syms.stab; + if (d->syms.n < n) { + d->syms.n = n; + d->syms.p = realloc(d->syms.p, d->syms.n * sizeof(*d->syms.p)); + CHECK_NOTNULL(d->syms.p); + } for (i = 0; i < n; ++i) { - if (!st[i].st_name) continue; - if (!(0 <= st[i].st_name && st[i].st_name < stablen)) continue; - if (ELF64_ST_TYPE(st[i].st_info) == STT_SECTION) continue; - if (ELF64_ST_TYPE(st[i].st_info) == STT_FILE) continue; - if (startswith(d->syms.stab + st[i].st_name, "v_")) continue; + if (ELF64_ST_TYPE(st[i].st_info) == STT_SECTION || + ELF64_ST_TYPE(st[i].st_info) == STT_FILE || !st[i].st_name || + startswith(d->syms.stab + st[i].st_name, "v_") || + !(0 <= st[i].st_name && st[i].st_name < stablen) || !st[i].st_value || + !(-0x800000000000 <= (int64_t)st[i].st_value && + (int64_t)st[i].st_value < 0x800000000000)) { + continue; + } isabs = st[i].st_shndx == SHN_ABS; isweak = ELF64_ST_BIND(st[i].st_info) == STB_WEAK; islocal = ELF64_ST_BIND(st[i].st_info) == STB_LOCAL; @@ -85,19 +98,51 @@ static void DisLoadElfSyms(struct Dis *d, struct Elf *elf) { isprotected = st[i].st_other == STV_PROTECTED; isfunc = ELF64_ST_TYPE(st[i].st_info) == STT_FUNC; isobject = ELF64_ST_TYPE(st[i].st_info) == STT_OBJECT; - t.unique = i; - t.size = st[i].st_size; - t.name = st[i].st_name; - t.addr = st[i].st_value; - t.rank = -islocal + -isweak + -isabs + isprotected + isobject + isfunc; - t.iscode = DisIsText(d, st[i].st_value) ? !isobject : isfunc; - t.isabs = isabs; - APPEND(&d->syms.p, &d->syms.i, &d->syms.n, &t); + d->syms.p[j].unique = i; + d->syms.p[j].size = st[i].st_size; + d->syms.p[j].name = st[i].st_name; + d->syms.p[j].addr = st[i].st_value; + d->syms.p[j].rank = + -islocal + -isweak + -isabs + isprotected + isobject + isfunc; + d->syms.p[j].iscode = DisIsText(d, st[i].st_value) ? !isobject : isfunc; + d->syms.p[j].isabs = isabs; + ++j; } } + d->syms.i = j; +} + +static void DisSortSyms(struct Dis *d) { qsort(d->syms.p, d->syms.i, sizeof(struct DisSym), (void *)DisSymCompare); } +static void DisCanonizeSyms(struct Dis *d) { + int64_t i, j, a; + if (d->syms.i) { + i = 1; + j = 1; + a = d->syms.p[0].addr; + do { + if (d->syms.p[j].addr > a) { + a = d->syms.p[j].addr; + if (j > i) { + d->syms.p[i] = d->syms.p[j]; + } + ++i; + } + ++j; + } while (j < d->syms.i); + d->syms.p = realloc(d->syms.p, sizeof(*d->syms.p) * i); + d->syms.i = i; + d->syms.n = i; + } + for (i = 0; i < d->syms.i; ++i) { + DEBUGF("%p-%p %s", d->syms.p[i].addr, + d->syms.p[i].addr + (d->syms.p[i].size ? d->syms.p[i].size - 1 : 0), + d->syms.stab + d->syms.p[i].name); + } +} + bool DisIsProg(struct Dis *d, int64_t addr) { long i; if (g_disisprog_disable) return true; @@ -122,36 +167,24 @@ bool DisIsText(struct Dis *d, int64_t addr) { } long DisFindSym(struct Dis *d, int64_t addr) { - size_t i, l, r, m, n; - if (d->syms.p) { - if (DisIsProg(d, addr)) { - l = 0; - r = d->syms.i; - while (l < r) { - m = (l + r) >> 1; - if (d->syms.p[m].addr < addr) { - l = m + 1; - } else { - r = m; - } - } - if (d->syms.p[l].addr == addr) { - return l; - } - l = MAX(0, (long)l - 10); - for (n = 0, i = l; i < d->syms.i && n < 20; ++i, ++n) { - if (addr >= d->syms.p[i].addr && - addr < d->syms.p[i].addr + d->syms.p[i].size) { - return i; - } - } - for (n = 0, i = l; i < d->syms.i && n < 20; ++i, ++n) { - if (addr >= d->syms.p[i].addr && - (i + 1 == d->syms.i || addr < d->syms.p[i + 1].addr)) { - return i; - } + long l, r, m, n; + if (DisIsProg(d, addr)) { + l = 0; + r = d->syms.i; + while (l < r) { + m = (l + r) >> 1; + if (d->syms.p[m].addr > addr) { + r = m; + } else { + l = m + 1; } } + if (r && (addr == d->syms.p[r - 1].addr || + (addr > d->syms.p[r - 1].addr && + (addr <= d->syms.p[r - 1].addr + d->syms.p[r - 1].size || + !d->syms.p[r - 1].size)))) { + return r - 1; + } } return -1; } @@ -170,4 +203,6 @@ void DisLoadElf(struct Dis *d, struct Elf *elf) { if (!elf || !elf->ehdr) return; DisLoadElfLoads(d, elf); DisLoadElfSyms(d, elf); + DisSortSyms(d); + DisCanonizeSyms(d); } diff --git a/tool/build/lib/flags.c b/tool/build/lib/flags.c index 9bd899c3..04e7ec6d 100644 --- a/tool/build/lib/flags.c +++ b/tool/build/lib/flags.c @@ -53,3 +53,12 @@ uint64_t ExportFlags(uint64_t flags) { flags |= GetLazyParityBool(flags) << FLAGS_PF; return flags; } + +int64_t AluFlags(uint64_t x, uint32_t af, uint32_t *f, uint32_t of, uint32_t cf, + uint32_t sf) { + *f &= ~(1u << FLAGS_CF | 1u << FLAGS_ZF | 1u << FLAGS_SF | 1u << FLAGS_OF | + 1u << FLAGS_AF | 0xFF000000u); + *f |= sf << FLAGS_SF | cf << FLAGS_CF | !x << FLAGS_ZF | of << FLAGS_OF | + af << FLAGS_AF | (x & 0xFF) << 24; + return x; +} diff --git a/tool/build/lib/flags.h b/tool/build/lib/flags.h index 763a0045..2807a7b2 100644 --- a/tool/build/lib/flags.h +++ b/tool/build/lib/flags.h @@ -64,6 +64,7 @@ COSMOPOLITAN_C_START_ bool GetParity(uint8_t); uint64_t ExportFlags(uint64_t); void ImportFlags(struct Machine *, uint64_t); +int64_t AluFlags(uint64_t, uint32_t, uint32_t *, uint32_t, uint32_t, uint32_t); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/loader.c b/tool/build/lib/loader.c index 48c60785..bd8ddca8 100644 --- a/tool/build/lib/loader.c +++ b/tool/build/lib/loader.c @@ -46,9 +46,6 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize, align = MAX(phdr->p_align, PAGESIZE); CHECK_EQ(1, popcnt(align)); CHECK_EQ(0, (phdr->p_vaddr - phdr->p_offset) % align); - /*-Type-Offset---VirtAddr-----------PhysAddr-----------FileSiz--MemSiz---Flg-Align----*/ - /*-LOAD-0x000000-0x0000000000400000-0x0000000000400000-0x0008e4-0x0008e4-R-E-0x200000-*/ - /*-LOAD-0x000fe0-0x0000000000600fe0-0x0000000000600fe0-0x000030-0x000310-RW--0x200000-*/ felf = (int64_t)(intptr_t)code; vstart = ROUNDDOWN(phdr->p_vaddr, align); vbss = ROUNDUP(phdr->p_vaddr + phdr->p_filesz, align); @@ -56,10 +53,10 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize, fstart = felf + ROUNDDOWN(phdr->p_offset, align); fend = felf + phdr->p_offset + phdr->p_filesz; bsssize = vend - vbss; - LOGF("LOADELFLOADSEGMENT" - " VSTART %#lx VBSS %#lx VEND %#lx" - " FSTART %#lx FEND %#lx BSSSIZE %#lx", - vstart, vbss, vend, fstart, fend, bsssize); + VERBOSEF("LOADELFLOADSEGMENT" + " VSTART %#lx VBSS %#lx VEND %#lx" + " FSTART %#lx FEND %#lx BSSSIZE %#lx", + vstart, vbss, vend, fstart, fend, bsssize); m->brk = MAX(m->brk, vend); CHECK_GE(vend, vstart); CHECK_GE(fend, fstart); @@ -69,9 +66,9 @@ static void LoadElfLoadSegment(struct Machine *m, void *code, size_t codesize, CHECK_GE(vend - vstart, fstart - fend); CHECK_LE(phdr->p_filesz, phdr->p_memsz); CHECK_EQ(felf + phdr->p_offset - fstart, phdr->p_vaddr - vstart); - CHECK_NE(-1, ReserveVirtual(m, vstart, fend - fstart)); + CHECK_NE(-1, ReserveVirtual(m, vstart, fend - fstart, 0x0207)); VirtualRecv(m, vstart, (void *)fstart, fend - fstart); - if (bsssize) CHECK_NE(-1, ReserveVirtual(m, vbss, bsssize)); + if (bsssize) CHECK_NE(-1, ReserveVirtual(m, vbss, bsssize, 0x0207)); if (phdr->p_memsz - phdr->p_filesz > bsssize) { VirtualSet(m, phdr->p_vaddr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz - bsssize); @@ -82,7 +79,7 @@ static void LoadElf(struct Machine *m, struct Elf *elf) { unsigned i; Elf64_Phdr *phdr; m->ip = elf->base = elf->ehdr->e_entry; - LOGF("LOADELF ENTRY %p", m->ip); + VERBOSEF("LOADELF ENTRY %p", m->ip); for (i = 0; i < elf->ehdr->e_phnum; ++i) { phdr = getelfsegmentheaderaddress(elf->ehdr, elf->size, i); switch (phdr->p_type) { @@ -149,9 +146,9 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars, } CHECK_NE(-1, close(fd)); ResetCpu(m); - if (m->mode == XED_MACHINE_MODE_REAL) { + if ((m->mode & 3) == XED_MODE_REAL) { elf->base = 0x7c00; - CHECK_NE(-1, ReserveVirtual(m, 0, BIGPAGESIZE)); + CHECK_NE(-1, ReserveReal(m, BIGPAGESIZE)); m->ip = 0x7c00; Write64(m->cs, 0); Write64(m->dx, 0); @@ -168,7 +165,8 @@ void LoadProgram(struct Machine *m, const char *prog, char **args, char **vars, } else { sp = 0x800000000000; Write64(m->sp, sp); - CHECK_NE(-1, ReserveVirtual(m, sp - STACKSIZE, STACKSIZE)); + m->cr3 = AllocateLinearPage(m); + CHECK_NE(-1, ReserveVirtual(m, sp - STACKSIZE, STACKSIZE, 0x0207)); LoadArgv(m, prog, args, vars); if (memcmp(elf->map, "\177ELF", 4) == 0) { elf->ehdr = (void *)elf->map; diff --git a/tool/build/lib/machine.c b/tool/build/lib/machine.c index 8ebcc057..1ac10a55 100644 --- a/tool/build/lib/machine.c +++ b/tool/build/lib/machine.c @@ -35,6 +35,7 @@ #include "tool/build/lib/machine.h" #include "tool/build/lib/memory.h" #include "tool/build/lib/modrm.h" +#include "tool/build/lib/op101.h" #include "tool/build/lib/sse.h" #include "tool/build/lib/ssefloat.h" #include "tool/build/lib/ssemov.h" @@ -883,9 +884,6 @@ static void OpBsubiImm(struct Machine *m, uint32_t rde) { Bsubi(m, rde, m->xedd->op.uimm0); } -static void OpLgdtMs(struct Machine *m, uint32_t rde) { -} - static void OpPushImm(struct Machine *m, uint32_t rde) { Push(m, rde, m->xedd->op.uimm0); } @@ -1328,21 +1326,6 @@ static void Op0ff(struct Machine *m, uint32_t rde) { kOp0ff[ModrmReg(rde)](m, rde); } -static void Op101(struct Machine *m, uint32_t rde) { - if (IsModrmRegister(rde)) { - if (ModrmReg(rde) == 0b111 && ModrmRm(rde) == 0b001) { - OpRdtscp(m, rde); - return; - } - } else { - if (ModrmReg(rde) == 2) { - OpLgdtMs(m, rde); - return; - } - } - OpUd(m, rde); -} - static void OpDoubleShift(struct Machine *m, uint32_t rde) { uint8_t *p; uint64_t x; @@ -1400,6 +1383,44 @@ static void OpNop(struct Machine *m, uint32_t rde) { } } +static void OpMovRqCq(struct Machine *m, uint32_t rde) { + switch (ModrmReg(rde)) { + case 0: + Write64(RegRexbRm(m, rde), m->cr0); + break; + case 2: + Write64(RegRexbRm(m, rde), m->cr2); + break; + case 3: + Write64(RegRexbRm(m, rde), m->cr3); + break; + case 4: + Write64(RegRexbRm(m, rde), m->cr4); + break; + default: + OpUd(m, rde); + } +} + +static void OpMovCqRq(struct Machine *m, uint32_t rde) { + switch (ModrmReg(rde)) { + case 0: + m->cr0 = Read64(RegRexbRm(m, rde)); + break; + case 2: + m->cr2 = Read64(RegRexbRm(m, rde)); + break; + case 3: + m->cr3 = Read64(RegRexbRm(m, rde)); + break; + case 4: + m->cr4 = Read64(RegRexbRm(m, rde)); + break; + default: + OpUd(m, rde); + } +} + static const nexgen32e_f kNexgen32e[] = { [0x000] = OpAlubAdd, [0x001] = OpAluw, @@ -1689,9 +1710,9 @@ static const nexgen32e_f kNexgen32e[] = { [0x11D] = OpHintNopEv, [0x11E] = OpUd, [0x11F] = OpNopEv, - [0x120] = OpUd, + [0x120] = OpMovRqCq, [0x121] = OpUd, - [0x122] = OpUd, + [0x122] = OpMovCqRq, [0x123] = OpUd, [0x124] = OpUd, [0x125] = OpUd, diff --git a/tool/build/lib/machine.h b/tool/build/lib/machine.h index 41469d2c..0d43c4a2 100644 --- a/tool/build/lib/machine.h +++ b/tool/build/lib/machine.h @@ -131,6 +131,9 @@ struct Machine { }; }; } sse; + uint64_t cr0; + uint64_t cr2; + uint64_t cr4; struct MachineRealFree { uint64_t i; uint64_t n; @@ -140,6 +143,15 @@ struct Machine { uint32_t i; void *p[6]; } freelist; + struct MachineMemstat { + int freed; + int resizes; + int reserved; + int committed; + int allocated; + int reclaimed; + int pagetables; + } memstat; int64_t brk; int64_t bofram[2]; jmp_buf onhalt; @@ -157,7 +169,9 @@ void ResetTlb(struct Machine *); void LoadInstruction(struct Machine *); void ExecuteInstruction(struct Machine *); long AllocateLinearPage(struct Machine *); -int ReserveVirtual(struct Machine *, int64_t, size_t); +long AllocateLinearPageRaw(struct Machine *); +int ReserveReal(struct Machine *, size_t); +int ReserveVirtual(struct Machine *, int64_t, size_t, uint64_t); char *FormatPml4t(struct Machine *) nodiscard; int64_t FindVirtual(struct Machine *, int64_t, size_t); int FreeVirtual(struct Machine *, int64_t, size_t); diff --git a/tool/build/lib/memory.c b/tool/build/lib/memory.c index 7d6a7ab6..409a09c6 100644 --- a/tool/build/lib/memory.c +++ b/tool/build/lib/memory.c @@ -19,6 +19,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" #include "libc/log/check.h" +#include "libc/log/log.h" #include "libc/macros.h" #include "libc/mem/mem.h" #include "libc/str/str.h" @@ -44,41 +45,58 @@ void SetWriteAddr(struct Machine *m, int64_t addr, uint32_t size) { } } +long HandlePageFault(struct Machine *m, uint64_t entry, uint64_t table, + unsigned index) { + long page; + if ((page = AllocateLinearPage(m)) != -1) { + --m->memstat.reserved; + *(uint64_t *)(m->real.p + table + index * 8) = + page | entry & ~0x7ffffffffe00; + } + return page; +} + void *FindReal(struct Machine *m, int64_t virt) { - uint8_t *host; - uint64_t real, pte, *pt; - unsigned skew, level, i; - if (!(-0x800000000000 <= virt && virt < 0x800000000000)) { + long page; + uint64_t table, entry; + unsigned skew, level, index, i; + if ((m->mode & 3) != XED_MODE_REAL) { + if (-0x800000000000 <= virt && virt < 0x800000000000) { + skew = virt & 0xfff; + virt &= -0x1000; + for (i = 0; i < ARRAYLEN(m->tlb); ++i) { + if (m->tlb[i].virt == virt && m->tlb[i].host) { + return m->tlb[i].host + skew; + } + } + level = 39; + entry = m->cr3; + do { + table = entry & 0x7ffffffff000; + CHECK_LT(table, m->real.n); + index = (virt >> level) & 511; + entry = *(uint64_t *)(m->real.p + table + index * 8); + if (!(entry & 1)) return NULL; + } while ((level -= 9) >= 12); + if (!(entry & 0x0e00)) { + page = entry & 0x7ffffffff000; + CHECK_LT(page, m->real.n); + } else if ((page = HandlePageFault(m, entry, table, index)) == -1) { + return NULL; + } + m->tlbindex = (m->tlbindex + 1) & (ARRAYLEN(m->tlb) - 1); + m->tlb[m->tlbindex] = m->tlb[0]; + m->tlb[0].virt = virt; + m->tlb[0].host = m->real.p + page; + return m->real.p + page + skew; + } else { + return NULL; + } + } else if (0 <= virt && virt + 0xfff < m->real.n) { + return m->real.p + virt; + } else { return NULL; } - skew = virt & 0xfff; - virt &= -0x1000; - for (i = 0; i < ARRAYLEN(m->tlb); ++i) { - if (m->tlb[i].virt == virt && m->tlb[i].host) { - return m->tlb[i].host + skew; - } - } - level = 39; - real = m->cr3; - for (;;) { - if (real + 0x1000 > m->real.n) { - return NULL; - } - host = m->real.p + real; - if (level < 12) break; - pt = (uint64_t *)host; - pte = pt[(virt >> level) & 511]; - if (!(pte & 1)) { - return NULL; - } - real = pte & 0x00007ffffffff000; - level -= 9; - } - m->tlbindex = (m->tlbindex + 1) & (ARRAYLEN(m->tlb) - 1); - m->tlb[m->tlbindex] = m->tlb[0]; - m->tlb[0].host = host; - m->tlb[0].virt = virt; - return host + skew; } void *ResolveAddress(struct Machine *m, int64_t v) { diff --git a/tool/build/lib/memorymalloc.c b/tool/build/lib/memorymalloc.c index 8fea2bb9..c46c64c5 100644 --- a/tool/build/lib/memorymalloc.c +++ b/tool/build/lib/memorymalloc.c @@ -35,7 +35,6 @@ struct Machine *NewMachine(void) { struct Machine *m; m = xmemalignzero(alignof(struct Machine), sizeof(struct Machine)); - m->mode = XED_MACHINE_MODE_LONG_64; ResetCpu(m); ResetMem(m); return m; @@ -60,11 +59,20 @@ void FreeMachine(struct Machine *m) { void ResetMem(struct Machine *m) { FreeMachineRealFree(m); ResetTlb(m); + memset(&m->memstat, 0, sizeof(m->memstat)); m->real.i = 0; - m->cr3 = AllocateLinearPage(m); + m->cr3 = 0; } long AllocateLinearPage(struct Machine *m) { + long page; + if ((page = AllocateLinearPageRaw(m)) != -1) { + memset(m->real.p + page, 0, 0x1000); + } + return page; +} + +long AllocateLinearPageRaw(struct Machine *m) { uint8_t *p; size_t i, n; struct MachineRealFree *rf; @@ -79,6 +87,8 @@ long AllocateLinearPage(struct Machine *m) { m->realfree = rf->next; free(rf); } + --m->memstat.freed; + ++m->memstat.reclaimed; } else { i = m->real.i; n = m->real.n; @@ -94,6 +104,7 @@ long AllocateLinearPage(struct Machine *m) { m->real.p = p; m->real.n = n; ResetTlb(m); + ++m->memstat.resizes; } else { return -1; } @@ -102,8 +113,9 @@ long AllocateLinearPage(struct Machine *m) { DCHECK_EQ(0, n & 0xfff); DCHECK_LE(i + 0x1000, n); m->real.i += 0x1000; + ++m->memstat.allocated; } - memset(m->real.p + i, 0, 0x1000); /* TODO: lazy page clearing */ + ++m->memstat.committed; return i; } @@ -117,24 +129,51 @@ static void MachineWrite64(struct Machine *m, unsigned long i, uint64_t x) { Write64(m->real.p + i, x); } -int ReserveVirtual(struct Machine *m, int64_t virt, size_t size) { - int64_t level, pt, ti, mi, end; - for (end = virt + size; virt < end; virt += 0x1000) { - for (pt = m->cr3, level = 39; level >= 12; level -= 9) { - pt = pt & 0x00007ffffffff000; - ti = (virt >> level) & 511; - DEBUGF("reserve %p level %d table %p index %ld", virt, level, pt, ti); - mi = pt + ti * 8; - pt = MachineRead64(m, mi); - if (!(pt & 1)) { - if ((pt = AllocateLinearPage(m)) == -1) return -1; - MachineWrite64(m, mi, pt | 7); - } +int ReserveReal(struct Machine *m, size_t n) { + uint8_t *p; + DCHECK_EQ(0, n & 0xfff); + if (m->real.n < n) { + if ((p = realloc(m->real.p, n))) { + m->real.p = p; + m->real.n = n; + ResetTlb(m); + ++m->memstat.resizes; + } else { + return -1; } } return 0; } +int ReserveVirtual(struct Machine *m, int64_t virt, size_t size, uint64_t key) { + int64_t ti, mi, pt, end, level; + for (end = virt + size;;) { + for (pt = m->cr3, level = 39; level >= 12; level -= 9) { + pt = pt & 0x7ffffffff000; + ti = (virt >> level) & 511; + mi = (pt & 0x7ffffffff000) + ti * 8; + pt = MachineRead64(m, mi); + if (level > 12) { + if (!(pt & 1)) { + if ((pt = AllocateLinearPage(m)) == -1) return -1; + MachineWrite64(m, mi, pt | 7); + ++m->memstat.pagetables; + } + continue; + } + for (;;) { + if (!(pt & 1)) { + MachineWrite64(m, mi, key); + ++m->memstat.reserved; + } + if ((virt += 0x1000) >= end) return 0; + if (++ti == 512) break; + pt = MachineRead64(m, (mi += 8)); + } + } + } +} + int64_t FindVirtual(struct Machine *m, int64_t virt, size_t size) { uint64_t i, pt, got; got = 0; @@ -154,30 +193,39 @@ int64_t FindVirtual(struct Machine *m, int64_t virt, size_t size) { return virt; } -int FreeVirtual(struct Machine *m, int64_t base, size_t size) { +static void AppendRealFree(struct Machine *m, uint64_t real) { struct MachineRealFree *rf; - uint64_t i, mi, pt, la, end, virt; - for (virt = base, end = virt + size; virt < end;) { + if (m->realfree && real == m->realfree->i + m->realfree->n) { + m->realfree->n += 0x1000; + } else if ((rf = malloc(sizeof(struct MachineRealFree)))) { + rf->i = real; + rf->n = 0x1000; + rf->next = m->realfree; + m->realfree = rf; + } +} + +int FreeVirtual(struct Machine *m, int64_t base, size_t size) { + uint64_t i, mi, pt, end, virt; + for (virt = base, end = virt + size; virt < end; virt += 1ull << i) { for (pt = m->cr3, i = 39;; i -= 9) { mi = (pt & 0x7ffffffff000) + ((virt >> i) & 511) * 8; pt = MachineRead64(m, mi); if (!(pt & 1)) { break; } else if (i == 12) { - MachineWrite64(m, mi, 0); - la = pt & 0x7ffffffff000; - if (m->realfree && la == m->realfree->i + m->realfree->n) { - m->realfree->n += 0x1000; - } else if ((rf = malloc(sizeof(struct MachineRealFree)))) { - rf->i = la; - rf->n = 0x1000; - rf->next = m->realfree; - m->realfree = rf; + ++m->memstat.freed; + if (pt & 0x0e00) { + --m->memstat.reserved; + } else { + --m->memstat.committed; + AppendRealFree(m, pt & 0x7ffffffff000); } + MachineWrite64(m, mi, 0); break; } } - virt += 1ull << i; } + ResetTlb(m); return 0; } diff --git a/tool/build/lib/modrm.c b/tool/build/lib/modrm.c index 601620e0..5685e8a8 100644 --- a/tool/build/lib/modrm.c +++ b/tool/build/lib/modrm.c @@ -236,6 +236,10 @@ uint8_t *GetModrmRegisterWordPointerWrite(struct Machine *m, uint32_t rde, } } +uint8_t *GetModrmRegisterWordPointerWrite2(struct Machine *m, uint32_t rde) { + return GetModrmRegisterWordPointerWrite(m, rde, 2); +} + uint8_t *GetModrmRegisterWordPointerWrite4(struct Machine *m, uint32_t rde) { return GetModrmRegisterWordPointerWrite(m, rde, 4); } diff --git a/tool/build/lib/modrm.h b/tool/build/lib/modrm.h index 95fca435..acc3d20b 100644 --- a/tool/build/lib/modrm.h +++ b/tool/build/lib/modrm.h @@ -59,7 +59,6 @@ extern const uint8_t kByteReg[32]; int64_t ComputeAddress(const struct Machine *, uint32_t); struct AddrSeg LoadEffectiveAddress(const struct Machine *, uint32_t); - void *ComputeReserveAddressRead(struct Machine *, uint32_t, size_t); void *ComputeReserveAddressRead1(struct Machine *, uint32_t); void *ComputeReserveAddressRead4(struct Machine *, uint32_t); @@ -68,7 +67,6 @@ void *ComputeReserveAddressWrite(struct Machine *, uint32_t, size_t); void *ComputeReserveAddressWrite1(struct Machine *, uint32_t); void *ComputeReserveAddressWrite4(struct Machine *, uint32_t); void *ComputeReserveAddressWrite8(struct Machine *, uint32_t); - uint8_t *GetModrmRegisterBytePointerRead(struct Machine *, uint32_t); uint8_t *GetModrmRegisterBytePointerWrite(struct Machine *, uint32_t); uint8_t *GetModrmRegisterMmPointerRead(struct Machine *, uint32_t, size_t); @@ -82,6 +80,7 @@ uint8_t *GetModrmRegisterWordPointerRead8(struct Machine *, uint32_t); uint8_t *GetModrmRegisterWordPointerReadOsz(struct Machine *, uint32_t); uint8_t *GetModrmRegisterWordPointerReadOszRexw(struct Machine *, uint32_t); uint8_t *GetModrmRegisterWordPointerWrite(struct Machine *, uint32_t, size_t); +uint8_t *GetModrmRegisterWordPointerWrite2(struct Machine *, uint32_t); uint8_t *GetModrmRegisterWordPointerWrite4(struct Machine *, uint32_t); uint8_t *GetModrmRegisterWordPointerWrite8(struct Machine *, uint32_t); uint8_t *GetModrmRegisterWordPointerWriteOsz(struct Machine *, uint32_t); diff --git a/tool/build/lib/op101.c b/tool/build/lib/op101.c new file mode 100644 index 00000000..30c13040 --- /dev/null +++ b/tool/build/lib/op101.c @@ -0,0 +1,160 @@ +/*-*- 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 │ +│ │ +│ This program is free software; you can redistribute it and/or modify │ +│ it under the terms of the GNU General Public License as published by │ +│ the Free Software Foundation; version 2 of the License. │ +│ │ +│ This program is distributed in the hope that it will be useful, but │ +│ WITHOUT ANY WARRANTY; without even the implied warranty of │ +│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │ +│ General Public License for more details. │ +│ │ +│ You should have received a copy of the GNU General Public License │ +│ along with this program; if not, write to the Free Software │ +│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ +│ 02110-1301 USA │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "tool/build/lib/endian.h" +#include "tool/build/lib/modrm.h" +#include "tool/build/lib/op101.h" +#include "tool/build/lib/throw.h" +#include "tool/build/lib/time.h" + +static void SgdtMs(struct Machine *m, uint32_t rde) { +} + +static void LgdtMs(struct Machine *m, uint32_t rde) { +} + +static void SidtMs(struct Machine *m, uint32_t rde) { +} + +static void LidtMs(struct Machine *m, uint32_t rde) { +} + +static void Monitor(struct Machine *m, uint32_t rde) { +} + +static void Mwait(struct Machine *m, uint32_t rde) { +} + +static void Swapgs(struct Machine *m, uint32_t rde) { +} + +static void Vmcall(struct Machine *m, uint32_t rde) { +} + +static void Vmlaunch(struct Machine *m, uint32_t rde) { +} + +static void Vmresume(struct Machine *m, uint32_t rde) { +} + +static void Vmxoff(struct Machine *m, uint32_t rde) { +} + +static void InvlpgM(struct Machine *m, uint32_t rde) { + ResetTlb(m); +} + +static void Smsw(struct Machine *m, uint32_t rde, bool ismem) { + if (ismem) { + Write16(GetModrmRegisterWordPointerWrite2(m, rde), m->cr0); + } else if (Rexw(rde)) { + Write64(RegRexrReg(m, rde), m->cr0); + } else if (!Osz(rde)) { + Write64(RegRexrReg(m, rde), m->cr0 & 0xffffffff); + } else { + Write16(RegRexrReg(m, rde), m->cr0); + } +} + +static void Lmsw(struct Machine *m, uint32_t rde) { + m->cr0 = Read16(GetModrmRegisterWordPointerRead2(m, rde)); +} + +void Op101(struct Machine *m, uint32_t rde) { + bool ismem; + ismem = !IsModrmRegister(rde); + switch (ModrmReg(rde)) { + case 0: + if (ismem) { + SgdtMs(m, rde); + } else { + switch (ModrmRm(rde)) { + case 1: + Vmcall(m, rde); + break; + case 2: + Vmlaunch(m, rde); + break; + case 3: + Vmresume(m, rde); + break; + case 4: + Vmxoff(m, rde); + break; + default: + OpUd(m, rde); + } + } + break; + case 1: + if (ismem) { + SidtMs(m, rde); + } else { + switch (ModrmRm(rde)) { + case 0: + Monitor(m, rde); + break; + case 1: + Mwait(m, rde); + break; + default: + OpUd(m, rde); + } + } + break; + case 2: + if (ismem) { + LgdtMs(m, rde); + } else { + OpUd(m, rde); + } + break; + case 3: + if (ismem) { + LidtMs(m, rde); + } else { + OpUd(m, rde); + } + break; + case 4: + Smsw(m, rde, ismem); + break; + case 6: + Lmsw(m, rde); + break; + case 7: + if (ismem) { + InvlpgM(m, rde); + } else { + switch (ModrmRm(rde)) { + case 0: + Swapgs(m, rde); + break; + case 1: + OpRdtscp(m, rde); + break; + default: + OpUd(m, rde); + } + } + break; + default: + OpUd(m, rde); + } +} diff --git a/tool/build/lib/op101.h b/tool/build/lib/op101.h new file mode 100644 index 00000000..7e8cb0a5 --- /dev/null +++ b/tool/build/lib/op101.h @@ -0,0 +1,11 @@ +#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_OP101_H_ +#define COSMOPOLITAN_TOOL_BUILD_LIB_OP101_H_ +#include "tool/build/lib/machine.h" +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +void Op101(struct Machine *, uint32_t); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_TOOL_BUILD_LIB_OP101_H_ */ diff --git a/tool/build/lib/panel.h b/tool/build/lib/panel.h index 93d2a7a2..d0e48660 100644 --- a/tool/build/lib/panel.h +++ b/tool/build/lib/panel.h @@ -5,10 +5,12 @@ COSMOPOLITAN_C_START_ struct Panel { - int i; - int top, bottom; - int left, right; + int top; + int bottom; + int left; + int right; struct Buffer *lines; + size_t n; }; ssize_t PrintPanels(int, long, struct Panel *, long, long); diff --git a/tool/build/lib/pml4tfmt.c b/tool/build/lib/pml4tfmt.c index 434ffb84..3ea5dcf8 100644 --- a/tool/build/lib/pml4tfmt.c +++ b/tool/build/lib/pml4tfmt.c @@ -70,6 +70,7 @@ char *FormatPml4t(struct Machine *m) { unsigned short i, a[4]; struct Pml4tFormater pp = {0}; unsigned short range[][2] = {{256, 512}, {0, 256}}; + if ((m->mode & 3) != XED_MODE_LONG) return strdup(""); pd[0] = GetPt(m, m->cr3); for (i = 0; i < ARRAYLEN(range); ++i) { a[0] = range[i][0]; diff --git a/tool/build/lib/pty.c b/tool/build/lib/pty.c index 5e9d8d3d..c7464602 100644 --- a/tool/build/lib/pty.c +++ b/tool/build/lib/pty.c @@ -32,6 +32,7 @@ #include "libc/str/str.h" #include "libc/str/thompike.h" #include "libc/str/tpenc.h" +#include "libc/sysv/errfuns.h" #include "libc/unicode/unicode.h" #include "libc/x/x.h" #include "tool/build/lib/pty.h" @@ -159,30 +160,30 @@ * @see ECMA-48 */ -struct MachinePty *MachinePtyNew(void) { - struct MachinePty *pty; - pty = xcalloc(1, sizeof(struct MachinePty)); - MachinePtyResize(pty, 25, 80); - MachinePtyFullReset(pty); - MachinePtyErase(pty, 0, pty->yn * pty->xn); +struct Pty *NewPty(void) { + struct Pty *pty; + pty = xcalloc(1, sizeof(struct Pty)); + PtyResize(pty, 25, 80); + PtyFullReset(pty); + PtyErase(pty, 0, pty->yn * pty->xn); return pty; } -static void MachinePtyFreePlanes(struct MachinePty *pty) { +static void FreePtyPlanes(struct Pty *pty) { free(pty->wcs); free(pty->fgs); free(pty->bgs); free(pty->prs); } -void MachinePtyFree(struct MachinePty *pty) { +void FreePty(struct Pty *pty) { if (pty) { - MachinePtyFreePlanes(pty); + FreePtyPlanes(pty); free(pty); } } -static wchar_t *MachinePtyGetXlatAscii(void) { +static wchar_t *GetXlatAscii(void) { unsigned i; static bool once; static wchar_t xlat[128]; @@ -195,7 +196,7 @@ static wchar_t *MachinePtyGetXlatAscii(void) { return xlat; } -static wchar_t *MachinePtyGetXlatLineDrawing(void) { +static wchar_t *GetXlatLineDrawing(void) { unsigned i; static bool once; static wchar_t xlat[128]; @@ -212,7 +213,7 @@ static wchar_t *MachinePtyGetXlatLineDrawing(void) { return xlat; } -static void MachinePtyXlatAlphabet(wchar_t xlat[128], int a, int b) { +static void XlatAlphabet(wchar_t xlat[128], int a, int b) { unsigned i; for (i = 0; i < 128; ++i) { if ('a' <= i && i <= 'z') { @@ -225,37 +226,37 @@ static void MachinePtyXlatAlphabet(wchar_t xlat[128], int a, int b) { } } -static wchar_t *MachinePtyGetXlatItalic(void) { +static wchar_t *GetXlatItalic(void) { static bool once; static wchar_t xlat[128]; if (!once) { - MachinePtyXlatAlphabet(xlat, L'𝑎', L'𝐴'); + XlatAlphabet(xlat, L'𝑎', L'𝐴'); once = true; } return xlat; } -static wchar_t *MachinePtyGetXlatBoldItalic(void) { +static wchar_t *GetXlatBoldItalic(void) { static bool once; static wchar_t xlat[128]; if (!once) { - MachinePtyXlatAlphabet(xlat, L'𝒂', L'𝑨'); + XlatAlphabet(xlat, L'𝒂', L'𝑨'); once = true; } return xlat; } -static wchar_t *MachinePtyGetXlatBoldFraktur(void) { +static wchar_t *GetXlatBoldFraktur(void) { static bool once; static wchar_t xlat[128]; if (!once) { - MachinePtyXlatAlphabet(xlat, L'𝖆', L'𝕬'); + XlatAlphabet(xlat, L'𝖆', L'𝕬'); once = true; } return xlat; } -static wchar_t *MachinePtyGetXlatFraktur(void) { +static wchar_t *GetXlatFraktur(void) { unsigned i; static bool once; static wchar_t xlat[128]; @@ -274,7 +275,7 @@ static wchar_t *MachinePtyGetXlatFraktur(void) { return xlat; } -static wchar_t *MachinePtyGetXlatDoubleWidth(void) { +static wchar_t *GetXlatDoubleWidth(void) { unsigned i; static bool once; static wchar_t xlat[128]; @@ -291,50 +292,49 @@ static wchar_t *MachinePtyGetXlatDoubleWidth(void) { return xlat; } -static wchar_t *MachinePtyGetXlatSgr(struct MachinePty *pty) { - switch (!!(pty->pr & kMachinePtyFraktur) << 2 | - !!(pty->pr & kMachinePtyItalic) << 1 | - !!(pty->pr & kMachinePtyBold) << 0) { +static wchar_t *GetXlatSgr(struct Pty *pty) { + switch (!!(pty->pr & kPtyFraktur) << 2 | !!(pty->pr & kPtyItalic) << 1 | + !!(pty->pr & kPtyBold) << 0) { case 0b100: case 0b110: - return MachinePtyGetXlatFraktur(); + return GetXlatFraktur(); case 0b101: case 0b111: - return MachinePtyGetXlatBoldFraktur(); + return GetXlatBoldFraktur(); case 0b011: - return MachinePtyGetXlatBoldItalic(); + return GetXlatBoldItalic(); case 0b010: - return MachinePtyGetXlatItalic(); + return GetXlatItalic(); default: - return MachinePtyGetXlatAscii(); + return GetXlatAscii(); } } -static void MachinePtySetXlat(struct MachinePty *pty, wchar_t *xlat) { +static void PtySetXlat(struct Pty *pty, wchar_t *xlat) { pty->xlat = xlat; - pty->pr &= ~(kMachinePtyItalic | kMachinePtyFraktur); + pty->pr &= ~(kPtyItalic | kPtyFraktur); } -static void MachinePtySetCodepage(struct MachinePty *pty, char id) { +static void PtySetCodepage(struct Pty *pty, char id) { unsigned i; switch (id) { default: case 'B': - MachinePtySetXlat(pty, MachinePtyGetXlatAscii()); + PtySetXlat(pty, GetXlatAscii()); break; case '0': - MachinePtySetXlat(pty, MachinePtyGetXlatLineDrawing()); + PtySetXlat(pty, GetXlatLineDrawing()); break; } } -void MachinePtyErase(struct MachinePty *pty, long dst, long n) { +void PtyErase(struct Pty *pty, long dst, long n) { DCHECK_LE(dst + n, pty->yn * pty->xn); wmemset((void *)(pty->wcs + dst), ' ', n); wmemset((void *)(pty->prs + dst), 0, n); } -void MachinePtyMemmove(struct MachinePty *pty, long dst, long src, long n) { +void PtyMemmove(struct Pty *pty, long dst, long src, long n) { DCHECK_LE(src + n, pty->yn * pty->xn); DCHECK_LE(dst + n, pty->yn * pty->xn); memmove(pty->wcs + dst, pty->wcs + src, n * 4); @@ -343,7 +343,7 @@ void MachinePtyMemmove(struct MachinePty *pty, long dst, long src, long n) { memmove(pty->prs + dst, pty->prs + src, n * 4); } -void MachinePtyFullReset(struct MachinePty *pty) { +void PtyFullReset(struct Pty *pty) { pty->y = 0; pty->x = 0; pty->pr = 0; @@ -354,21 +354,21 @@ void MachinePtyFullReset(struct MachinePty *pty) { pty->state = 0; pty->esc.i = 0; pty->input.i = 0; - pty->xlat = MachinePtyGetXlatAscii(); - MachinePtyErase(pty, 0, pty->yn * pty->xn); + pty->xlat = GetXlatAscii(); + PtyErase(pty, 0, pty->yn * pty->xn); } -void MachinePtySetY(struct MachinePty *pty, int y) { - pty->conf &= ~kMachinePtyRedzone; +void PtySetY(struct Pty *pty, int y) { + pty->conf &= ~kPtyRedzone; pty->y = MAX(0, MIN(pty->yn - 1, y)); } -void MachinePtySetX(struct MachinePty *pty, int x) { - pty->conf &= ~kMachinePtyRedzone; +void PtySetX(struct Pty *pty, int x) { + pty->conf &= ~kPtyRedzone; pty->x = MAX(0, MIN(pty->xn - 1, x)); } -void MachinePtyResize(struct MachinePty *pty, int yn, int xn) { +void PtyResize(struct Pty *pty, int yn, int xn) { unsigned y, ym, xm, y0; uint32_t *wcs, *fgs, *bgs, *prs; if (xn < 80) xn = 80; @@ -387,93 +387,92 @@ void MachinePtyResize(struct MachinePty *pty, int yn, int xn) { memcpy(bgs + y * xn, pty->bgs + y * pty->xn, xm * 4); memcpy(prs + y * xn, pty->prs + y * pty->xn, xm * 4); } - MachinePtyFreePlanes(pty); + FreePtyPlanes(pty); pty->wcs = wcs; pty->fgs = fgs; pty->bgs = bgs; pty->prs = prs; pty->yn = yn; pty->xn = xn; - MachinePtySetY(pty, pty->y); - MachinePtySetX(pty, pty->x); + PtySetY(pty, pty->y); + PtySetX(pty, pty->x); } -static void MachinePtyConcatInput(struct MachinePty *pty, const char *data, - size_t n) { +static void PtyConcatInput(struct Pty *pty, const char *data, size_t n) { CONCAT(&pty->input.p, &pty->input.i, &pty->input.n, data, n); } -static void MachinePtyScroll(struct MachinePty *pty) { - MachinePtyMemmove(pty, 0, pty->xn, pty->xn * (pty->yn - 1)); - MachinePtyErase(pty, pty->xn * (pty->yn - 1), pty->xn); +static void PtyScroll(struct Pty *pty) { + PtyMemmove(pty, 0, pty->xn, pty->xn * (pty->yn - 1)); + PtyErase(pty, pty->xn * (pty->yn - 1), pty->xn); } -static void MachinePtyReverse(struct MachinePty *pty) { - MachinePtyMemmove(pty, pty->xn, 0, pty->xn * (pty->yn - 1)); - MachinePtyErase(pty, 0, pty->xn); +static void PtyReverse(struct Pty *pty) { + PtyMemmove(pty, pty->xn, 0, pty->xn * (pty->yn - 1)); + PtyErase(pty, 0, pty->xn); } -static void MachinePtyIndex(struct MachinePty *pty) { +static void PtyIndex(struct Pty *pty) { if (pty->y < pty->yn - 1) { ++pty->y; } else { - MachinePtyScroll(pty); + PtyScroll(pty); } } -static void MachinePtyReverseIndex(struct MachinePty *pty) { +static void PtyReverseIndex(struct Pty *pty) { if (pty->y) { --pty->y; } else { - MachinePtyReverse(pty); + PtyReverse(pty); } } -static void MachinePtyCarriageReturn(struct MachinePty *pty) { - MachinePtySetX(pty, 0); +static void PtyCarriageReturn(struct Pty *pty) { + PtySetX(pty, 0); } -static void MachinePtyNewline(struct MachinePty *pty) { - MachinePtyIndex(pty); - if (!(pty->conf & kMachinePtyNoopost)) { - MachinePtyCarriageReturn(pty); +static void PtyNewline(struct Pty *pty) { + PtyIndex(pty); + if (!(pty->conf & kPtyNoopost)) { + PtyCarriageReturn(pty); } } -static void MachinePtyAdvance(struct MachinePty *pty) { +static void PtyAdvance(struct Pty *pty) { DCHECK_EQ(pty->xn - 1, pty->x); - DCHECK(pty->conf & kMachinePtyRedzone); - pty->conf &= ~kMachinePtyRedzone; + DCHECK(pty->conf & kPtyRedzone); + pty->conf &= ~kPtyRedzone; pty->x = 0; if (pty->y < pty->yn - 1) { ++pty->y; } else { - MachinePtyScroll(pty); + PtyScroll(pty); } } -static void MachinePtyWriteGlyph(struct MachinePty *pty, wint_t wc, int w) { +static void PtyWriteGlyph(struct Pty *pty, wint_t wc, int w) { uint32_t i; if (w < 1) wc = ' ', w = 1; - if ((pty->conf & kMachinePtyRedzone) || pty->x + w > pty->xn) { - MachinePtyAdvance(pty); + if ((pty->conf & kPtyRedzone) || pty->x + w > pty->xn) { + PtyAdvance(pty); } i = pty->y * pty->xn + pty->x; pty->wcs[i] = wc; - if ((pty->prs[i] = pty->pr) & (kMachinePtyFg | kMachinePtyBg)) { + if ((pty->prs[i] = pty->pr) & (kPtyFg | kPtyBg)) { pty->fgs[i] = pty->fg; pty->bgs[i] = pty->bg; } if ((pty->x += w) >= pty->xn) { pty->x = pty->xn - 1; - pty->conf |= kMachinePtyRedzone; + pty->conf |= kPtyRedzone; } } -static void MachinePtyWriteTab(struct MachinePty *pty) { +static void PtyWriteTab(struct Pty *pty) { unsigned x, x2; - if (pty->conf & kMachinePtyRedzone) { - MachinePtyAdvance(pty); + if (pty->conf & kPtyRedzone) { + PtyAdvance(pty); } x2 = MIN(pty->xn, ROUNDUP(pty->x + 1, 8)); for (x = pty->x; x < x2; ++x) { @@ -483,73 +482,73 @@ static void MachinePtyWriteTab(struct MachinePty *pty) { pty->x = x2; } else { pty->x = pty->xn - 1; - pty->conf |= kMachinePtyRedzone; + pty->conf |= kPtyRedzone; } } -static int MachinePtyAtoi(const char *s, const char **e) { +int PtyAtoi(const char *s, const char **e) { int i; for (i = 0; isdigit(*s); ++s) i *= 10, i += *s - '0'; if (e) *e = s; return i; } -static int MachinePtyGetMoveParam(struct MachinePty *pty) { - int x = MachinePtyAtoi(pty->esc.s, NULL); +static int PtyGetMoveParam(struct Pty *pty) { + int x = PtyAtoi(pty->esc.s, NULL); if (x < 1) x = 1; return x; } -static void MachinePtySetCursorPosition(struct MachinePty *pty) { +static void PtySetCursorPosition(struct Pty *pty) { int row, col; const char *s = pty->esc.s; - row = max(1, MachinePtyAtoi(s, &s)); + row = max(1, PtyAtoi(s, &s)); if (*s == ';') ++s; - col = max(1, MachinePtyAtoi(s, &s)); - MachinePtySetY(pty, row - 1); - MachinePtySetX(pty, col - 1); + col = max(1, PtyAtoi(s, &s)); + PtySetY(pty, row - 1); + PtySetX(pty, col - 1); } -static void MachinePtySetCursorRow(struct MachinePty *pty) { - MachinePtySetY(pty, MachinePtyGetMoveParam(pty) - 1); +static void PtySetCursorRow(struct Pty *pty) { + PtySetY(pty, PtyGetMoveParam(pty) - 1); } -static void MachinePtySetCursorColumn(struct MachinePty *pty) { - MachinePtySetX(pty, MachinePtyGetMoveParam(pty) - 1); +static void PtySetCursorColumn(struct Pty *pty) { + PtySetX(pty, PtyGetMoveParam(pty) - 1); } -static void MachinePtyMoveCursor(struct MachinePty *pty, int dy, int dx) { - int n = MachinePtyGetMoveParam(pty); - MachinePtySetY(pty, pty->y + dy * n); - MachinePtySetX(pty, pty->x + dx * n); +static void PtyMoveCursor(struct Pty *pty, int dy, int dx) { + int n = PtyGetMoveParam(pty); + PtySetY(pty, pty->y + dy * n); + PtySetX(pty, pty->x + dx * n); } -static void MachinePtyScrollUp(struct MachinePty *pty) { - int n = MachinePtyGetMoveParam(pty); - while (n--) MachinePtyScroll(pty); +static void PtyScrollUp(struct Pty *pty) { + int n = PtyGetMoveParam(pty); + while (n--) PtyScroll(pty); } -static void MachinePtyScrollDown(struct MachinePty *pty) { - int n = MachinePtyGetMoveParam(pty); - while (n--) MachinePtyReverse(pty); +static void PtyScrollDown(struct Pty *pty) { + int n = PtyGetMoveParam(pty); + while (n--) PtyReverse(pty); } -static void MachinePtySetCursorStatus(struct MachinePty *pty, bool status) { +static void PtySetCursorStatus(struct Pty *pty, bool status) { if (status) { - pty->conf &= ~kMachinePtyNocursor; + pty->conf &= ~kPtyNocursor; } else { - pty->conf |= kMachinePtyNocursor; + pty->conf |= kPtyNocursor; } } -static void MachinePtySetMode(struct MachinePty *pty, bool status) { +static void PtySetMode(struct Pty *pty, bool status) { const char *p = pty->esc.s; switch (*p++) { case '?': while (isdigit(*p)) { - switch (MachinePtyAtoi(p, &p)) { + switch (PtyAtoi(p, &p)) { case 25: - MachinePtySetCursorStatus(pty, status); + PtySetCursorStatus(pty, status); break; default: break; @@ -564,131 +563,131 @@ static void MachinePtySetMode(struct MachinePty *pty, bool status) { } } -static void MachinePtySaveCursorPosition(struct MachinePty *pty) { +static void PtySaveCursorPosition(struct Pty *pty) { pty->save = (pty->y & 0x7FFF) | (pty->x & 0x7FFF) << 16; } -static void MachinePtyRestoreCursorPosition(struct MachinePty *pty) { - MachinePtySetY(pty, (pty->save & 0x00007FFF) >> 000); - MachinePtySetX(pty, (pty->save & 0x7FFF0000) >> 020); +static void PtyRestoreCursorPosition(struct Pty *pty) { + PtySetY(pty, (pty->save & 0x00007FFF) >> 000); + PtySetX(pty, (pty->save & 0x7FFF0000) >> 020); } -static void MachinePtyEraseDisplay(struct MachinePty *pty) { - switch (MachinePtyAtoi(pty->esc.s, NULL)) { +static void PtyEraseDisplay(struct Pty *pty) { + switch (PtyAtoi(pty->esc.s, NULL)) { case 0: - MachinePtyErase(pty, pty->y * pty->xn + pty->x, - pty->yn * pty->xn - (pty->y * pty->xn + pty->x)); + PtyErase(pty, pty->y * pty->xn + pty->x, + pty->yn * pty->xn - (pty->y * pty->xn + pty->x)); break; case 1: - MachinePtyErase(pty, 0, pty->y * pty->xn + pty->x); + PtyErase(pty, 0, pty->y * pty->xn + pty->x); break; case 2: case 3: - MachinePtyErase(pty, 0, pty->yn * pty->xn); + PtyErase(pty, 0, pty->yn * pty->xn); break; default: break; } } -static void MachinePtyEraseLine(struct MachinePty *pty) { - switch (MachinePtyAtoi(pty->esc.s, NULL)) { +static void PtyEraseLine(struct Pty *pty) { + switch (PtyAtoi(pty->esc.s, NULL)) { case 0: - MachinePtyErase(pty, pty->y * pty->xn + pty->x, pty->xn - pty->x); + PtyErase(pty, pty->y * pty->xn + pty->x, pty->xn - pty->x); break; case 1: - MachinePtyErase(pty, pty->y * pty->xn, pty->x); + PtyErase(pty, pty->y * pty->xn, pty->x); break; case 2: - MachinePtyErase(pty, pty->y * pty->xn, pty->xn); + PtyErase(pty, pty->y * pty->xn, pty->xn); break; default: break; } } -static void MachinePtyEraseCells(struct MachinePty *pty) { +static void PtyEraseCells(struct Pty *pty) { int i, n, x; i = pty->y * pty->xn + pty->x; n = pty->yn * pty->xn; - x = min(max(MachinePtyAtoi(pty->esc.s, NULL), 1), n - i); - MachinePtyErase(pty, i, x); + x = min(max(PtyAtoi(pty->esc.s, NULL), 1), n - i); + PtyErase(pty, i, x); } -static int MachinePtyArg1(struct MachinePty *pty) { - return max(1, MachinePtyAtoi(pty->esc.s, NULL)); +static int PtyArg1(struct Pty *pty) { + return max(1, PtyAtoi(pty->esc.s, NULL)); } -static void MachinePtyInsertCells(struct MachinePty *pty) { - int n = min(pty->xn - pty->x, MachinePtyArg1(pty)); - MachinePtyMemmove(pty, pty->y * pty->xn + pty->x + n, - pty->y * pty->xn + pty->x, pty->xn - (pty->x + n)); - MachinePtyErase(pty, pty->y * pty->xn + pty->x, n); +static void PtyInsertCells(struct Pty *pty) { + int n = min(pty->xn - pty->x, PtyArg1(pty)); + PtyMemmove(pty, pty->y * pty->xn + pty->x + n, pty->y * pty->xn + pty->x, + pty->xn - (pty->x + n)); + PtyErase(pty, pty->y * pty->xn + pty->x, n); } -static void MachinePtyInsertLines(struct MachinePty *pty) { - int n = min(pty->yn - pty->y, MachinePtyArg1(pty)); - MachinePtyMemmove(pty, (pty->y + n) * pty->xn, pty->y * pty->xn, - (pty->yn - pty->y - n) * pty->xn); - MachinePtyErase(pty, pty->y * pty->xn, n * pty->xn); +static void PtyInsertLines(struct Pty *pty) { + int n = min(pty->yn - pty->y, PtyArg1(pty)); + PtyMemmove(pty, (pty->y + n) * pty->xn, pty->y * pty->xn, + (pty->yn - pty->y - n) * pty->xn); + PtyErase(pty, pty->y * pty->xn, n * pty->xn); } -static void MachinePtyDeleteCells(struct MachinePty *pty) { - int n = min(pty->xn - pty->x, MachinePtyArg1(pty)); - MachinePtyMemmove(pty, pty->y * pty->xn + pty->x, - pty->y * pty->xn + pty->x + n, pty->xn - (pty->x + n)); - MachinePtyErase(pty, pty->y * pty->xn + pty->x, n); +static void PtyDeleteCells(struct Pty *pty) { + int n = min(pty->xn - pty->x, PtyArg1(pty)); + PtyMemmove(pty, pty->y * pty->xn + pty->x, pty->y * pty->xn + pty->x + n, + pty->xn - (pty->x + n)); + PtyErase(pty, pty->y * pty->xn + pty->x, n); } -static void MachinePtyDeleteLines(struct MachinePty *pty) { - int n = min(pty->yn - pty->y, MachinePtyArg1(pty)); - MachinePtyMemmove(pty, pty->y * pty->xn, (pty->y + n) * pty->xn, - (pty->yn - pty->y - n) * pty->xn); - MachinePtyErase(pty, (pty->y + n) * pty->xn, n * pty->xn); +static void PtyDeleteLines(struct Pty *pty) { + int n = min(pty->yn - pty->y, PtyArg1(pty)); + PtyMemmove(pty, pty->y * pty->xn, (pty->y + n) * pty->xn, + (pty->yn - pty->y - n) * pty->xn); + PtyErase(pty, (pty->y + n) * pty->xn, n * pty->xn); } -static void MachinePtyReportDeviceStatus(struct MachinePty *pty) { - MachinePtyWriteInput(pty, "\e[0n", 4); +static void PtyReportDeviceStatus(struct Pty *pty) { + PtyWriteInput(pty, "\e[0n", 4); } -static void MachinePtyReportPreferredVtType(struct MachinePty *pty) { - MachinePtyWriteInput(pty, "\e[?1;0c", 4); +static void PtyReportPreferredVtType(struct Pty *pty) { + PtyWriteInput(pty, "\e[?1;0c", 4); } -static void MachinePtyReportPreferredVtIdentity(struct MachinePty *pty) { - MachinePtyWriteInput(pty, "\e/Z", 4); +static void PtyReportPreferredVtIdentity(struct Pty *pty) { + PtyWriteInput(pty, "\e/Z", 4); } -static void MachinePtyBell(struct MachinePty *pty) { - pty->conf |= kMachinePtyBell; +static void PtyBell(struct Pty *pty) { + pty->conf |= kPtyBell; } -static void MachinePtyLed(struct MachinePty *pty) { - switch (MachinePtyAtoi(pty->esc.s, NULL)) { +static void PtyLed(struct Pty *pty) { + switch (PtyAtoi(pty->esc.s, NULL)) { case 0: - pty->conf &= ~kMachinePtyLed1; - pty->conf &= ~kMachinePtyLed2; - pty->conf &= ~kMachinePtyLed3; - pty->conf &= ~kMachinePtyLed4; + pty->conf &= ~kPtyLed1; + pty->conf &= ~kPtyLed2; + pty->conf &= ~kPtyLed3; + pty->conf &= ~kPtyLed4; break; case 1: - pty->conf |= kMachinePtyLed1; + pty->conf |= kPtyLed1; break; case 2: - pty->conf |= kMachinePtyLed2; + pty->conf |= kPtyLed2; break; case 3: - pty->conf |= kMachinePtyLed3; + pty->conf |= kPtyLed3; break; case 4: - pty->conf |= kMachinePtyLed4; + pty->conf |= kPtyLed4; break; default: break; } } -static void MachinePtyReportCursorPosition(struct MachinePty *pty) { +static void PtyReportCursorPosition(struct Pty *pty) { char *p; char buf[2 + 10 + 1 + 10 + 1]; p = buf; @@ -698,23 +697,23 @@ static void MachinePtyReportCursorPosition(struct MachinePty *pty) { *p++ = ';'; p += uint64toarray_radix10((pty->x + 1) & 0x7fff, p); *p++ = 'R'; - MachinePtyWriteInput(pty, buf, p - buf); + PtyWriteInput(pty, buf, p - buf); } -static void MachinePtyCsiN(struct MachinePty *pty) { - switch (MachinePtyAtoi(pty->esc.s, NULL)) { +static void PtyCsiN(struct Pty *pty) { + switch (PtyAtoi(pty->esc.s, NULL)) { case 5: - MachinePtyReportDeviceStatus(pty); + PtyReportDeviceStatus(pty); break; case 6: - MachinePtyReportCursorPosition(pty); + PtyReportCursorPosition(pty); break; default: break; } } -static void MachinePtySelectGraphicsRendition(struct MachinePty *pty) { +static void PtySelectGraphicsRendition(struct Pty *pty) { char *p, c; unsigned x; uint8_t code[4]; @@ -755,69 +754,69 @@ static void MachinePtySelectGraphicsRendition(struct MachinePty *pty) { break; case 0: pty->pr = 0; - pty->xlat = MachinePtyGetXlatSgr(pty); + pty->xlat = GetXlatSgr(pty); break; case 1: - pty->pr |= kMachinePtyBold; - pty->xlat = MachinePtyGetXlatSgr(pty); + pty->pr |= kPtyBold; + pty->xlat = GetXlatSgr(pty); break; case 2: - pty->pr |= kMachinePtyFaint; + pty->pr |= kPtyFaint; break; case 3: - pty->pr |= kMachinePtyItalic; - pty->xlat = MachinePtyGetXlatSgr(pty); + pty->pr |= kPtyItalic; + pty->xlat = GetXlatSgr(pty); break; case 4: - pty->pr |= kMachinePtyUnder; + pty->pr |= kPtyUnder; break; case 5: - pty->pr |= kMachinePtyBlink; + pty->pr |= kPtyBlink; break; case 7: - pty->pr |= kMachinePtyFlip; + pty->pr |= kPtyFlip; break; case 8: - pty->pr |= kMachinePtyConceal; + pty->pr |= kPtyConceal; break; case 9: - pty->pr |= kMachinePtyStrike; + pty->pr |= kPtyStrike; break; case 20: - pty->pr |= kMachinePtyFraktur; - pty->xlat = MachinePtyGetXlatSgr(pty); + pty->pr |= kPtyFraktur; + pty->xlat = GetXlatSgr(pty); break; case 21: - pty->pr |= kMachinePtyUnder | kMachinePtyDunder; + pty->pr |= kPtyUnder | kPtyDunder; break; case 22: - pty->pr &= ~(kMachinePtyFaint | kMachinePtyBold); - pty->xlat = MachinePtyGetXlatSgr(pty); + pty->pr &= ~(kPtyFaint | kPtyBold); + pty->xlat = GetXlatSgr(pty); break; case 23: - pty->pr &= ~kMachinePtyItalic; - pty->xlat = MachinePtyGetXlatSgr(pty); + pty->pr &= ~kPtyItalic; + pty->xlat = GetXlatSgr(pty); break; case 24: - pty->pr &= ~(kMachinePtyUnder | kMachinePtyDunder); + pty->pr &= ~(kPtyUnder | kPtyDunder); break; case 25: - pty->pr &= ~kMachinePtyBlink; + pty->pr &= ~kPtyBlink; break; case 27: - pty->pr &= ~kMachinePtyFlip; + pty->pr &= ~kPtyFlip; break; case 28: - pty->pr &= ~kMachinePtyConceal; + pty->pr &= ~kPtyConceal; break; case 29: - pty->pr &= ~kMachinePtyStrike; + pty->pr &= ~kPtyStrike; break; case 39: - pty->pr &= ~kMachinePtyFg; + pty->pr &= ~kPtyFg; break; case 49: - pty->pr &= ~kMachinePtyBg; + pty->pr &= ~kPtyBg; break; case 90 ... 97: code[0] -= 90 - 30; @@ -825,8 +824,8 @@ static void MachinePtySelectGraphicsRendition(struct MachinePty *pty) { /* fallthrough */ case 30 ... 37: pty->fg = code[0] - 30; - pty->pr |= kMachinePtyFg; - pty->pr &= ~kMachinePtyTrue; + pty->pr |= kPtyFg; + pty->pr &= ~kPtyTrue; break; case 100 ... 107: code[0] -= 100 - 40; @@ -834,8 +833,8 @@ static void MachinePtySelectGraphicsRendition(struct MachinePty *pty) { /* fallthrough */ case 40 ... 47: pty->bg = code[0] - 40; - pty->pr |= kMachinePtyBg; - pty->pr &= ~kMachinePtyTrue; + pty->pr |= kPtyBg; + pty->pr &= ~kPtyTrue; break; default: break; @@ -858,8 +857,8 @@ static void MachinePtySelectGraphicsRendition(struct MachinePty *pty) { code[3] = 0; t = kSgr; pty->fg = READ32LE(code); - pty->pr |= kMachinePtyFg; - pty->pr |= kMachinePtyTrue; + pty->pr |= kPtyFg; + pty->pr |= kPtyTrue; } break; case kSgrBgTrue: @@ -867,21 +866,21 @@ static void MachinePtySelectGraphicsRendition(struct MachinePty *pty) { code[3] = 0; t = kSgr; pty->bg = READ32LE(code); - pty->pr |= kMachinePtyBg; - pty->pr |= kMachinePtyTrue; + pty->pr |= kPtyBg; + pty->pr |= kPtyTrue; } break; case kSgrFgXterm: t = kSgr; pty->fg = code[0]; - pty->pr |= kMachinePtyFg; - pty->pr &= ~kMachinePtyTrue; + pty->pr |= kPtyFg; + pty->pr &= ~kPtyTrue; break; case kSgrBgXterm: t = kSgr; pty->bg = code[0]; - pty->pr |= kMachinePtyBg; - pty->pr &= ~kMachinePtyTrue; + pty->pr |= kPtyBg; + pty->pr &= ~kPtyTrue; break; default: abort(); @@ -893,243 +892,243 @@ static void MachinePtySelectGraphicsRendition(struct MachinePty *pty) { } } -static void MachinePtyCsi(struct MachinePty *pty) { +static void PtyCsi(struct Pty *pty) { switch (pty->esc.s[pty->esc.i - 1]) { case 'f': case 'H': - MachinePtySetCursorPosition(pty); + PtySetCursorPosition(pty); break; case 'G': - MachinePtySetCursorColumn(pty); + PtySetCursorColumn(pty); break; case 'd': - MachinePtySetCursorRow(pty); + PtySetCursorRow(pty); break; case 'F': pty->x = 0; /* fallthrough */ case 'A': - MachinePtyMoveCursor(pty, -1, +0); + PtyMoveCursor(pty, -1, +0); break; case 'E': pty->x = 0; /* fallthrough */ case 'B': - MachinePtyMoveCursor(pty, +1, +0); + PtyMoveCursor(pty, +1, +0); break; case 'C': - MachinePtyMoveCursor(pty, +0, +1); + PtyMoveCursor(pty, +0, +1); break; case 'D': - MachinePtyMoveCursor(pty, +0, -1); + PtyMoveCursor(pty, +0, -1); break; case 'S': - MachinePtyScrollUp(pty); + PtyScrollUp(pty); break; case 'T': - MachinePtyScrollDown(pty); + PtyScrollDown(pty); break; case '@': - MachinePtyInsertCells(pty); + PtyInsertCells(pty); break; case 'P': - MachinePtyDeleteCells(pty); + PtyDeleteCells(pty); break; case 'L': - MachinePtyInsertLines(pty); + PtyInsertLines(pty); break; case 'M': - MachinePtyDeleteLines(pty); + PtyDeleteLines(pty); break; case 'J': - MachinePtyEraseDisplay(pty); + PtyEraseDisplay(pty); break; case 'K': - MachinePtyEraseLine(pty); + PtyEraseLine(pty); break; case 'X': - MachinePtyEraseCells(pty); + PtyEraseCells(pty); break; case 's': - MachinePtySaveCursorPosition(pty); + PtySaveCursorPosition(pty); break; case 'u': - MachinePtyRestoreCursorPosition(pty); + PtyRestoreCursorPosition(pty); break; case 'n': - MachinePtyCsiN(pty); + PtyCsiN(pty); break; case 'm': - MachinePtySelectGraphicsRendition(pty); + PtySelectGraphicsRendition(pty); break; case 'h': - MachinePtySetMode(pty, true); + PtySetMode(pty, true); break; case 'l': - MachinePtySetMode(pty, false); + PtySetMode(pty, false); break; case 'c': - MachinePtyReportPreferredVtType(pty); + PtyReportPreferredVtType(pty); break; case 'q': - MachinePtyLed(pty); + PtyLed(pty); break; default: break; } } -static void MachinePtyScreenAlignmentDisplay(struct MachinePty *pty) { +static void PtyScreenAlignmentDisplay(struct Pty *pty) { wmemset((void *)pty->wcs, 'E', pty->yn * pty->xn); } -static void MachinePtyEscHash(struct MachinePty *pty) { +static void PtyEscHash(struct Pty *pty) { switch (pty->esc.s[1]) { case '5': - MachinePtySetXlat(pty, MachinePtyGetXlatAscii()); + PtySetXlat(pty, GetXlatAscii()); break; case '6': - MachinePtySetXlat(pty, MachinePtyGetXlatDoubleWidth()); + PtySetXlat(pty, GetXlatDoubleWidth()); break; case '8': - MachinePtyScreenAlignmentDisplay(pty); + PtyScreenAlignmentDisplay(pty); break; default: break; } } -static void MachinePtyEsc(struct MachinePty *pty) { +static void PtyEsc(struct Pty *pty) { switch (pty->esc.s[0]) { case 'c': - MachinePtyFullReset(pty); + PtyFullReset(pty); break; case '7': - MachinePtySaveCursorPosition(pty); + PtySaveCursorPosition(pty); break; case '8': - MachinePtyRestoreCursorPosition(pty); + PtyRestoreCursorPosition(pty); break; case 'E': pty->x = 0; case 'D': - MachinePtyIndex(pty); + PtyIndex(pty); break; case 'M': - MachinePtyReverseIndex(pty); + PtyReverseIndex(pty); break; case 'Z': - MachinePtyReportPreferredVtIdentity(pty); + PtyReportPreferredVtIdentity(pty); break; case '(': - MachinePtySetCodepage(pty, pty->esc.s[1]); + PtySetCodepage(pty, pty->esc.s[1]); break; case '#': - MachinePtyEscHash(pty); + PtyEscHash(pty); break; default: break; } } -static void MachinePtyCntrl(struct MachinePty *pty, int c01) { +static void PtyCntrl(struct Pty *pty, int c01) { switch (c01) { case '\a': - MachinePtyBell(pty); + PtyBell(pty); break; case 0x85: case '\f': case '\v': case '\n': - MachinePtyNewline(pty); + PtyNewline(pty); break; case '\r': - MachinePtyCarriageReturn(pty); + PtyCarriageReturn(pty); break; case '\e': - pty->state = kMachinePtyEsc; + pty->state = kPtyEsc; pty->esc.i = 0; break; case '\t': - MachinePtyWriteTab(pty); + PtyWriteTab(pty); break; case 0x7F: case '\b': pty->x = MAX(0, pty->x - 1); break; case 0x84: - MachinePtyIndex(pty); + PtyIndex(pty); break; case 0x8D: - MachinePtyReverseIndex(pty); + PtyReverseIndex(pty); break; case 0x9B: - pty->state = kMachinePtyCsi; + pty->state = kPtyCsi; break; default: break; } } -static void MachinePtyEscAppend(struct MachinePty *pty, char c) { +static void PtyEscAppend(struct Pty *pty, char c) { pty->esc.i = MIN(pty->esc.i + 1, ARRAYLEN(pty->esc.s) - 1); pty->esc.s[pty->esc.i - 1] = c; pty->esc.s[pty->esc.i - 0] = 0; } -ssize_t MachinePtyWrite(struct MachinePty *pty, const void *data, size_t n) { +ssize_t PtyWrite(struct Pty *pty, const void *data, size_t n) { int i; wchar_t wc; const uint8_t *p; for (p = data, i = 0; i < n; ++i) { switch (pty->state) { - case kMachinePtyAscii: + case kPtyAscii: if (0x00 <= p[i] && p[i] <= 0x7F) { if (0x20 <= p[i] && p[i] <= 0x7E) { if ((wc = pty->xlat[p[i]]) >= 0) { - MachinePtyWriteGlyph(pty, wc, 1); + PtyWriteGlyph(pty, wc, 1); } else { - MachinePtyWriteGlyph(pty, -wc, 2); + PtyWriteGlyph(pty, -wc, 2); } } else { - MachinePtyCntrl(pty, p[i]); + PtyCntrl(pty, p[i]); } } else if (!ThomPikeCont(p[i])) { - pty->state = kMachinePtyUtf8; + pty->state = kPtyUtf8; pty->u8 = ThomPikeByte(p[i]); pty->n8 = ThomPikeLen(p[i]) - 1; } break; - case kMachinePtyUtf8: + case kPtyUtf8: if (ThomPikeCont(p[i])) { pty->u8 = ThomPikeMerge(pty->u8, p[i]); if (--pty->n8) break; } wc = pty->u8; if ((0x00 <= wc && wc <= 0x1F) || (0x7F <= wc && wc <= 0x9F)) { - MachinePtyCntrl(pty, wc); + PtyCntrl(pty, wc); } else { - MachinePtyWriteGlyph(pty, wc, wcwidth(wc)); + PtyWriteGlyph(pty, wc, wcwidth(wc)); } - pty->state = kMachinePtyAscii; + pty->state = kPtyAscii; pty->u8 = 0; --i; break; - case kMachinePtyEsc: + case kPtyEsc: if (p[i] == '[') { - pty->state = kMachinePtyCsi; - } else if (0x30 <= p[i] && p[i] <= 0x7e) { - MachinePtyEscAppend(pty, p[i]); - MachinePtyEsc(pty); - pty->state = kMachinePtyAscii; - } else if (0x20 <= p[i] && p[i] <= 0x2f) { - MachinePtyEscAppend(pty, p[i]); + pty->state = kPtyCsi; + } else if (0x30 <= p[i] && p[i] <= 0x7E) { + PtyEscAppend(pty, p[i]); + PtyEsc(pty); + pty->state = kPtyAscii; + } else if (0x20 <= p[i] && p[i] <= 0x2F) { + PtyEscAppend(pty, p[i]); } else { - pty->state = kMachinePtyAscii; + pty->state = kPtyAscii; } break; - case kMachinePtyCsi: - MachinePtyEscAppend(pty, p[i]); + case kPtyCsi: + PtyEscAppend(pty, p[i]); switch (p[i]) { case ':': case ';': @@ -1152,11 +1151,11 @@ ssize_t MachinePtyWrite(struct MachinePty *pty, const void *data, size_t n) { case '\\': case 'A' ... 'Z': case 'a' ... 'z': - MachinePtyCsi(pty); - pty->state = kMachinePtyAscii; + PtyCsi(pty); + pty->state = kPtyAscii; break; default: - pty->state = kMachinePtyAscii; + pty->state = kPtyAscii; continue; } break; @@ -1167,20 +1166,19 @@ ssize_t MachinePtyWrite(struct MachinePty *pty, const void *data, size_t n) { return n; } -ssize_t MachinePtyWriteInput(struct MachinePty *pty, const void *data, - size_t n) { - MachinePtyConcatInput(pty, data, n); - if (!(pty->conf & kMachinePtyNoecho)) { - MachinePtyWrite(pty, data, n); +ssize_t PtyWriteInput(struct Pty *pty, const void *data, size_t n) { + PtyConcatInput(pty, data, n); + if (!(pty->conf & kPtyNoecho)) { + PtyWrite(pty, data, n); } return n; } -ssize_t MachinePtyRead(struct MachinePty *pty, void *buf, size_t size) { +ssize_t PtyRead(struct Pty *pty, void *buf, size_t size) { char *p; size_t n; n = MIN(size, pty->input.i); - if (!(pty->conf & kMachinePtyNocanon)) { + if (!(pty->conf & kPtyNocanon)) { if ((p = memchr(pty->input.p, '\n', n))) { n = MIN(n, pty->input.p - p + 1); } else { @@ -1193,7 +1191,7 @@ ssize_t MachinePtyRead(struct MachinePty *pty, void *buf, size_t size) { return n; } -static char *MachinePtyEncodeRgb(char *p, int rgb) { +static char *PtyEncodeRgb(char *p, int rgb) { *p++ = '2'; *p++ = ';'; p += uint64toarray_radix10((rgb & 0x0000ff) >> 000, p); @@ -1204,94 +1202,91 @@ static char *MachinePtyEncodeRgb(char *p, int rgb) { return p; } -static char *MachinePtyEncodeXterm256(char *p, int xt) { +static char *PtyEncodeXterm256(char *p, int xt) { *p++ = '5'; *p++ = ';'; p += uint64toarray_radix10(xt, p); return p; } -char *MachinePtyEncodeStyle(char *p, uint32_t xr, uint32_t pr, uint32_t fg, - uint32_t bg) { +char *PtyEncodeStyle(char *p, uint32_t xr, uint32_t pr, uint32_t fg, + uint32_t bg) { *p++ = '\e'; *p++ = '['; - if (pr & (kMachinePtyBold | kMachinePtyFaint | kMachinePtyFlip | - kMachinePtyUnder | kMachinePtyDunder | kMachinePtyBlink | - kMachinePtyStrike | kMachinePtyFg | kMachinePtyBg)) { - if (xr & (kMachinePtyBold | kMachinePtyFaint)) { - if ((xr & (kMachinePtyBold | kMachinePtyFaint)) ^ - (pr & (kMachinePtyBold | kMachinePtyFaint))) { + if (pr & (kPtyBold | kPtyFaint | kPtyFlip | kPtyUnder | kPtyDunder | + kPtyBlink | kPtyStrike | kPtyFg | kPtyBg)) { + if (xr & (kPtyBold | kPtyFaint)) { + if ((xr & (kPtyBold | kPtyFaint)) ^ (pr & (kPtyBold | kPtyFaint))) { *p++ = '2'; *p++ = '2'; *p++ = ';'; } - if (pr & kMachinePtyBold) { + if (pr & kPtyBold) { *p++ = '1'; *p++ = ';'; } - if (pr & kMachinePtyFaint) { + if (pr & kPtyFaint) { *p++ = '2'; *p++ = ';'; } } - if (xr & (kMachinePtyUnder | kMachinePtyDunder)) { - if ((xr & (kMachinePtyUnder | kMachinePtyDunder)) ^ - (pr & (kMachinePtyUnder | kMachinePtyDunder))) { + if (xr & (kPtyUnder | kPtyDunder)) { + if ((xr & (kPtyUnder | kPtyDunder)) ^ (pr & (kPtyUnder | kPtyDunder))) { *p++ = '2'; *p++ = '4'; *p++ = ';'; } - if (pr & kMachinePtyUnder) { + if (pr & kPtyUnder) { *p++ = '4'; *p++ = ';'; } - if (pr & kMachinePtyDunder) { + if (pr & kPtyDunder) { *p++ = '2'; *p++ = '1'; *p++ = ';'; } } - if (xr & (kMachinePtyFlip | kMachinePtyBlink | kMachinePtyStrike)) { - if (xr & kMachinePtyFlip) { - if (!(pr & kMachinePtyFlip)) *p++ = '2'; + if (xr & (kPtyFlip | kPtyBlink | kPtyStrike)) { + if (xr & kPtyFlip) { + if (!(pr & kPtyFlip)) *p++ = '2'; *p++ = '7'; *p++ = ';'; } - if (xr & kMachinePtyBlink) { - if (!(pr & kMachinePtyBlink)) *p++ = '2'; + if (xr & kPtyBlink) { + if (!(pr & kPtyBlink)) *p++ = '2'; *p++ = '5'; *p++ = ';'; } - if (xr & kMachinePtyStrike) { - if (!(pr & kMachinePtyStrike)) *p++ = '2'; + if (xr & kPtyStrike) { + if (!(pr & kPtyStrike)) *p++ = '2'; *p++ = '9'; *p++ = ';'; } } - if (xr & (kMachinePtyFg | kMachinePtyTrue)) { + if (xr & (kPtyFg | kPtyTrue)) { *p++ = '3'; - if (pr & kMachinePtyFg) { + if (pr & kPtyFg) { *p++ = '8'; *p++ = ';'; - if (pr & kMachinePtyTrue) { - p = MachinePtyEncodeRgb(p, fg); + if (pr & kPtyTrue) { + p = PtyEncodeRgb(p, fg); } else { - p = MachinePtyEncodeXterm256(p, fg); + p = PtyEncodeXterm256(p, fg); } } else { *p++ = '9'; } *p++ = ';'; } - if (xr & (kMachinePtyBg | kMachinePtyTrue)) { + if (xr & (kPtyBg | kPtyTrue)) { *p++ = '4'; - if (pr & kMachinePtyBg) { + if (pr & kPtyBg) { *p++ = '8'; *p++ = ';'; - if (pr & kMachinePtyTrue) { - p = MachinePtyEncodeRgb(p, bg); + if (pr & kPtyTrue) { + p = PtyEncodeRgb(p, bg); } else { - p = MachinePtyEncodeXterm256(p, bg); + p = PtyEncodeXterm256(p, bg); } } else { *p++ = '9'; @@ -1307,25 +1302,24 @@ char *MachinePtyEncodeStyle(char *p, uint32_t xr, uint32_t pr, uint32_t fg, return p; } -void MachinePtyAppendLine(struct MachinePty *pty, struct Buffer *buf, - unsigned y) { +int PtyAppendLine(struct Pty *pty, struct Buffer *buf, unsigned y) { uint64_t u; - size_t need; char *p, *pb; - uint32_t i, j, w, wc, np, xp, pr, fg, bg, ci; - if (y >= pty->yn) return; - need = buf->i + pty->xn * 60; - if (need > buf->n) { - CHECK_NOTNULL((buf->p = realloc(buf->p, need))); - buf->n = need; + uint32_t i, j, n, w, wc, np, xp, pr, fg, bg, ci; + if (y >= pty->yn) return einval(); + n = buf->i + pty->xn * 60; /* torture character length */ + if (n > buf->n) { + if (!(p = realloc(buf->p, n))) return -1; + buf->p = p; + buf->n = n; } i = y * pty->xn; j = (y + 1) * pty->xn; pb = buf->p + buf->i; - ci = !(pty->conf & kMachinePtyNocursor) && y == pty->y ? i + pty->x : -1; + ci = !(pty->conf & kPtyNocursor) && y == pty->y ? i + pty->x : -1; for (pr = 0; i < j; i += w) { np = pty->prs[i]; - if (!(np & kMachinePtyConceal)) { + if (!(np & kPtyConceal)) { wc = pty->wcs[i]; DCHECK(!(0x00 <= wc && wc <= 0x1F)); DCHECK(!(0x7F <= wc && wc <= 0x9F)); @@ -1342,30 +1336,30 @@ void MachinePtyAppendLine(struct MachinePty *pty, struct Buffer *buf, } if (i == ci) { if (u != ' ') { - np ^= kMachinePtyFlip; + np ^= kPtyFlip; } else { u = tpenc(u'▂'); - if (pty->conf & kMachinePtyBlinkcursor) { - np |= kMachinePtyBlink; + if (pty->conf & kPtyBlinkcursor) { + np |= kPtyBlink; } } } fg = bg = -1; xp = pr ^ np; - if (np & (kMachinePtyFg | kMachinePtyBg)) { - if (np & kMachinePtyFg) { - if (pty->fgs[i] != fg) xp |= kMachinePtyFg; + if (np & (kPtyFg | kPtyBg)) { + if (np & kPtyFg) { + if (pty->fgs[i] != fg) xp |= kPtyFg; fg = pty->fgs[i]; } - if (np & kMachinePtyBg) { - if (pty->bgs[i] != bg) xp |= kMachinePtyBg; + if (np & kPtyBg) { + if (pty->bgs[i] != bg) xp |= kPtyBg; bg = pty->bgs[i]; } } p = pb; if (xp) { pr = np; - p = MachinePtyEncodeStyle(p, xp, pr, fg, bg); + p = PtyEncodeStyle(p, xp, pr, fg, bg); } do { *p++ = u & 0xFF; @@ -1376,4 +1370,5 @@ void MachinePtyAppendLine(struct MachinePty *pty, struct Buffer *buf, } DCHECK_LE(pb - buf->p, buf->n); buf->i = pb - buf->p; + return 0; } diff --git a/tool/build/lib/pty.h b/tool/build/lib/pty.h index e4918d55..99b5faac 100644 --- a/tool/build/lib/pty.h +++ b/tool/build/lib/pty.h @@ -2,36 +2,36 @@ #define COSMOPOLITAN_TOOL_BUILD_LIB_PTY_H_ #include "tool/build/lib/buffer.h" -#define kMachinePtyFg 0x0001 -#define kMachinePtyBg 0x0002 -#define kMachinePtyBold 0x0004 -#define kMachinePtyFlip 0x0008 -#define kMachinePtyFaint 0x0010 -#define kMachinePtyUnder 0x0020 -#define kMachinePtyDunder 0x0040 -#define kMachinePtyTrue 0x0080 -#define kMachinePtyBlink 0x0100 -#define kMachinePtyItalic 0x0200 -#define kMachinePtyFraktur 0x0400 -#define kMachinePtyStrike 0x0800 -#define kMachinePtyConceal 0x1000 +#define kPtyFg 0x0001 +#define kPtyBg 0x0002 +#define kPtyBold 0x0004 +#define kPtyFlip 0x0008 +#define kPtyFaint 0x0010 +#define kPtyUnder 0x0020 +#define kPtyDunder 0x0040 +#define kPtyTrue 0x0080 +#define kPtyBlink 0x0100 +#define kPtyItalic 0x0200 +#define kPtyFraktur 0x0400 +#define kPtyStrike 0x0800 +#define kPtyConceal 0x1000 -#define kMachinePtyBell 0x001 -#define kMachinePtyRedzone 0x002 -#define kMachinePtyNocursor 0x004 -#define kMachinePtyBlinkcursor 0x008 -#define kMachinePtyNocanon 0x010 -#define kMachinePtyNoecho 0x020 -#define kMachinePtyNoopost 0x040 -#define kMachinePtyLed1 0x080 -#define kMachinePtyLed2 0x100 -#define kMachinePtyLed3 0x200 -#define kMachinePtyLed4 0x400 +#define kPtyBell 0x001 +#define kPtyRedzone 0x002 +#define kPtyNocursor 0x004 +#define kPtyBlinkcursor 0x008 +#define kPtyNocanon 0x010 +#define kPtyNoecho 0x020 +#define kPtyNoopost 0x040 +#define kPtyLed1 0x080 +#define kPtyLed2 0x100 +#define kPtyLed3 0x200 +#define kPtyLed4 0x400 #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -struct MachinePty { +struct Pty { int y; int x; int yn; @@ -48,34 +48,34 @@ struct MachinePty { uint32_t *fgs; uint32_t *bgs; wchar_t *xlat; - enum MachinePtyState { - kMachinePtyAscii, - kMachinePtyUtf8, - kMachinePtyEsc, - kMachinePtyCsi, + enum PtyState { + kPtyAscii, + kPtyUtf8, + kPtyEsc, + kPtyCsi, } state; - struct MachinePtyEsc { + struct PtyEsc { unsigned i; char s[64]; } esc; - struct MachinePtyInput { + struct PtyInput { size_t i, n; char *p; } input; }; -void MachinePtyFree(struct MachinePty *); -struct MachinePty *MachinePtyNew(void) nodiscard; -void MachinePtyResize(struct MachinePty *, int, int); -ssize_t MachinePtyRead(struct MachinePty *, void *, size_t); -ssize_t MachinePtyWrite(struct MachinePty *, const void *, size_t); -ssize_t MachinePtyWriteInput(struct MachinePty *, const void *, size_t); -void MachinePtyAppendLine(struct MachinePty *, struct Buffer *, unsigned); -void MachinePtyFullReset(struct MachinePty *); -void MachinePtyMemmove(struct MachinePty *, long, long, long); -void MachinePtyErase(struct MachinePty *, long, long); -void MachinePtySetY(struct MachinePty *, int); -void MachinePtySetX(struct MachinePty *, int); +void FreePty(struct Pty *); +struct Pty *NewPty(void) nodiscard; +void PtyResize(struct Pty *, int, int); +ssize_t PtyRead(struct Pty *, void *, size_t); +ssize_t PtyWrite(struct Pty *, const void *, size_t); +ssize_t PtyWriteInput(struct Pty *, const void *, size_t); +int PtyAppendLine(struct Pty *, struct Buffer *, unsigned); +void PtyFullReset(struct Pty *); +void PtyMemmove(struct Pty *, long, long, long); +void PtyErase(struct Pty *, long, long); +void PtySetY(struct Pty *, int); +void PtySetX(struct Pty *, int); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/ssemov.c b/tool/build/lib/ssemov.c index 86c69bf8..894979dc 100644 --- a/tool/build/lib/ssemov.c +++ b/tool/build/lib/ssemov.c @@ -17,6 +17,7 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/intrin/pmovmskb.h" #include "libc/str/str.h" #include "tool/build/lib/address.h" #include "tool/build/lib/endian.h" @@ -496,23 +497,9 @@ void OpMov0fD6(struct Machine *m, uint32_t rde) { } } -static uint8_t pmovmskb(uint64_t x) { - return (x & 0x0000000000000080) >> 007 | (x & 0x0000000000008000) >> 016 | - (x & 0x0000000000800000) >> 025 | (x & 0x0000000080000000) >> 034 | - (x & 0x0000008000000000) >> 043 | (x & 0x0000800000000000) >> 052 | - (x & 0x0080000000000000) >> 061 | (x & 0x8000000000000000) >> 070; -} - void OpPmovmskbGdqpNqUdq(struct Machine *m, uint32_t rde) { - uint64_t bitmask; - if (Osz(rde)) { - bitmask = pmovmskb(Read64(XmmRexbRm(m, rde) + 8)) << 8 | - pmovmskb(Read64(XmmRexbRm(m, rde))); - } else { - bitmask = pmovmskb(Read64(MmRm(m, rde) + 8)) << 8 | - pmovmskb(Read64(MmRm(m, rde))); - } - Write64(RegRexrReg(m, rde), bitmask); + Write64(RegRexrReg(m, rde), + pmovmskb(XmmRexbRm(m, rde)) & (Osz(rde) ? 0xffff : 0xff)); } void OpMaskMovDiXmmRegXmmRm(struct Machine *m, uint32_t rde) { diff --git a/tool/build/lib/stats.c b/tool/build/lib/stats.c index 291b4690..cf95a485 100644 --- a/tool/build/lib/stats.c +++ b/tool/build/lib/stats.c @@ -19,6 +19,6 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "tool/build/lib/stats.h" -unsigned long ops; unsigned long taken; unsigned long ntaken; +unsigned long opcount; diff --git a/tool/build/lib/stats.h b/tool/build/lib/stats.h index 291fbade..1f5c0819 100644 --- a/tool/build/lib/stats.h +++ b/tool/build/lib/stats.h @@ -3,9 +3,9 @@ #if !(__ASSEMBLER__ + __LINKER__ + 0) COSMOPOLITAN_C_START_ -extern unsigned long ops; extern unsigned long taken; extern unsigned long ntaken; +extern unsigned long opcount; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/tool/build/lib/syscall.c b/tool/build/lib/syscall.c index 30f9122c..0d3624ec 100644 --- a/tool/build/lib/syscall.c +++ b/tool/build/lib/syscall.c @@ -30,6 +30,7 @@ #include "libc/calls/struct/timeval.h" #include "libc/calls/struct/winsize.h" #include "libc/errno.h" +#include "libc/fmt/fmt.h" #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/macros.h" @@ -321,11 +322,22 @@ static int XlatMsyncFlags(int x) { return res; } +static unsigned XlatOpenMode(unsigned flags) { + switch (flags & 3) { + case 0: + return O_RDONLY; + case 1: + return O_WRONLY; + case 2: + return O_RDWR; + default: + unreachable; + } +} + static unsigned XlatOpenFlags(unsigned flags) { unsigned res = 0; - if ((flags & 3) == 0) res = O_RDONLY; - if ((flags & 3) == 1) res = O_WRONLY; - if ((flags & 3) == 3) res = O_RDWR; + res = XlatOpenMode(flags); if (flags & 0x80000) res |= O_CLOEXEC; if (flags & 0x400) res |= O_APPEND; if (flags & 0x40) res |= O_CREAT; @@ -355,6 +367,7 @@ static int XlatFcntlArg(int x) { switch (x) { XLAT(0, 0); XLAT(1, FD_CLOEXEC); + XLAT(0x0800, O_NONBLOCK); default: return einval(); } @@ -401,6 +414,14 @@ static int XlatRusage(int x) { } } +static const char *GetSimulated(void) { + if (IsGenuineCosmo()) { + return " SIMULATED"; + } else { + return ""; + } +} + static void VirtualSendRead(struct Machine *m, void *dst, int64_t addr, uint64_t n) { VirtualSend(m, dst, addr, n); @@ -508,7 +529,7 @@ static int OpMadvise(struct Machine *m, int64_t addr, size_t length, static int64_t OpBrk(struct Machine *m, int64_t addr) { addr = ROUNDUP(addr, PAGESIZE); if (addr > m->brk) { - if (ReserveVirtual(m, m->brk, addr - m->brk) != -1) { + if (ReserveVirtual(m, m->brk, addr - m->brk, 0x0207) != -1) { m->brk = addr; } } else if (addr < m->brk) { @@ -519,34 +540,47 @@ static int64_t OpBrk(struct Machine *m, int64_t addr) { return m->brk; } +static int OpMunmap(struct Machine *m, int64_t virt, uint64_t size) { + VERBOSEF("MUNMAP%s %p %,ld", GetSimulated(), virt, size); + return FreeVirtual(m, virt, size); +} + static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot, int flags, int fd, int64_t offset) { void *tmp; - LOGF("MMAP%s %p %,ld %#x %#x %d %#lx", IsGenuineCosmo() ? " SIMULATED" : "", - virt, size, prot, flags, fd, offset); - flags = XlatMapFlags(flags); - if (fd != -1 && (fd = XlatFd(m, fd)) == -1) return -1; - if (!(flags & MAP_FIXED)) { - if (!virt) { - if ((virt = FindVirtual(m, m->brk, size)) == -1) return -1; - m->brk = virt + size; - } else { - if ((virt = FindVirtual(m, virt, size)) == -1) return -1; + uint64_t key; + VERBOSEF("MMAP%s %p %,ld %#x %#x %d %#lx", GetSimulated(), virt, size, prot, + flags, fd, offset); + if (prot & PROT_READ) { + key = 0x0205; + if (prot & PROT_WRITE) key |= 2; + if (!(prot & PROT_EXEC)) key |= 0x8000000000000000; + flags = XlatMapFlags(flags); + if (fd != -1 && (fd = XlatFd(m, fd)) == -1) return -1; + if (!(flags & MAP_FIXED)) { + if (!virt) { + if ((virt = FindVirtual(m, m->brk, size)) == -1) return -1; + m->brk = virt + size; + } else { + if ((virt = FindVirtual(m, virt, size)) == -1) return -1; + } } + if (ReserveVirtual(m, virt, size, key) != -1) { + if (fd != -1 && !(flags & MAP_ANONYMOUS)) { + /* TODO: lazy file mappings */ + CHECK_NOTNULL((tmp = malloc(size))); + CHECK_EQ(size, pread(fd, tmp, size, offset)); + VirtualRecvWrite(m, virt, tmp, size); + free(tmp); + } + } else { + FreeVirtual(m, virt, size); + return -1; + } + return virt; + } else { + return FreeVirtual(m, virt, size); } - if (ReserveVirtual(m, virt, size) == -1) return -1; - if (fd != -1 && !(flags & MAP_ANONYMOUS)) { - /* TODO: lazy page loading */ - CHECK_NOTNULL((tmp = malloc(size))); - CHECK_EQ(size, pread(fd, tmp, size, offset)); - VirtualRecvWrite(m, virt, tmp, size); - free(tmp); - } - return virt; -} - -static int OpMunmap(struct Machine *m, int64_t addr, uint64_t size) { - return FreeVirtual(m, addr, size); } static int OpMsync(struct Machine *m, int64_t virt, size_t size, int flags) { @@ -574,18 +608,23 @@ static int OpClose(struct Machine *m, int fd) { return rc; } -static int OpOpenat(struct Machine *m, int dirfd, int64_t path, int flags, +static int OpOpenat(struct Machine *m, int dirfd, int64_t pathaddr, int flags, int mode) { int fd, i; + const char *path; flags = XlatOpenFlags(flags); if ((dirfd = XlatAfd(m, dirfd)) == -1) return -1; if ((i = MachineFdAdd(&m->fds)) == -1) return -1; - if ((fd = openat(dirfd, LoadStr(m, path), flags, mode)) != -1) { + path = LoadStr(m, pathaddr); + if ((fd = openat(dirfd, path, flags, mode)) != -1) { m->fds.p[i].cb = &kMachineFdCbHost; m->fds.p[i].fd = fd; + VERBOSEF("openat(%#x, %`'s, %#x, %#x) → %d [%d]", dirfd, path, flags, mode, + i, fd); fd = i; } else { MachineFdRemove(&m->fds, i); + VERBOSEF("openat(%#x, %`'s, %#x, %#x) failed", dirfd, path, flags, mode); } return fd; } @@ -768,9 +807,13 @@ static ssize_t OpWrite(struct Machine *m, int fd, int64_t addr, size_t size) { if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) { if ((rc = m->fds.p[fd].cb->writev(m->fds.p[fd].fd, iv.p, iv.i)) != -1) { SetReadAddr(m, addr, rc); + } else { + VERBOSEF("write(%d [%d], %p, %zu) failed: %s", fd, m->fds.p[fd].fd, + addr, size, strerror(errno)); } } } else { + VERBOSEF("write(%d, %p, %zu) bad fd", fd, addr, size); rc = ebadf(); } FreeIovs(&iv); @@ -1363,7 +1406,7 @@ void OpSyscall(struct Machine *m, uint32_t rde) { SYSCALL(0x177, vmsplice(di, P(si), dx, r0)); CASE(0xE7, HaltMachine(m, di | 0x100)); default: - LOGF("missing syscall 0x%03x", ax); + VERBOSEF("missing syscall 0x%03x", ax); ax = enosys(); break; } diff --git a/tool/build/lib/throw.c b/tool/build/lib/throw.c index 87fcc2f6..82f77f88 100644 --- a/tool/build/lib/throw.c +++ b/tool/build/lib/throw.c @@ -20,6 +20,7 @@ #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/nexgen32e/vendor.h" +#include "libc/runtime/gc.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "tool/build/lib/address.h" @@ -34,7 +35,7 @@ static bool IsHaltingInitialized(struct Machine *m) { void HaltMachine(struct Machine *m, int code) { CHECK(IsHaltingInitialized(m)); - longjmp(m->onhalt, code); + gclongjmp(m->onhalt, code); } void ThrowDivideError(struct Machine *m) { diff --git a/tool/build/tinyemu.c b/tool/build/tinyemu.c index 71597228..bf3d8d52 100644 --- a/tool/build/tinyemu.c +++ b/tool/build/tinyemu.c @@ -17,19 +17,22 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/log/log.h" -#include "libc/mem/mem.h" -#include "libc/runtime/runtime.h" +#include "libc/calls/calls.h" +#include "libc/log/check.h" #include "libc/stdio/stdio.h" #include "libc/sysv/consts/ex.h" #include "libc/sysv/consts/fileno.h" #include "libc/x/x.h" #include "tool/build/lib/loader.h" #include "tool/build/lib/machine.h" -#include "tool/build/lib/memory.h" -#include "tool/build/lib/pty.h" #include "tool/build/lib/syscall.h" +static void AddHostFd(struct Machine *m, int fd) { + int i = m->fds.i++; + CHECK_NE(-1, (m->fds.p[i].fd = dup(fd))); + m->fds.p[i].cb = &kMachineFdCbHost; +} + int main(int argc, char *argv[]) { int rc; struct Elf elf; @@ -42,15 +45,10 @@ int main(int argc, char *argv[]) { } m = NewMachine(); LoadProgram(m, argv[1], argv + 2, environ, &elf); - m->fds.i = 3; - m->fds.n = 8; - m->fds.p = xcalloc(m->fds.n, sizeof(struct MachineFd)); - m->fds.p[0].fd = STDIN_FILENO; - m->fds.p[0].cb = &kMachineFdCbHost; - m->fds.p[1].fd = STDOUT_FILENO; - m->fds.p[1].cb = &kMachineFdCbHost; - m->fds.p[2].fd = STDERR_FILENO; - m->fds.p[2].cb = &kMachineFdCbHost; + m->fds.p = xcalloc((m->fds.n = 8), sizeof(struct MachineFd)); + AddHostFd(m, STDIN_FILENO); + AddHostFd(m, STDOUT_FILENO); + AddHostFd(m, STDERR_FILENO); if (!(rc = setjmp(m->onhalt))) { for (;;) { LoadInstruction(m); diff --git a/tool/viz/basicidea.c b/tool/viz/basicidea.c index 0b4677e2..b04bfa3a 100644 --- a/tool/viz/basicidea.c +++ b/tool/viz/basicidea.c @@ -248,7 +248,6 @@ int main(int argc, char *argv[]) { void *rgb; size_t size; unsigned yn, xn; - cancolor(); GetTermSize(&yn, &xn); yn *= 2; size = yn * xn * 4; diff --git a/tool/viz/cpuid.c b/tool/viz/cpuid.c index 8e205830..4cca2a28 100644 --- a/tool/viz/cpuid.c +++ b/tool/viz/cpuid.c @@ -17,6 +17,7 @@ │ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │ │ 02110-1301 USA │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/log/color.h" #include "libc/log/log.h" #include "libc/nexgen32e/cpuid4.h" #include "libc/nexgen32e/nexgen32e.h" @@ -30,9 +31,6 @@ #include "tool/decode/lib/idname.h" #include "tool/decode/lib/x86idnames.h" -#define RED (cancolor() ? "\x1b[91m" : "") -#define GREEN (cancolor() ? "\x1b[32m" : "") -#define RESET (cancolor() ? "\x1b[0m" : "") #define CANIUSE(FEATURE) caniuse(#FEATURE, X86_HAVE(FEATURE)) #define SHOW(CONSTANT) show(#CONSTANT, CONSTANT) diff --git a/tool/viz/deathstar.c b/tool/viz/deathstar.c index 6a887d2a..fc115063 100644 --- a/tool/viz/deathstar.c +++ b/tool/viz/deathstar.c @@ -1,7 +1,9 @@ #include "dsp/tty/tty.h" +#include "libc/bits/safemacros.h" #include "libc/calls/calls.h" #include "libc/calls/struct/termios.h" #include "libc/log/check.h" +#include "libc/log/color.h" #include "libc/log/log.h" #include "libc/macros.h" #include "libc/math.h" @@ -21,10 +23,10 @@ #define WRITE(s) write(STDOUT_FILENO, s, strlen(s)) struct Sphere { - double cx, cy, cz, r; + long double cx, cy, cz, r; }; -const char *kShades[] = { +static const char *kShades[] = { "\e[48;5;232m ", "\e[48;5;233m ", "\e[48;5;234m ", "\e[48;5;235m ", "\e[48;5;236m ", "\e[48;5;237m ", "\e[48;5;238m ", "\e[48;5;239m ", "\e[48;5;240m ", "\e[48;5;241m ", "\e[48;5;242m ", "\e[48;5;243m ", @@ -33,52 +35,53 @@ const char *kShades[] = { "\e[48;5;252m ", "\e[48;5;253m ", "\e[48;5;254m ", "\e[48;5;255m ", }; -jmp_buf jb_; -double light_[3] = {-50, 0, 50}; -struct Sphere pos_ = {11, 11, 11, 11}; -struct Sphere neg_ = {1, 1, -4, 11}; +static jmp_buf jb_; +static long double light_[3] = {-50, 0, 50}; +static struct Sphere pos_ = {11, 11, 11, 11}; +static struct Sphere neg_ = {1, 1, -4, 11}; static void OnCtrlC(int sig) { longjmp(jb_, 1); } -static void Normalize(double v[3]) { - double len; - len = 1 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); +static void Normalize(long double v[3]) { + long double len; + len = 1 / sqrtl(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); v[0] *= len; v[1] *= len; v[2] *= len; } -static double Dot(const double x[3], const double y[3]) { - return fabs(x[0] * y[0] + x[1] * y[1] + x[2] * y[2]); +static long double Dot(const long double x[3], const long double y[3]) { + return fabsl(x[0] * y[0] + x[1] * y[1] + x[2] * y[2]); } /* check if a ray (x,y, -inf)->(x, y, inf) hits a sphere; if so, return the intersecting z values. z1 is closer to the eye */ -static int HitSphere(struct Sphere *s, double x, double y, double z[2]) { - double zsq; +static int HitSphere(struct Sphere *s, long double x, long double y, + long double z[2]) { + long double zsq; x -= s->cx; y -= s->cy; zsq = s->r * s->r - (x * x + y * y); if (zsq < 0) { return 0; } else { - zsq = sqrt(zsq); + zsq = sqrtl(zsq); z[0] = s->cz - zsq; z[1] = s->cz + zsq; return 1; } } -static void DrawSphere(double k, double ambient) { +static void DrawSphere(long double k, long double ambient) { int i, j, hit_result; - double x, y, vec[3], zb[2], zs[2]; - for (i = floor(pos_.cy - pos_.r); i <= ceil(pos_.cy + pos_.r); i++) { - y = i + .5; - for (j = floor(pos_.cx - 2 * pos_.r); j <= ceil(pos_.cx + 2 * pos_.r); + long double x, y, vec[3], zb[2], zs[2]; + for (i = floorl(pos_.cy - pos_.r); i <= ceill(pos_.cy + pos_.r); i++) { + y = i + .5L; + for (j = floorl(pos_.cx - 2 * pos_.r); j <= ceill(pos_.cx + 2 * pos_.r); j++) { - x = .5 * (j - pos_.cx) + .5 + pos_.cx; + x = .5L * (j - pos_.cx) + .5L + pos_.cx; if (!HitSphere(&pos_, x, y, zb)) { /* ray lands in blank space, draw bg */ hit_result = 0; @@ -114,10 +117,10 @@ static void DrawSphere(double k, double ambient) { break; } Normalize(vec); - WRITE( - kShades[MIN(ARRAYLEN(kShades) - 1, - MAX(0, lround((1 - (pow(Dot(light_, vec), k) + ambient)) * - (ARRAYLEN(kShades) - 1))))]); + WRITE(kShades[min( + ARRAYLEN(kShades) - 1, + max(0, lroundl((1 - (powl(Dot(light_, vec), k) + ambient)) * + (ARRAYLEN(kShades) - 1))))]); } WRITE("\e[0m\n"); } @@ -125,7 +128,7 @@ static void DrawSphere(double k, double ambient) { } int main() { - double ang; + long double ang; struct termios old; if (cancolor()) { WRITE("\e[?25l"); @@ -134,13 +137,12 @@ int main() { ang = 0; for (;;) { WRITE("\e[H"); - light_[1] = cos(ang * 2); - light_[2] = cos(ang); - light_[0] = sin(ang); + light_[1] = cosl(ang * 2); + sincosl(ang, &light_[0], &light_[2]); Normalize(light_); - ang += .05; - DrawSphere(1.5, .01); - usleep(1. / FRAMERATE * 1e6); + ang += .05L; + DrawSphere(1.5L, .01L); + usleep(1.L / FRAMERATE * 1e6); } } WRITE("\e[0m\e[H\e[J\e[?25h"); diff --git a/tool/viz/derasterize.c b/tool/viz/derasterize.c index e9a4efb6..b9a70ef7 100644 --- a/tool/viz/derasterize.c +++ b/tool/viz/derasterize.c @@ -590,7 +590,6 @@ int main(int argc, char *argv[]) { unsigned yd, xd; __fast_math(); showcrashreports(); - cancolor(); GetOpts(argc, argv); // if sizes are given, 2 cases: // - positive values: use that as the target size diff --git a/tool/viz/magikarp.c b/tool/viz/magikarp.c index 467eff69..630d0e84 100644 --- a/tool/viz/magikarp.c +++ b/tool/viz/magikarp.c @@ -668,7 +668,6 @@ int main(int argc, char *argv[]) { break; } } - cancolor(); showcrashreports(); for (i = optind; i < argc; ++i) { WithImageFile(argv[i], scaler); diff --git a/tool/viz/printimage.c b/tool/viz/printimage.c index 5df1bbea..30798967 100644 --- a/tool/viz/printimage.c +++ b/tool/viz/printimage.c @@ -399,7 +399,6 @@ void WithImageFile(const char *path, int main(int argc, char *argv[]) { int i; - cancolor(); GetOpts(&argc, argv); stbi_set_unpremultiply_on_load(true); for (i = optind; i < argc; ++i) { diff --git a/tool/viz/printpixel.c b/tool/viz/printpixel.c index f4166419..2fec922a 100644 --- a/tool/viz/printpixel.c +++ b/tool/viz/printpixel.c @@ -41,7 +41,7 @@ int main(int argc, char *argv[]) { r = (rgb & 0xff0000) >> 020; tty = rgb2tty(r, g, b); printf("\e[48;5;%dm \e[0m %d \\e[48;5;%dm %s #%02x%02x%02x\n", tty.xt, - tty.xt, tty.xt, indexdoublenulstring(kXtermName, tty.xt), r, g, b); + tty.xt, tty.xt, IndexDoubleNulString(kXtermName, tty.xt), r, g, b); } return 0; } diff --git a/tool/viz/printvideo.c b/tool/viz/printvideo.c index dda19279..ac4bc05f 100644 --- a/tool/viz/printvideo.c +++ b/tool/viz/printvideo.c @@ -1603,7 +1603,6 @@ int main(int argc, char *argv[]) { sigaddset(&wut, SIGPIPE); sigprocmask(SIG_SETMASK, &wut, NULL); if (!NoDebug()) showcrashreports(); - cancolor(); fullclear_ = true; GetOpts(argc, argv); if (!tuned_) PickDefaults(); @@ -1613,7 +1612,7 @@ int main(int argc, char *argv[]) { ffplay_ = commandvenv("FFPLAY", "ffplay"); infd_ = STDIN_FILENO; outfd_ = STDOUT_FILENO; - nullfd_ = open("/dev/null", O_APPEND | O_RDWR | O_NONBLOCK); + nullfd_ = open("/dev/null", O_APPEND | O_RDWR); if (!setjmp(jb_)) { xsigaction(SIGINT, OnCtrlC, 0, 0, NULL); xsigaction(SIGHUP, OnCtrlC, 0, 0, NULL); @@ -1625,11 +1624,11 @@ int main(int argc, char *argv[]) { __cxa_atexit(OnExit, NULL, NULL); g_logfile = fopen(logpath_, "a"); if (ischardev(infd_) && ischardev(outfd_)) { - CHECK_NE(-1, fcntl(infd_, F_SETFL, O_NONBLOCK)); + /* CHECK_NE(-1, fcntl(infd_, F_SETFL, O_NONBLOCK)); */ } else if (infd_ != outfd_) { infd_ = -1; } - CHECK_NE(-1, fcntl(outfd_, F_SETFL, O_NONBLOCK)); + /* CHECK_NE(-1, fcntl(outfd_, F_SETFL, O_NONBLOCK)); */ if (CanPlayAudio()) MakeLatencyLittleLessBad(); TryToOpenFrameBuffer(); RenounceSpecialPrivileges(); diff --git a/tool/viz/xterm256info.c b/tool/viz/xterm256info.c index 14ec2171..3552e6ac 100644 --- a/tool/viz/xterm256info.c +++ b/tool/viz/xterm256info.c @@ -700,7 +700,7 @@ int main(int argc, char *argv[]) { for (i = 0; i < 256; ++i) { printf("\e[48;5;%dm \e[0m \e[38;5;%dm██\e[0m \e[1;48;5;%dm " "\e[0m \e[1;38;5;%dm██\e[0m %-6hhu%-18s#%02hhx%02hhx%02hhx\n", - i, i, i, i, i, indexdoublenulstring(kXtermName, i), kXtermRgb[i].r, + i, i, i, i, i, IndexDoubleNulString(kXtermName, i), kXtermRgb[i].r, kXtermRgb[i].g, kXtermRgb[i].b); } return 0;